dbfp_pub/dbfp.py

192 lines
5.6 KiB
Python

#
#
#
import os
import argparse
import logging
from subprocess import Popen, PIPE, check_call
# our libs
from libs import android
from libs.toolbox import ToolBox
from libs.fingerprint import FingerprintDB
from libs.fingerprint_index import FingerprintIndex
BASE_DIR = "data"
FP_BASE_DIR = "fingerprints"
def main():
parseArgs()
#
def compareFingerprint(file_in, file_json):
db = FingerprintDB()
db.scanDBFile(file_in)
percent = db.compareDB(file_json)
print "Percent match: {}".format(str(percent))
#
def createFingerprint(file_in, verbose, app_name, app_ver, notes):
db = FingerprintDB()
retVal = db.scanDBFile(file_in)
if (retVal > 0):
if verbose:
db.debugFingerprint()
if app_name:
db.setAppName(app_name)
if app_ver:
db.setAppVer(app_ver)
if notes:
db.setNotes(notes)
db.writeFingerprint()
else:
print db.getErrorString(retVal)
#
def indexFingerprints(fp_dir):
logging.info("fp_dir=={}".format(fp_dir))
db = FingerprintDB()
fp = FingerprintIndex()
fp.openIndex(fp_dir)
#
def compareFingerprintDir(file_in, fp_dir):
db = FingerprintDB()
db.scanDBFile(file_in)
md5_db = db.getMD5DB()
md5_tables = db.getMD5TablesArray()
fp = FingerprintIndex()
fp.openIndex(fp_dir)
fp_list = fp.findFP(md5_db, md5_tables)
results = []
for fp in fp_list:
fq_fp = fp_dir + os.path.sep + fp
print "[ OPEN fingerprint ] [ {} ]".format(fq_fp)
percent = db.compareDB(fq_fp)
results.append(percent)
print "RESULTS: {}".format(results)
results.sort()
print "RESULTS: {}".format(results)
#
def androidPull():
ap = android.AndroidAppPull()
isRoot = ap.isADBRoot();
if (not isRoot):
print "ERROR: adb is not running as root, exec 'adb root'"
return
if (not mkdir(BASE_DIR)):
logging.error("ERROR creating directory: {}".format(BASE_DIR))
return
if (not mkdir(FP_BASE_DIR)):
logging.error("ERROR creating directory: {}".format(FP_BASE_DIR))
return
dir_names = ap.getAppsDir()
for dir_name in dir_names:
fq_dir = BASE_DIR + os.path.sep + dir_name
ap.pullApp(BASE_DIR, dir_name)
__createFingerprint(fq_dir, FP_BASE_DIR, dir_name)
#
def androidData(data_dir):
dir_names = []
try:
dirs = os.listdir(data_dir)
except:
return
out_dir = FP_BASE_DIR + "_" + ToolBox.getTimestampStr()
if (not mkdir(out_dir)):
logging.error("ERROR creating directory: {}".format(FP_BASE_DIR))
return
for ddir in dirs:
in_dir = data_dir + os.path.sep + ddir
__createFingerprint(in_dir, out_dir, ddir)
# in_dir: fully qualified directory path to find sqlite files
def __createFingerprint(in_dir, out_dir, dir_name):
try:
db_dir = in_dir + os.path.sep + "databases"
logging.info("in_dir=={}".format(db_dir))
files = os.listdir(db_dir)
except:
# not finding a databases folder is normal, not all apps use sqlite
return
for filein in files:
db = FingerprintDB()
ddir = db_dir + os.path.sep + filein
logging.info('Parsing file "{}"'.format(ddir))
retVal = db.scanDBFile(ddir)
if (retVal > 0):
fname = dir_name + "__" + filein + "__dbfp" + ".json"
fq_name = out_dir + os.path.sep + fname
db.setAppName(dir_name)
db.writeFingerprintFile(fq_name)
#
def __getFileName():
'''standardize on a file name, use timestamp? '''
pass
#
def mkdir(fdir):
retval = False
try:
check_call(["mkdir", fdir])
retval = True
except:
logging.error('ERROR: problem creating directory "{}"'.format(fdir))
return retval
#
def parseArgs():
print '***** ***** ***** *****'
print ' DB Fingerprint'
print '***** ***** ***** *****\n'
parser = argparse.ArgumentParser(description="Fingerprint a sqlite database based on its schema")
parser.add_argument('-db', '--database', required=False, help="path to file to be fingerprinted")
parser.add_argument('-fd', '--fpdir', required=False, help="path to directory of fingerprint files")
parser.add_argument('-fp', '--fingerprint', required=False, help="fingerprint file to use in comparison")
parser.add_argument('-dd', '--data_dir', required=False, help="path to a directory with sqlite files")
parser.add_argument('-idx', '--index_fingerprints', required=False, help="path to a directory with sqlite files")
parser.add_argument('-an', '--app_name', required=False)
parser.add_argument('-av', '--app_version', required=False)
parser.add_argument('-n', '--notes', required=False)
parser.add_argument('-pull', required=False, action='store_true', help="automated pull of applications from a physical android phone")
parser.add_argument('-v', '--verbose', action='store_true', help="will set logging level to DEBUG")
parser.add_argument('-l', '--logging', action='store_true', help="will supercede the -v option and send all logging to a file, logging.DEBUG")
# parser.add_argument('-t', '--title', required=False)
args = parser.parse_args()
if (args.logging):
logging.basicConfig(filename='dbfp.log', level=logging.DEBUG)
if (args.verbose):
logging.basicConfig(level=logging.DEBUG)
else:
logging.basicConfig(level=logging.CRITICAL)
if (args.database and args.fingerprint):
compareFingerprint(args.database, args.fingerprint)
elif (args.database and args.fpdir):
compareFingerprintDir(args.database, args.fpdir)
elif (args.data_dir):
androidData(args.data_dir)
elif (args.index_fingerprints):
indexFingerprints(args.index_fingerprints)
elif (args.pull):
androidPull()
elif (args.database):
createFingerprint(args.database, args.verbose, args.app_name, args.app_version, args.notes)
else:
parser.print_help()
if __name__ == "__main__":
main()