def filter_valid_apks(source_directory, valid_apks_directory=None, invalid_apks_directory=None, with_color=True): """ Analyses a set of Android apks with Androguard to filter valid and invalid samples If a JSON file with the same name that the app is found in the source directory, it is also moved Parameters ---------- :param source_directory: Folder containing apk files :param valid_apks_directory: Folder where valid apks are saved :param invalid_apks_directory: Folder where invalid apks are saved :param with_color: If colors are used to print messages """ if not isdir(source_directory): print "Folder not found!" sys.exit(0) if valid_apks_directory is None: valid_apks_directory = join_dir(source_directory, VALID_APKS_DIRECTORY) if invalid_apks_directory is None: invalid_apks_directory = join_dir(source_directory, INVALID_APKS_DIRECTORY) num_valid_apk = 0 num_invalid_apk = 0 files_apks = [ f for f in listdir(source_directory) if isfile(join(source_directory, f)) and f.endswith(".apk") ] print str(len(files_apks)) + " apks found. Processing..." if not os.path.exists(valid_apks_directory): os.makedirs(valid_apks_directory) if not os.path.exists(invalid_apks_directory): os.makedirs(invalid_apks_directory) for apk in tqdm(files_apks): if not apk.endswith(".apk"): shutil.move(join_dir(source_directory, apk), join_dir(source_directory, apk + ".apk")) apk += ".apk" json_file = apk.replace(".apk", ".json") try: apk_analysed = APK(join_dir(source_directory, apk)) valid_apk = apk_analysed.valid_apk except: valid_apk = False if valid_apk: if isfile(join(source_directory, json_file)): shutil.move(join_dir(source_directory, json_file), join_dir(valid_apks_directory, json_file)) shutil.move(join_dir(source_directory, apk), join_dir(valid_apks_directory, apk)) num_valid_apk += 1 else: if isfile(join(source_directory, json_file)): shutil.move(join_dir(source_directory, json_file), join_dir(invalid_apks_directory, json_file)) shutil.move(join_dir(source_directory, apk), join_dir(invalid_apks_directory, apk)) num_invalid_apk += 1 print_message("TOTAL VALID APKS: " + str(num_valid_apk), with_color, "green") print colored("TOTAL INVALID APKS: " + str(num_invalid_apk), "red")
def androsign_main(args_apk, args_hash, args_all, show): from androguard.core.bytecodes.apk import APK from androguard.util import get_certificate_name_string import hashlib import binascii import traceback from colorama import Fore, Style from asn1crypto import x509, keys from oscrypto import asymmetric # Keep the list of hash functions in sync with cli/entry_points.py:sign hashfunctions = dict(md5=hashlib.md5, sha1=hashlib.sha1, sha256=hashlib.sha256, sha512=hashlib.sha512, ) if args_hash.lower() not in hashfunctions: print("Hash function {} not supported!" .format(args_hash.lower()), file=sys.stderr) print("Use one of {}" .format(", ".join(hashfunctions.keys())), file=sys.stderr) sys.exit(1) for path in args_apk: try: a = APK(path) print("{}, package: '{}'".format(os.path.basename(path), a.get_package())) print("Is signed v1: {}".format(a.is_signed_v1())) print("Is signed v2: {}".format(a.is_signed_v2())) print("Is signed v3: {}".format(a.is_signed_v3())) certs = set(a.get_certificates_der_v3() + a.get_certificates_der_v2() + [a.get_certificate_der(x) for x in a.get_signature_names()]) pkeys = set(a.get_public_keys_der_v3() + a.get_public_keys_der_v2()) if len(certs) > 0: print("Found {} unique certificates".format(len(certs))) for cert in certs: if show: x509_cert = x509.Certificate.load(cert) print("Issuer:", get_certificate_name_string(x509_cert.issuer, short=True)) print("Subject:", get_certificate_name_string(x509_cert.subject, short=True)) print("Serial Number:", hex(x509_cert.serial_number)) print("Hash Algorithm:", x509_cert.hash_algo) print("Signature Algorithm:", x509_cert.signature_algo) print("Valid not before:", x509_cert['tbs_certificate']['validity']['not_before'].native) print("Valid not after:", x509_cert['tbs_certificate']['validity']['not_after'].native) if not args_all: print("{} {}".format(args_hash.lower(), hashfunctions[args_hash.lower()](cert).hexdigest())) else: for k, v in hashfunctions.items(): print("{} {}".format(k, v(cert).hexdigest())) print() if len(certs) > 0: print("Found {} unique public keys associated with the certs".format(len(pkeys))) for public_key in pkeys: if show: x509_public_key = asymmetric.load_public_key(public_key) print("PublicKey Algorithm:", x509_public_key.algorithm) print("Bit Size:", x509_public_key.bit_size) print("Fingerprint:", binascii.hexlify(x509_public_key.fingerprint)) try: print("Hash Algorithm:", hash_algo(x509_public_key)) except ValueError as ve: # RSA pkey does not have an hash algorithm pass print() except: print(Fore.RED + "Error in {}".format(os.path.basename(path)) + Style.RESET_ALL, file=sys.stderr) traceback.print_exc(file=sys.stderr) if len(args_apk) > 1: print()
def cert_info(app_dir, app_file): """Return certificate information.""" try: logger.info('Reading Code Signing Certificate') manifestfile = None manidat = '' cert_info = '' certlist = [] cert_path = os.path.join(app_dir, 'META-INF/') apk_file = os.path.join(app_dir, app_file) hashfunctions = { 'md5': hashlib.md5, 'sha1': hashlib.sha1, 'sha256': hashlib.sha256, 'sha512': hashlib.sha512, } files = [ f for f in os.listdir(cert_path) if os.path.isfile(os.path.join(cert_path, f)) ] a = APK(apk_file) if a.is_signed(): certlist.append('APK is signed') else: certlist.append('Missing certificate') certlist.append('v1 signature: {}'.format(a.is_signed_v1())) certlist.append('v2 signature: {}'.format(a.is_signed_v2())) certlist.append('v3 signature: {}'.format(a.is_signed_v3())) certs = set( a.get_certificates_der_v3() + a.get_certificates_der_v2() + [a.get_certificate_der(x) for x in a.get_signature_names()]) pkeys = set(a.get_public_keys_der_v3() + a.get_public_keys_der_v2()) if len(certs) > 0: certlist.append('Found {} unique certificates'.format(len(certs))) for cert in certs: x509_cert = x509.Certificate.load(cert) certlist.append('Subject: {}'.format( get_certificate_name_string(x509_cert.subject, short=True))) certlist.append('Signature Algorithm: {}'.format( x509_cert.signature_algo)) certlist.append('Valid From: {}'.format( x509_cert['tbs_certificate']['validity']['not_before'].native)) certlist.append('Valid To: {}'.format( x509_cert['tbs_certificate']['validity']['not_after'].native)) certlist.append('Issuer: {}'.format( get_certificate_name_string(x509_cert.issuer, short=True))) certlist.append('Serial Number: {}'.format( hex(x509_cert.serial_number))) certlist.append('Hash Algorithm: {}'.format(x509_cert.hash_algo)) for k, v in hashfunctions.items(): certlist.append('{}: {}'.format(k, v(cert).hexdigest())) for public_key in pkeys: x509_public_key = asymmetric.load_public_key(public_key) certlist.append('PublicKey Algorithm: {}'.format( x509_public_key.algorithm)) certlist.append('Bit Size: {}'.format(x509_public_key.bit_size)) certlist.append('Fingerprint: {}'.format( binascii.hexlify(x509_public_key.fingerprint).decode('utf-8'))) cert_info = '\n'.join(certlist) if 'MANIFEST.MF' in files: manifestfile = os.path.join(cert_path, 'MANIFEST.MF') if manifestfile: with open(manifestfile, 'r', encoding='utf-8') as manifile: manidat = manifile.read() sha256_digest = bool(re.findall(r'SHA-256-Digest', manidat)) findings = [] if a.is_signed(): findings.append(('good', 'Application is signed with a code ' 'signing certificate')) else: findings.append(('bad', 'Code signing certificate not found')) if a.is_signed_v1(): status = 'bad' if a.is_signed_v2() or a.is_signed_v3(): status = 'warning' findings.append( (status, 'Application is signed with v1 signature scheme, ' 'making it vulnerable to Janus vulnerability on ' 'Android <7.0')) if re.findall(r'CN=Android Debug', cert_info): findings.append( ('bad', 'Application signed with a debug certificate. ' 'Production application must not be shipped ' 'with a debug certificate.')) if re.findall(r'Hash Algorithm: sha1', cert_info): status = 'bad' desc = ('Application is signed with SHA1withRSA. ' 'SHA1 hash algorithm is known to have ' 'collision issues.') if sha256_digest: status = 'warning' desc += (' The manifest file indicates SHA256withRSA' ' is in use.') findings.append((status, desc)) cert_dic = { 'certificate_info': cert_info, 'certificate_findings': findings, } return cert_dic except Exception: logger.exception('Reading Code Signing Certificate') return {}
def run(self): """Run Google play unofficial python api the get the google play information @return: list of google play features """ self.key = "googleplay" googleplay = {} if not HAVE_GOOGLEPLAY: log.error("Unable to import the GooglePlay library, has it been " "installed properly?") return if not HAVE_ANDROGUARD: log.error("Could not find the Androguard library, please install " "it. (`pip install androguard`)") if ("file" not in self.task["category"]): return f = File(self.task["target"]) if f.get_name().endswith((".zip", ".apk")) or "zip" in f.get_type(): if not os.path.exists(self.file_path): raise CuckooProcessingError( "Sample file doesn't exist: \"%s\"" % self.file_path) android_id = self.options.get("android_id") google_login = self.options.get("google_login") google_password = self.options.get("google_password") # auth_token = self.options.get("auth_token", None) if not android_id and not google_login and not google_password: raise CuckooProcessingError( "Google Play Credentials not configured, skip") try: a = APK(self.file_path) if a.is_valid_APK(): package = a.get_package() # Connect api = GooglePlayAPI(android_id) api.login(google_login, google_password, None) # Get the version code and the offer type from the app details app_data = api.details(package) app_detail = app_data.docV2.details.appDetails if not app_detail.installationSize: return googleplay googleplay["title"] = app_detail.title googleplay["app_category"] = app_detail.appCategory._values googleplay["version_code"] = app_detail.versionCode googleplay["app_type"] = app_detail.appType googleplay["content_rating"] = app_detail.contentRating googleplay["developer_email"] = app_detail.developerEmail googleplay["developer_name"] = app_detail.developerName googleplay[ "developer_website"] = app_detail.developerWebsite googleplay[ "installation_size"] = app_detail.installationSize googleplay["num_downloads"] = app_detail.numDownloads googleplay["upload_date"] = app_detail.uploadDate googleplay["permissions"] = app_detail.permission._values except (IOError, OSError, BadZipfile) as e: raise CuckooProcessingError("Error opening file %s" % e) return googleplay
# Parsing and calculating testme = nlp(apkstr) if testme.similarity(sample) > 0.7: for token in testme: if token.pos_ == "PUNCT": pass else: print(f"{cyan}({magenta}*{cyan})->{white} {apkstr}") # Execution if __name__ == '__main__': try: # Getting and parsing target APK targetAPK = str(sys.argv[1]) parsed = APK(targetAPK) # Permissions side Analyzer(parsed) # Deep scanner DeepScan(parsed) # Strings side print( f"{infoS} Analyzing interesting strings. It will take a while...\n" ) #Thread Number threadNumber = 0
def get_package_name(apk_path): """ Extract the package name of an APK """ a = APK(apk_path) return a.get_package(), a.get_androidversion_code()
from androguard.core.bytecodes.apk import APK from androguard.core.bytecodes.dvm import DalvikVMFormat from androguard.core.bytecodes.dvm import ClassDefItem a = APK("C:/Users/jysrm/OneDrive/바탕 화면/study/test.apk") f = open("new.txt", 'w') d = DalvikVMFormat(a) code_item = d.get_codes_item() code = code_item.show() f.write(code) f.close()
from androguard.core.bytecodes.axml import AXMLPrinter from androguard.core.bytecodes.axml import ARSCParser ANDROID_SCHEME = "{http://schemas.android.com/apk/res/android}scheme" ANDROID_HOST = "{http://schemas.android.com/apk/res/android}host" ANDROID_NAME = "{http://schemas.android.com/apk/res/android}name" ANDROID_BACKUP = "{http://schemas.android.com/apk/res/android}allowBackup" ANDROID_CLEAR = "{http://schemas.android.com/apk/res/android}usesCleartextTraffic" ANDROID_VALUE = "{http://schemas.android.com/apk/res/android}value" if len(sys.argv) != 2: print("Введите путь к APK\n") exit(400) file = sys.argv[1] apk = APK(file) axml = apk.get_android_manifest_xml() lil_pow = 0 print("Флаги безопасности Manifest'а\n" "а. Установки CleartextTraffic:") guess = axml.find("./application[@{}]".format(ANDROID_CLEAR)) if guess != None: print(guess.attrib.get(ANDROID_CLEAR)) else: print("Не обнаружено.") print("b. Установки allowBackup:") guess = axml.find("./application[@{}]".format(ANDROID_BACKUP)) if guess != None:
def is_valid_apk(p, arg): if not (os.path.exists(arg) and os.path.isfile(arg) and APK(arg).is_valid_APK()): p.error("[ERROR] The APK file {} is not valid!".format(arg)) return arg
def analyze_apk(task, scan_id): # Start the APK analysis global APK_PATH global DECOMPILE_PATH try: scan = Scan.objects.get(pk=scan_id) APK_PATH = settings.BASE_DIR + scan.apk.url DECOMPILE_PATH = os.path.splitext(APK_PATH)[0] scan.status = 'In Progress' scan.progress = 3 scan.save() task.update_state(state = 'STARTED', meta = {'current': scan.progress, 'total': 100, 'status': scan.status}) logger.debug(scan.status) a = APK(APK_PATH) scan = set_hash_app(scan) scan.status = 'Getting info of apk' scan.progress = 5 scan.save() task.update_state(state = 'STARTED', meta = {'current': scan.progress, 'total': 100, 'status': scan.status}) logger.debug(scan.status) scan = get_info_apk(a, scan) scan.status = 'Getting info of certificates' scan.progress = 10 scan.save() task.update_state(state = 'STARTED', meta = {'current': scan.progress, 'total': 100, 'status': scan.status}) logger.debug(scan.status) certificates = get_info_certificate(a, scan) if (settings.VIRUSTOTAL_ENABLED): scan.status = 'Getting info of VT' scan.progress = 15 scan.save() task.update_state(state = 'STARTED', meta = {'current': scan.progress, 'total': 100, 'status': scan.status}) logger.debug(scan.status) report = get_report_virus_total(scan, scan.sha256) if (not report and settings.VIRUSTOTAL_UPLOAD): scan.status = 'Upload to VT' scan.save() upload_virus_total(scan, APK_PATH, scan.sha256) scan.status = 'Decompiling' scan.progress = 20 scan.save() task.update_state(state = 'STARTED', meta = {'current': scan.progress, 'total': 100, 'status': scan.status}) logger.debug(scan.status) decompile_jadx() if (a.get_app_icon()): update_icon(scan, DECOMPILE_PATH + '/resources/' + a.get_app_icon()) scan.status = 'Finding vulnerabilities' scan.progress = 40 task.update_state(state = 'STARTED', meta = {'current': scan.progress, 'total': 100, 'status': scan.status}) scan.save() logger.debug(scan.status) findings = get_tree_dir(scan) scan.status = 'Finished' scan.progress = 100 scan.finished_on = datetime.now() scan.save() task.update_state(state = 'STARTED', meta = {'current': scan.progress, 'total': 100, 'status': scan.status}) logger.debug(scan.status) except Exception as e: scan.progress = 100 scan.status = "Error" scan.finished_on = datetime.now() scan.save() task.update_state(state = 'STARTED', meta = {'current': scan.progress, 'total': 100, 'status': scan.status}) logger.error(e)
def main(options, args): if options.emulator is None or options.file is None or options.policy is None: sys.exit('please confirm the parameters are correct') emulator = options.emulator apk_path = options.file policy = options.policy device = Device(emulator) if options.install: stevedore.install_apk(apk_path, device) if not os.path.isdir(LOGS): os.mkdir(LOGS) sha256 = hashlib.sha256() sha256.update(open(apk_path).read()) sha256sum = sha256.hexdigest() log_file = os.path.join(LOGS, sha256sum + '.log') if not os.path.isfile(log_file): #print 'writing log file into %s' % log_file try: apk = APK(apk_path) except Exception as ex: return False, ex if not apk.is_valid_APK(): return False, 'It is not a valid apk' activities = [] for act in apk.get_activities(): if not filtered(act, FILTERED_ACTIVITY): activities.append(act) services = apk.get_services() receivers = [] for rec in apk.get_receivers(): if not filtered(rec, FILTERED_BROADCAST): receivers.append(rec) package_name = apk.get_package() #write to log file with open(log_file, 'w') as fout: fout.write('package_name=' + package_name + '\n') fout.write('activity=' + ' '.join(activities) + '\n') fout.write('service=' + ' '.join(services) + '\n') fout.write('receiver=' + ' '.join(receivers) + '\n') else: #print 'reading log file from %s' % log_file with open(log_file, 'r') as fin: for line in fin.readlines(): if line.startswith('package_name='): package_name = line.replace('package_name=', '') elif line.startswith('activity='): activities = line.replace('activity=', '').split() elif line.startswith('service='): services = line.replace('service=', '').split() elif line.startswith('receiver='): receivers = line.replace('receiver=', '').split() if policy == 'random': policy = ['broadcast', 'listener', 'launcher', 'service', 'receiver'][random.randint(0, 4)] if policy == 'broadcast': actions = IntentEvent.get_intent_actions() if len(actions) > 0: selected = actions[random.randint(0, len(actions) - 1)] intent = IntentEvent(action=selected, package_name=package_name) intent.execute(device) elif policy == 'listener': if emulator.startswith('emulator'): listener_type = ['sms', 'gsm', 'rotate', 'volume'][random.randint(0, 3)] listener = ListenerEvent(listener_type) listener.execute(device) else: listener_type = ['sms', 'rotate', 'volume'][random.randint(0, 2)] if listener_type == 'sms': intent = IntentEvent( action='android.provider.Telephony.SMS_RECEIVED' ) #, package_name=package_name) intent.execute(device) else: listener = ListenerEvent(listener_type) listener.execute(device) elif policy == 'launcher': if len(activities) > 0: selected = activities[random.randint(0, len(activities) - 1)] launcher = LauncherEvent(package_name, selected) launcher.execute(device) elif policy == 'service': if len(services) > 0: selected = services[random.randint(0, len(services) - 1)] service = ServiceEvent(package_name, selected) service.execute(device) if random.randint(0, 1) == 1: import time time.sleep(3) service = ServiceEvent(package_name=package_name, service_name=selected, stop=True) service.execute(device) elif policy == 'receiver': if len(receivers) > 0: selected = receivers[random.randint(0, len(receivers) - 1)] receiver = ReceiverEvent(package_name, selected) receiver.execute(device)
def extract_features(file_path): result = {} try: a = APK(file_path) d = DalvikVMFormat(a.get_dex()) dx = Analysis(d) vm = dvm.DalvikVMFormat(a.get_dex()) vmx = analysis.Analysis(vm) d.set_vmanalysis(dx) d.set_decompiler(DecompilerDAD(d, dx)) except Exception as e: print e return None result['android_version_code'] = a.get_androidversion_code() result['android_version_name'] = a.get_androidversion_name() result['max_sdk'] = a.get_max_sdk_version() result['min_sdk'] = a.get_min_sdk_version() result['libraries'] = a.get_libraries() result['filename'] = a.get_filename() result['target_sdk'] = a.get_target_sdk_version() result['md5'] = hashlib.md5(a.get_raw()).hexdigest() result['sha256'] = hashlib.sha256(a.get_raw()).hexdigest() result['permissions'] = a.get_permissions() result['activities'] = a.get_activities() result['providers'] = a.get_providers() result['services'] = a.get_services() result['strings'] = d.get_strings() result['class_names'] = [c.get_name() for c in d.get_classes()] result['method_names'] = [m.get_name() for m in d.get_methods()] result['field_names'] = [f.get_name() for f in d.get_fields()] # result['is_native_code'] = 1 if analysis.is_native_code(dx) else 0 result['is_obfuscation'] = 1 if analysis.is_ascii_obfuscation(d) else 0 # result['is_crypto_code'] = 1 if analysis.is_crypto_code(dx) else 0 # result['is_dyn_code'] = 1 if analysis.is_dyn_code(dx) else 0 # result['is_reflection_code'] = 1 if analysis.is_reflection_code(vmx) else 0 result['is_database'] = 1 if d.get_regex_strings(DB_REGEX) else 0 s_list = [] s_list.extend(result['class_names']) s_list.extend(result['method_names']) s_list.extend(result['field_names']) result['entropy_rate'] = entropy_rate(s_list) result['feature_vectors'] = {} result['feature_vectors']['api_calls'] = [] for call in API_CALLS: status = 1 if dx.get_method_by_name(".", call, ".") else 0 result['feature_vectors']['api_calls'].append(status) result['feature_vectors']['permissions'] = [] for permission in PERMISSIONS: status = 1 if permission in result['permissions'] else 0 result['feature_vectors']['permissions'].append(status) result['feature_vectors']['special_strings'] = [] for word in SPECIAL_STRINGS: status = 1 if d.get_regex_strings(word) else 0 result['feature_vectors']['special_strings'].append(status) result['feature_vectors']['others'] = [ # result['is_reflection_code'], # result['is_crypto_code'], # result['is_native_code'], result['is_obfuscation'], result['is_database'], # result['is_dyn_code'] ] return result
def run(self): """Run androguard to extract static android information @return: list of static features """ self.key = "apkinfo" apkinfo = {} if "file" not in self.task["category"] or not HAVE_ANDROGUARD: return f = File(self.task["target"]) #if f.get_name().endswith((".zip", ".apk")) or "zip" in f.get_type(): if not os.path.exists(self.file_path): raise CuckooProcessingError("Sample file doesn't exist: \"%s\"" % self.file_path) try: a = APK(self.file_path) if a.is_valid_APK(): manifest = {} apkinfo["files"] = self._apk_files(a) manifest["package"] = a.get_package() apkinfo["hidden_payload"] = [] for file in apkinfo["files"]: if self.file_type_check(file): apkinfo["hidden_payload"].append(file) apkinfo["files_flaged"] = self.files_name_map manifest["permissions"] = get_permissions(a) manifest["main_activity"] = a.get_main_activity() manifest["activities"] = a.get_activities() manifest["services"] = a.get_services() manifest["receivers"] = a.get_receivers() manifest["receivers_actions"] = get_extended_receivers(a) manifest["providers"] = a.get_providers() manifest["libraries"] = list(a.get_libraries()) apkinfo["manifest"] = manifest apkinfo["icon"] = get_apk_icon(self.file_path) certificate = get_certificate(self.file_path) if certificate: apkinfo["certificate"] = certificate #vm = DalvikVMFormat(a.get_dex()) #strings = vm.get_strings() strings = self._get_strings(self.file_path) apkinfo["interesting_strings"] = find_strings(strings) apkinfo["dex_strings"] = strings static_calls = {} if self.options.decompilation: if self.check_size(apkinfo["files"]): vm = DalvikVMFormat(a.get_dex()) vmx = Analysis(vm) vmx.create_xref() static_calls["all_methods"] = get_methods(vmx) static_calls[ "permissions_method_calls"] = get_show_Permissions( vmx) static_calls[ "native_method_calls"] = get_show_NativeMethods( vmx) static_calls["is_native_code"] = bool( static_calls["native_method_calls"] ) # True if not empty, False if empty static_calls[ "dynamic_method_calls"] = get_show_DynCode(vmx) static_calls["is_dynamic_code"] = bool( static_calls["dynamic_method_calls"]) static_calls[ "reflection_method_calls"] = get_show_ReflectionCode( vmx) static_calls["is_reflection_code"] = bool( static_calls["reflection_method_calls"]) static_calls[ "crypto_method_calls"] = get_show_CryptoCode(vmx) static_calls["is_crypto_code"] = bool( static_calls["crypto_method_calls"]) classes = list() for cls in vm.get_classes(): classes.append(cls.name) static_calls["classes"] = classes else: log.warning( "Aborted decompilation, static extraction of calls not perforemd", ) apkinfo["static_method_calls"] = static_calls except (IOError, OSError, BadZipfile) as e: raise CuckooProcessingError("Error opening file %s" % e) return apkinfo
def reverse(nameApk): # doc file config with open(config_file, "r+") as f: dataConfig = json.load(f) maxLabelsNum = dataConfig['maxLabelsNum'] # Label tong hop # with open(LabelsNum_file, "r+") as file_LabeslNum: # LABELSNUMANDTEXT = json.load(file_LabeslNum) # Load Android API packages and classes global API_PACKAGES_LIST, API_CLASSES_LIST, API_SYSTEM_COMMANDS ############################################################ # READING PACKAGES, CLASSES AND SYSTEM COMMANDS ############################################################ package_file = load_file(str(package_index_file)) API_PACKAGES_LIST = [x.strip() for x in package_file] class_file = load_file(str(classes_index_file)) API_CLASSES_LIST = [x.strip() for x in class_file] commands_file = load_file(str(system_commands_file)) API_SYSTEM_COMMANDS = [x.strip() for x in commands_file] static_analysis_dict = collections.OrderedDict() try: analyze_apk = os.path.join(TEMP,nameApk) # Getting the name of the folder that contains all apks and folders with apks base_folder = TEMP.split("/")[-1] apk_filename = join_dir(base_folder, analyze_apk.replace(TEMP, '')) apk_filename = apk_filename.replace("//", "/") apk_name_no_extensions = "".join(apk_filename.split("/")[-1].split(".")[:-1]) # export to monggoDB # if os.path.isfile(join_dir(output_folder, apk_filename.split("/")[-1].replace('.apk', '-analysis.json'))): # database[apk_filename.replace('.apk', '')] = json.load( # open(join_dir(output_folder, apk_filename.split("/")[-1]. # replace('.apk', '-analysis.json')))) # continue pre_static_dict = collections.OrderedDict() pre_static_dict['Filename'] = apk_filename hasher_md5 = hashlib.md5() hasher_sha256 = hashlib.sha256() hasher_sha1 = hashlib.sha1() with open(analyze_apk, 'rb') as afile: buf = afile.read() hasher_md5.update(buf) hasher_sha256.update(buf) hasher_sha1.update(buf) md5 = hasher_md5.hexdigest() sha256 = hasher_sha256.hexdigest() sha1 = hasher_sha1.hexdigest() pre_static_dict["md5"] = md5 pre_static_dict["sha256"] = sha256 pre_static_dict["sha1"] = sha1 """ if label is not None: pre_static_dict["Label"] = label else: pre_static_dict["Label"] = "/".join(apk_filename.split("/")[:-1]) """ pre_static_dict["VT_positives"] = None apk_Oject = APK(analyze_apk) # get package name static_analysis_dict['Package_name'] = apk_Oject.get_package() # get Permission static_analysis_dict['Permissions'] = apk_Oject.get_permissions() # Activities try: list_activities = apk_Oject.get_activities() except UnicodeEncodeError: list_activities = [] # get Main ACtivity static_analysis_dict['Main_activity'] = apk_Oject.get_main_activity() # Receivers try: list_receivers = apk_Oject.get_receivers() except UnicodeEncodeError: list_receivers = [] # Services try: list_services = apk_Oject.get_services() except UnicodeEncodeError: list_services = [] # API calls and Strings list_smali_api_calls, list_smali_strings = read_strings_and_apicalls(analyze_apk, API_PACKAGES_LIST, API_CLASSES_LIST) for api_call in list_smali_api_calls.keys(): new_api_call = '.'.join(api_call.split(".")[:-1]) if new_api_call in list_smali_api_calls.keys(): list_smali_api_calls[new_api_call] = list_smali_api_calls[new_api_call] + list_smali_api_calls[ api_call] else: list_smali_api_calls[new_api_call] = list_smali_api_calls[api_call] del list_smali_api_calls[api_call] static_analysis_dict['API_calls'] = list_smali_api_calls static_analysis_dict['Strings'] = Counter(filter(None, list_smali_strings)) # API packages API_packages_dict = collections.OrderedDict() android_list_packages_lenghts = [len(x.split(".")) for x in API_PACKAGES_LIST] list_api_calls_keys = list_smali_api_calls.keys() for api_call in list_api_calls_keys: score = 0 package_chosen = None for i, package in enumerate(API_PACKAGES_LIST): len_package = android_list_packages_lenghts[i] if api_call.startswith(package) and len_package > score: score = len_package package_chosen = package if package_chosen is not None: if not package_chosen in API_packages_dict.keys(): API_packages_dict[package_chosen] = list_smali_api_calls[api_call] else: API_packages_dict[package_chosen] += list_smali_api_calls[api_call] static_analysis_dict['API_packages'] = API_packages_dict # Intents try: static_analysis_dict['Intents'] = intents_analysis(join_dir(analyze_apk.replace('.apk', ''), 'AndroidManifest.xml')) except: static_analysis_dict['Intents'] = {'Failed to extract intents': 0} # Intents of activities intents_activities = collections.OrderedDict() for activity in list_activities: intents_activities[activity] = check_for_intents(join_dir(analyze_apk.replace('.apk', ''), 'AndroidManifest.xml'), activity, 'activity') static_analysis_dict['Activities'] = intents_activities # Intents of services intents_services = collections.OrderedDict() for service in list_services: intents_services[service] = check_for_intents(join_dir(analyze_apk.replace('.apk', ''), 'AndroidManifest.xml'), service, 'service') static_analysis_dict['Services'] = intents_services # Intents of receivers intents_receivers = collections.OrderedDict() for intent in list_receivers: intents_receivers[intent] = check_for_intents(join_dir(analyze_apk.replace('.apk', '/'), 'AndroidManifest.xml'), intent, 'receiver') static_analysis_dict['Receivers'] = intents_receivers static_analysis_dict['Receivers'] = intents_receivers apk_total_analysis = collections.OrderedDict([("Pre_static_analysis", pre_static_dict), ("Static_analysis", static_analysis_dict)]) # # save_as_json(apk_total_analysis, output_name=join_dir(output_folder, apk_name_no_extensions + # "-analysis.json")) row = standardData(pre_static_dict, static_analysis_dict) csvFileClient = open(DataCSVClient + md5 + '.csv', 'w+', newline='') writer = csv.writer(csvFileClient, delimiter=',') writer.writerow(row) csvFileClient.close() delAPk(analyze_apk) if checkMerge(DataCSVClient, dataConfig['mergeCSV']): mergeCSV() return md5, apk_total_analysis except Exception as e: print('Exception: ', e) return 'Error', 'No features'
private_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption())) current_dir = os.getcwd() script_dir = dir_path = os.path.dirname(os.path.realpath(__file__)) if sys.version_info < (3, 6): raise RuntimeError("This application requires Python 3.6+") if not argv[1].endswith(".apk"): print("No apk given") sys.exit(1) print("APK loading...") a = APK(argv[1]) package_name = a.get_package() resources = a.get_android_resources() # .get_strings_resources() client_id = resources.get_string(package_name, "PSA_API_CLIENT_ID_PROD")[1] client_secret = resources.get_string(package_name, "PSA_API_CLIENT_SECRET_PROD")[1] HOST_BRANDID_PROD = resources.get_string(package_name, "HOST_BRANDID_PROD")[1] pfx_cert = a.get_file("assets/MWPMYMA1.pfx") REMOTE_REFRESH_TOKEN = None print("APK loaded !") client_email = input(f"{BRAND[package_name]['app_name']} email: ") client_password = getpass(f"{BRAND[package_name]['app_name']} password: "******"What is your country code ? (ex: FR, GB, DE, ES...)\n")
def testApksignAPKs(self): # These APKs are from the apksign testcases and cover # all different signature algorithms as well as some error cases from androguard.core.bytecodes.apk import APK import zipfile from asn1crypto import x509, pem import binascii root = "examples/signing/apksig" # Correct values generated with openssl: certfp = { "dsa-1024.x509.pem": "fee7c19ff9bfb4197b3727b9fd92d95406b1bd96db99ea642f5faac019a389d7", "dsa-2048.x509.pem": "97cce0bab292c2d5afb9de90e1810b41a5d25c006a10d10982896aa12ab35a9e", "dsa-3072.x509.pem": "966a4537058d24098ea213f12d4b24e37ff5a1d8f68deb8a753374881f23e474", "ec-p256.x509.pem": "6a8b96e278e58f62cfe3584022cec1d0527fcb85a9e5d2e1694eb0405be5b599", "ec-p384.x509.pem": "5e7777ada7ee7ce8f9c4d1b07094876e5604617b7988b4c5d5b764a23431afbe", "ec-p521.x509.pem": "69b50381d98bebcd27df6d7df8af8c8b38d0e51e9168a95ab992d1a9da6082da", "rsa-1024.x509.pem": "bc5e64eab1c4b5137c0fbc5ed05850b3a148d1c41775cffa4d96eea90bdd0eb8", "rsa-16384.x509.pem": "f3c6b37909f6df310652fbd7c55ec27d3079dcf695dc6e75e22ba7c4e1c95601", "rsa-2048.x509.pem": "fb5dbd3c669af9fc236c6991e6387b7f11ff0590997f22d0f5c74ff40e04fca8", "rsa-3072.x509.pem": "483934461229a780010bc07cd6eeb0b67025fc4fe255757abbf5c3f2ed249e89", "rsa-4096.x509.pem": "6a46158f87753395a807edcc7640ac99c9125f6b6e025bdbf461ff281e64e685", "rsa-8192.x509.pem": "060d0a24fea9b60d857225873f78838e081795f7ef2d1ea401262bbd75a58234", } will_not_validate_correctly = [ "targetSandboxVersion-2.apk", "targetSandboxVersion-2.apk", "v1-only-with-cr-in-entry-name.apk", "v1-only-with-lf-in-entry-name.apk", "v1-only-with-nul-in-entry-name.apk", "v1-only-with-rsa-1024-cert-not-der2.apk", "v2-only-cert-and-public-key-mismatch.apk", "v2-only-with-dsa-sha256-1024-sig-does-not-verify.apk", ] # Collect possible hashes for certificates # Unfortunately, not all certificates are supplied... for apath in os.listdir(root): if apath in certfp: with open(os.path.join(root, apath), "rb") as fp: cert = x509.Certificate.load(pem.unarmor(fp.read())[2]) h = cert.sha256_fingerprint.replace(" ", "").lower() self.assertEqual(h, certfp[apath]) self.assertIn(h, certfp.values()) for apath in os.listdir(root): if apath.endswith(".apk"): if apath == "v2-only-garbage-between-cd-and-eocd.apk" or \ apath == "v2-only-truncated-cd.apk": # Can not load as APK if sys.version_info.major == 2: # Different name in python2... with self.assertRaises(zipfile.BadZipfile): APK(os.path.join(root, apath)) else: with self.assertRaises(zipfile.BadZipFile): APK(os.path.join(root, apath)) continue elif apath in will_not_validate_correctly: # These APKs are faulty (by design) and will return a not correct fingerprint. # TODO: we need to check if we can prevent such errors... continue a = APK(os.path.join(root, apath)) self.assertIsInstance(a, APK) # Special error cases if apath == "v2-only-apk-sig-block-size-mismatch.apk": with self.assertRaises(AssertionError): a.is_signed_v2() continue elif apath == "v2-only-empty.apk": with self.assertRaises(AssertionError): a.is_signed_v2() continue if a.is_signed_v1(): if apath == "weird-compression-method.apk": with self.assertRaises(NotImplementedError): for c in a.get_signature_names(): a.get_certificate(c) elif apath == "v1-only-with-rsa-1024-cert-not-der.apk": for sig in a.get_signature_names(): c = a.get_certificate(sig) h = c.sha256_fingerprint.replace(" ", "").lower() self.assertNotIn(h, certfp.values()) # print([apath, h]) # I do not know, why put this file? der = a.get_certificate_der(sig) apk.show_Certificate(c, True) apk.show_Certificate(c, False) self.assertEqual( hashlib.sha256(der).hexdigest(), h) pass else: for sig in a.get_signature_names(): c = a.get_certificate(sig) h = c.sha256_fingerprint.replace(" ", "").lower() self.assertIn(h, certfp.values()) # Check that we get the same signature if we take the DER der = a.get_certificate_der(sig) self.assertEqual( hashlib.sha256(der).hexdigest(), h) if a.is_signed_v2(): if apath == "weird-compression-method.apk": with self.assertRaises(NotImplementedError): a.get_certificates_der_v2() elif apath == "v2-only-with-rsa-pkcs1-sha256-1024-cert-not-der.apk": # FIXME # Not sure what this one should do... but the certificate fingerprint is weird # as the hash over the DER is not the same when using the certificate continue else: for c in a.get_certificates_der_v2(): cert = x509.Certificate.load(c) h = cert.sha256_fingerprint.replace(" ", "").lower() self.assertIn(h, certfp.values()) # Check that we get the same signature if we take the DER self.assertEqual(hashlib.sha256(c).hexdigest(), h)
def analyzeAPK(filename, raw=False, decompiler=None): a = APK(filename, raw) return a
def testAPKActivitiesAreString(self): from androguard.core.bytecodes.apk import APK a = APK("examples/tests/a2dp.Vol_137.apk", testzip=True) activities = a.get_activities() self.assertTrue(isinstance(activities[0], str), 'activities[0] is not of type str')
def __init__(self, app_path): self.app_path = app_path from androguard.core.bytecodes.apk import APK self.a = APK(app_path) self.d = None self.dx = None
def testEffectiveTargetSdkVersion(self): from androguard.core.bytecodes.apk import APK a = APK('examples/android/abcore/app-prod-debug.apk') self.assertEqual(27, a.get_effective_target_sdk_version()) a = APK('examples/android/Invalid/Invalid.apk') self.assertEqual(15, a.get_effective_target_sdk_version()) a = APK('examples/android/TC/bin/TC-debug.apk') self.assertEqual(1, a.get_effective_target_sdk_version()) a = APK('examples/android/TCDiff/bin/TCDiff-debug.apk') self.assertEqual(1, a.get_effective_target_sdk_version()) a = APK('examples/android/TestsAndroguard/bin/TestActivity.apk') self.assertEqual(16, a.get_effective_target_sdk_version()) a = APK( 'examples/android/TestsAndroguard/bin/TestActivity_unsigned.apk') self.assertEqual(16, a.get_effective_target_sdk_version()) a = APK('examples/dalvik/test/bin/Test-debug.apk') self.assertEqual(1, a.get_effective_target_sdk_version()) a = APK('examples/dalvik/test/bin/Test-debug-unaligned.apk') self.assertEqual(1, a.get_effective_target_sdk_version()) a = APK('examples/tests/a2dp.Vol_137.apk') self.assertEqual(25, a.get_effective_target_sdk_version()) a = APK('examples/tests/hello-world.apk') self.assertEqual(25, a.get_effective_target_sdk_version()) a = APK('examples/tests/duplicate.permisssions_9999999.apk') self.assertEqual(27, a.get_effective_target_sdk_version()) a = APK('examples/tests/com.politedroid_4.apk') self.assertEqual(3, a.get_effective_target_sdk_version())
from androguard.core.bytecodes.apk import APK from androguard.core.bytecodes.dvm import DalvikVMFormat from androguard.core.analysis.analysis import Analysis from androguard.decompiler.decompiler import DecompilerJADX from androguard.core.androconf import show_logging import logging # Enable log output show_logging(level=logging.DEBUG) # Load our example APK a = APK("examples/android/TestsAndroguard/bin/TestActivity.apk") # Create DalvikVMFormat Object d = DalvikVMFormat(a) # Create Analysis Object dx = Analysis(d) # Load the decompiler # Set the path to the jadx executable! decompiler = DecompilerJADX(d, dx, jadx="/home/vagrant/jadx/build/jadx/bin/jadx") # propagate decompiler and analysis back to DalvikVMFormat d.set_decompiler(decompiler) d.set_vmanalysis(dx) # Now you can do stuff like: for m in d.get_methods()[:10]: print(m) print(decompiler.get_source_method(m))
def testUsesImpliedPermissions(self): from androguard.core.bytecodes.apk import APK a = APK('examples/android/abcore/app-prod-debug.apk') self.assertEqual([ ['android.permission.READ_EXTERNAL_STORAGE', None], ], a.get_uses_implied_permission_list()) a = APK('examples/android/Invalid/Invalid.apk') self.assertEqual([], a.get_uses_implied_permission_list()) a = APK('examples/android/TC/bin/TC-debug.apk') self.assertEqual([ ['android.permission.WRITE_EXTERNAL_STORAGE', None], ['android.permission.READ_PHONE_STATE', None], ['android.permission.READ_EXTERNAL_STORAGE', None], ], a.get_uses_implied_permission_list()) a = APK('examples/android/TCDiff/bin/TCDiff-debug.apk') self.assertEqual([ ['android.permission.WRITE_EXTERNAL_STORAGE', None], ['android.permission.READ_PHONE_STATE', None], ['android.permission.READ_EXTERNAL_STORAGE', None], ], a.get_uses_implied_permission_list()) a = APK('examples/android/TestsAndroguard/bin/TestActivity.apk') self.assertEqual([], a.get_uses_implied_permission_list()) a = APK( 'examples/android/TestsAndroguard/bin/TestActivity_unsigned.apk') self.assertEqual([], a.get_uses_implied_permission_list()) a = APK('examples/dalvik/test/bin/Test-debug.apk') self.assertEqual([ ['android.permission.WRITE_EXTERNAL_STORAGE', None], ['android.permission.READ_PHONE_STATE', None], ['android.permission.READ_EXTERNAL_STORAGE', None], ], a.get_uses_implied_permission_list()) a = APK('examples/dalvik/test/bin/Test-debug-unaligned.apk') self.assertEqual([ ['android.permission.WRITE_EXTERNAL_STORAGE', None], ['android.permission.READ_PHONE_STATE', None], ['android.permission.READ_EXTERNAL_STORAGE', None], ], a.get_uses_implied_permission_list()) a = APK('examples/tests/a2dp.Vol_137.apk') self.assertEqual([ ['android.permission.READ_EXTERNAL_STORAGE', None], ], a.get_uses_implied_permission_list()) a = APK('examples/tests/com.politedroid_4.apk') self.assertEqual([ ['android.permission.WRITE_EXTERNAL_STORAGE', None], ['android.permission.READ_PHONE_STATE', None], ['android.permission.READ_EXTERNAL_STORAGE', None], ], a.get_uses_implied_permission_list()) a = APK('examples/tests/duplicate.permisssions_9999999.apk') self.assertEqual([ ['android.permission.READ_EXTERNAL_STORAGE', 18], ], a.get_uses_implied_permission_list()) a = APK('examples/tests/hello-world.apk') self.assertEqual([], a.get_uses_implied_permission_list()) a = APK('examples/tests/urzip-πÇÇπÇÇ现代汉语通用字-български-عربي1234.apk') self.assertEqual([], a.get_uses_implied_permission_list())
def main(): parser = get_parser() args = parser.parse_args() hashfunctions = dict( md5=hashlib.md5, sha1=hashlib.sha1, sha256=hashlib.sha256, sha512=hashlib.sha512, ) if args.hash.lower() not in hashfunctions: print("Hash function {} not supported!".format(args.hash.lower()), file=sys.stderr) print("Use one of {}".format(", ".join(hashfunctions.keys())), file=sys.stderr) sys.exit(1) for path in args.apk: try: a = APK(path) print("{}, package: '{}'".format(os.path.basename(path), a.get_package())) print("Is signed v1: {}".format(a.is_signed_v1())) print("Is signed v2: {}".format(a.is_signed_v2())) certs = set( a.get_certificates_der_v2() + [a.get_certificate_der(x) for x in a.get_signature_names()]) if len(certs) > 0: print("Found {} unique certificates".format(len(certs))) for cert in certs: if args.show: x509_cert = x509.Certificate.load(cert) print( "Issuer:", get_certificate_name_string(x509_cert.issuer, short=True)) print( "Subject:", get_certificate_name_string(x509_cert.subject, short=True)) print("Serial Number:", hex(x509_cert.serial_number)) print("Hash Algorithm:", x509_cert.hash_algo) print("Signature Algorithm:", x509_cert.signature_algo) print( "Valid not before:", x509_cert['tbs_certificate'] ['validity']['not_before'].native) print( "Valid not after:", x509_cert['tbs_certificate'] ['validity']['not_after'].native) if not args.all: print("{} {}".format( args.hash.lower(), hashfunctions[args.hash.lower()](cert).hexdigest())) else: for k, v in hashfunctions.items(): print("{} {}".format(k, v(cert).hexdigest())) print() except: print(Fore.RED + "Error in {}".format(os.path.basename(path)) + Style.RESET_ALL, file=sys.stderr) traceback.print_exc(file=sys.stderr) if len(args.apk) > 1: print()
def get_dex(apk_path): """ Extract the package name of an APK """ a = APK(apk_path) return a.get_dex()
def load_apk(self, apk): if apk is not None and os.path.isfile(apk): self.apk = APK(apk) else: raise IOError("{0} could not be loaded".format(apk))
def extract_features(file_path): result = {} try: a = APK(file_path) d = DalvikVMFormat(a.get_dex()) dx = Analysis(d) vm = dvm.DalvikVMFormat(a.get_dex()) #vmx = analysis.uVMAnalysis(vm) d.set_vmanalysis(dx) d.set_decompiler(DecompilerDAD(d, dx)) except: return None result['android_version_code'] = a.get_androidversion_code() result['android_version_name'] = a.get_androidversion_name() result['max_sdk'] = a.get_max_sdk_version() result['min_sdk'] = a.get_min_sdk_version() #result['libraries'] = a.get_libraries() result['filename'] = a.get_filename() result['target_sdk'] = a.get_target_sdk_version() result['md5'] = hashlib.md5(a.get_raw()).hexdigest() result['sha256'] = hashlib.sha256(a.get_raw()).hexdigest() result['permissions'] = a.get_permissions() result['activities'] = a.get_activities() result['providers'] = a.get_providers() result['services'] = a.get_services() result['strings'] = d.get_strings() result['class_names'] = [c.get_name() for c in d.get_classes()] result['method_names'] = [m.get_name() for m in d.get_methods()] result['field_names'] = [f.get_name() for f in d.get_fields()] #result['is_native_code'] = 1 if analysis.is_native_code(dx) else 0 result['is_obfuscation'] = 1 if analysis.is_ascii_obfuscation(d) else 0 #result['is_crypto_code'] = 1 if analysis.is_crypto_code(dx) else 0 '''result['is_dyn_code'] = 1 if analysis.is_dyn_code(dx) else 0 result['is_reflection_code'] = 1 if analysis.is_reflection_code(vmx) else 0''' result['is_database'] = 1 if d.get_regex_strings(DB_REGEX) else 0 arr = [] s = a.get_elements("action", "name") for i in s: arr.append(i) result['intents'] = arr s_list = [] s_list.extend(result['class_names']) s_list.extend(result['method_names']) s_list.extend(result['field_names']) result['entropy_rate'] = entropy_rate(s_list) result['feature_vectors'] = {} # Search for the presence of api calls in a given apk result['feature_vectors']['api_calls'] = [] for call in API_CALLS: status = 1 if dx.get_method(call) else 0 result['feature_vectors']['api_calls'].append(status) # Search for the presence of permissions in a given apk result['feature_vectors']['permissions'] = [] for permission in PERMISSIONS: status = 1 if permission in result['permissions'] else 0 result['feature_vectors']['permissions'].append(status) #Search for the presence of intents in a given apk result['feature_vectors']['intents'] = [] n = len(INTENTS) m = len(result['intents']) for i in range(n): stri = INTENTS[i] flg = False for j in range(m): if stri in result['intents'][j]: flg = True break if flg: status = 1 else: status = 0 result['feature_vectors']['intents'].append(status) #Check for special strings in code result['feature_vectors']['special_strings'] = [] for word in SPECIAL_STRINGS: status = 1 if d.get_regex_strings(word) else 0 result['feature_vectors']['special_strings'].append(status) return result
def get_permissions(path): application = APK(path) permissions = application.get_permissions() permissions = list(set(permissions)) return permissions
def __init__(self, apk, pos): self.data = [] self.don = [] self.apk = APK(str(apk)) self.pos = pos self.main()
def testApksignAPKs(self): # These APKs are from the apksign testcases and cover # all different signature algorithms as well as some error cases from androguard.core.bytecodes.apk import APK import zipfile from asn1crypto import x509, pem import binascii root = "examples/signing/apksig" # Correct values generated with openssl: # In the apksig repo:src/test/resources/com/android/apksig # for f in *.pem; do openssl x509 -in $f -noout -sha256 -fingerprint; done certfp = { 'dsa-1024.x509.pem': 'fee7c19ff9bfb4197b3727b9fd92d95406b1bd96db99ea642f5faac019a389d7', 'dsa-2048.x509.pem': '97cce0bab292c2d5afb9de90e1810b41a5d25c006a10d10982896aa12ab35a9e', 'dsa-3072.x509.pem': '966a4537058d24098ea213f12d4b24e37ff5a1d8f68deb8a753374881f23e474', 'ec-p256.x509.pem': '6a8b96e278e58f62cfe3584022cec1d0527fcb85a9e5d2e1694eb0405be5b599', 'ec-p384.x509.pem': '5e7777ada7ee7ce8f9c4d1b07094876e5604617b7988b4c5d5b764a23431afbe', 'ec-p521.x509.pem': '69b50381d98bebcd27df6d7df8af8c8b38d0e51e9168a95ab992d1a9da6082da', 'rsa-1024_2.x509.pem': 'eba3685e799f59804684abebf0363e14ccb1c213e2b954a22669714ed97f61e9', 'rsa-1024.x509.pem': 'bc5e64eab1c4b5137c0fbc5ed05850b3a148d1c41775cffa4d96eea90bdd0eb8', 'rsa-16384.x509.pem': 'f3c6b37909f6df310652fbd7c55ec27d3079dcf695dc6e75e22ba7c4e1c95601', 'rsa-2048_2.x509.pem': '681b0e56a796350c08647352a4db800cc44b2adc8f4c72fa350bd05d4d50264d', 'rsa-2048_3.x509.pem': 'bb77a72efc60e66501ab75953af735874f82cfe52a70d035186a01b3482180f3', 'rsa-2048.x509.pem': 'fb5dbd3c669af9fc236c6991e6387b7f11ff0590997f22d0f5c74ff40e04fca8', 'rsa-3072.x509.pem': '483934461229a780010bc07cd6eeb0b67025fc4fe255757abbf5c3f2ed249e89', 'rsa-4096.x509.pem': '6a46158f87753395a807edcc7640ac99c9125f6b6e025bdbf461ff281e64e685', 'rsa-8192.x509.pem': '060d0a24fea9b60d857225873f78838e081795f7ef2d1ea401262bbd75a58234', } will_not_validate_correctly = [ "targetSandboxVersion-2.apk", "targetSandboxVersion-2.apk", "v1-only-with-cr-in-entry-name.apk", "v1-only-with-lf-in-entry-name.apk", "v1-only-with-nul-in-entry-name.apk", "v1-only-with-rsa-1024-cert-not-der2.apk", "v2-only-cert-and-public-key-mismatch.apk", "v2-only-with-dsa-sha256-1024-sig-does-not-verify.apk", "debuggable-boolean.apk", "debuggable-resource.apk", ] # Collect possible hashes for certificates # Unfortunately, not all certificates are supplied... for apath in os.listdir(root): if apath in certfp: with open(os.path.join(root, apath), "rb") as fp: cert = x509.Certificate.load(pem.unarmor(fp.read())[2]) h = cert.sha256_fingerprint.replace(" ","").lower() self.assertEqual(h, certfp[apath]) self.assertIn(h, certfp.values()) for apath in os.listdir(root): if apath.endswith(".apk"): if apath == "v2-only-garbage-between-cd-and-eocd.apk" or \ apath == "v2-only-truncated-cd.apk" or \ apath == "v1v2v3-with-rsa-2048-lineage-3-signers-invalid-zip.apk": # Can not load as APK with self.assertRaises(zipfile.BadZipFile): APK(os.path.join(root, apath)) continue elif apath in will_not_validate_correctly: # These APKs are faulty (by design) and will return a not correct fingerprint. # TODO: we need to check if we can prevent such errors... continue a = APK(os.path.join(root, apath)) self.assertIsInstance(a, APK) # Test if the correct method returns True, while others return # False m_tests = {'1': a.is_signed_v1, '2': a.is_signed_v2, '3': a.is_signed_v3} # These APKs will raise an error excluded = [ "v1v2v3-with-rsa-2048-lineage-3-signers-no-sig-block.apk", "v2-only-apk-sig-block-size-mismatch.apk", "v2-only-empty.apk", "v2-only-wrong-apk-sig-block-magic.apk", "v2-stripped.apk", "v2-stripped-with-ignorable-signing-schemes.apk", "v2v3-signed-v3-block-stripped.apk", "v3-only-empty.apk", "v3-only-with-ecdsa-sha512-p384-wrong-apk-sig-block-magic.apk", "v3-only-with-rsa-pkcs1-sha512-4096-apk-sig-block-size-mismatch.apk", "v3-stripped.apk", ] if apath[0] == "v" and apath not in excluded: methods = apath.split("-", 1)[0].split("v")[1:] for m, f in m_tests.items(): if m in methods: self.assertTrue(f()) else: self.assertFalse(f()) # Special error cases if apath == "v2-only-apk-sig-block-size-mismatch.apk": with self.assertRaises(apk.BrokenAPKError): a.is_signed_v2() continue elif apath == "v2-only-empty.apk": with self.assertRaises(apk.BrokenAPKError): a.is_signed_v2() continue elif apath == "v3-only-with-rsa-pkcs1-sha512-4096-apk-sig-block-size-mismatch.apk": with self.assertRaises(apk.BrokenAPKError): a.is_signed_v3() continue if a.is_signed_v1(): if apath == "weird-compression-method.apk": with self.assertRaises(NotImplementedError): for c in a.get_signature_names(): a.get_certificate(c) elif apath == "v1-only-with-rsa-1024-cert-not-der.apk": for sig in a.get_signature_names(): c = a.get_certificate(sig) h = c.sha256_fingerprint.replace(" ","").lower() self.assertNotIn(h, certfp.values()) # print([apath, h]) # I do not know, why put this file? der = a.get_certificate_der(sig) apk.show_Certificate(c, True) apk.show_Certificate(c, False) self.assertEqual(hashlib.sha256(der).hexdigest(), h) pass else: for sig in a.get_signature_names(): c = a.get_certificate(sig) h = c.sha256_fingerprint.replace(" ","").lower() self.assertIn(h, certfp.values()) # Check that we get the same signature if we take the DER der = a.get_certificate_der(sig) self.assertEqual(hashlib.sha256(der).hexdigest(), h) if a.is_signed_v2(): if apath == "weird-compression-method.apk": with self.assertRaises(NotImplementedError): a.get_certificates_der_v2() elif apath == "v2-only-with-rsa-pkcs1-sha256-1024-cert-not-der.apk": # FIXME # Not sure what this one should do... but the certificate fingerprint is weird # as the hash over the DER is not the same when using the certificate continue else: for c in a.get_certificates_der_v2(): cert = x509.Certificate.load(c) h = cert.sha256_fingerprint.replace(" ","").lower() self.assertIn(h, certfp.values()) # Check that we get the same signature if we take the DER self.assertEqual(hashlib.sha256(c).hexdigest(), h) if a.is_signed_v3(): print(apath) if apath == "weird-compression-method.apk": with self.assertRaises(NotImplementedError): a.get_certificates_der_v3() elif apath == "v3-only-with-rsa-pkcs1-sha256-3072-sig-does-not-verify.apk" or \ apath == "v3-only-cert-and-public-key-mismatch.apk": cert = x509.Certificate.load(a.get_certificates_der_v3()[0]) h = cert.sha256_fingerprint.replace(" ","").lower() self.assertNotIn(h, certfp.values()) else: for c in a.get_certificates_der_v3(): cert = x509.Certificate.load(c) h = cert.sha256_fingerprint.replace(" ","").lower() self.assertIn(h, certfp.values()) # Check that we get the same signature if we take the DER self.assertEqual(hashlib.sha256(c).hexdigest(), h)
def getFeatures(source_directory): ############################################################ # Label tong hop with open(LabelsNum_file, "r+") as file_LabeslNum: LABELSNUMANDTEXT = json.load(file_LabeslNum) # doc file config with open(config_file, "r+") as f: dataConfig = json.load(f) maxLabelsNum = dataConfig['maxLabelsNum'] #lay part Data partData = dataConfig['partData'] time = datetime.datetime.now() partDataFile = str(partData) + '_' + str(time).strip() + '.csv' csvFile = open(r'DataCSV/' + partDataFile, 'w+', newline='') writer = csv.writer(csvFile, delimiter=',') source_directory = str(source_directory) #if not os.path.exists(output_folder): # os.makedirs(output_folder) # Load Android API packages and classes global API_PACKAGES_LIST, API_CLASSES_LIST, API_SYSTEM_COMMANDS ############################################################ # get name and labels ARRNAME, ARRLABELS = load_NameandLabels(labels) ############################################################ # READING PACKAGES, CLASSES AND SYSTEM COMMANDS ############################################################ package_file = load_file(str(package_index_file)) API_PACKAGES_LIST = [x.strip() for x in package_file] class_file = load_file(str(classes_index_file)) API_CLASSES_LIST = [x.strip() for x in class_file] commands_file = load_file(str(system_commands_file)) API_SYSTEM_COMMANDS = [x.strip() for x in commands_file] ############################################################ ############################################################ apk_list = list_files(source_directory, '*.apk') for analyze_apk in tqdm(apk_list): # Getting the name of the folder that contains all apks and folders with apks base_folder = source_directory.split("/")[-1] apk_filename = join_dir(base_folder, analyze_apk.replace(source_directory, '')) apk_filename = apk_filename.replace("//", "/") apk_name_no_extensions = "".join( apk_filename.split("/")[-1].split(".")[:-1]) # export to monggoDB #if os.path.isfile(join_dir(output_folder, apk_filename.split("/")[-1].replace('.apk', '-analysis.json'))): # database[apk_filename.replace('.apk', '')] = json.load( # open(join_dir(output_folder, apk_filename.split("/")[-1]. # replace('.apk', '-analysis.json')))) # continue pre_static_dict = collections.OrderedDict() pre_static_dict['Filename'] = apk_filename hasher_md5 = hashlib.md5() hasher_sha256 = hashlib.sha256() hasher_sha1 = hashlib.sha1() with open(analyze_apk, 'rb') as afile: buf = afile.read() hasher_md5.update(buf) hasher_sha256.update(buf) hasher_sha1.update(buf) md5 = hasher_md5.hexdigest() sha256 = hasher_sha256.hexdigest() sha1 = hasher_sha1.hexdigest() pre_static_dict["md5"] = md5 pre_static_dict["sha256"] = sha256 pre_static_dict["sha1"] = sha1 """ if label is not None: pre_static_dict["Label"] = label else: pre_static_dict["Label"] = "/".join(apk_filename.split("/")[:-1]) """ pre_static_dict["VT_positives"] = None try: androguard_apk_object = APK(analyze_apk) except Exception: print("ERROR in APK: " + apk_name_no_extensions) continue static_analysis_dict = collections.OrderedDict() # Package name static_analysis_dict[ 'Package name'] = androguard_apk_object.get_package() # Permissions static_analysis_dict[ 'Permissions'] = androguard_apk_object.get_permissions() # Activities try: list_activities = androguard_apk_object.get_activities() except UnicodeEncodeError: list_activities = [] # Main activity static_analysis_dict[ 'Main activity'] = androguard_apk_object.get_main_activity() # Receivers try: list_receivers = androguard_apk_object.get_receivers() except UnicodeEncodeError: list_receivers = [] # Services try: list_services = androguard_apk_object.get_services() except UnicodeEncodeError: list_services = [] # API calls and Strings list_smali_api_calls, list_smali_strings = read_strings_and_apicalls( analyze_apk, API_PACKAGES_LIST, API_CLASSES_LIST) for api_call in list_smali_api_calls.keys(): new_api_call = '.'.join(api_call.split(".")[:-1]) if new_api_call in list_smali_api_calls.keys(): list_smali_api_calls[new_api_call] = list_smali_api_calls[ new_api_call] + list_smali_api_calls[api_call] else: list_smali_api_calls[new_api_call] = list_smali_api_calls[ api_call] del list_smali_api_calls[api_call] static_analysis_dict['API calls'] = list_smali_api_calls static_analysis_dict['Strings'] = Counter( filter(None, list_smali_strings)) # API packages API_packages_dict = collections.OrderedDict() android_list_packages_lenghts = [ len(x.split(".")) for x in API_PACKAGES_LIST ] list_api_calls_keys = list_smali_api_calls.keys() for api_call in list_api_calls_keys: score = 0 package_chosen = None for i, package in enumerate(API_PACKAGES_LIST): len_package = android_list_packages_lenghts[i] if api_call.startswith(package) and len_package > score: score = len_package package_chosen = package if package_chosen is not None: if not package_chosen in API_packages_dict.keys(): API_packages_dict[package_chosen] = list_smali_api_calls[ api_call] else: API_packages_dict[package_chosen] += list_smali_api_calls[ api_call] static_analysis_dict['API packages'] = API_packages_dict # Intents try: static_analysis_dict['Intents'] = intents_analysis( join_dir(analyze_apk.replace('.apk', ''), 'AndroidManifest.xml')) except: static_analysis_dict['Intents'] = {'Failed to extract intents': 0} # Intents of activities intents_activities = collections.OrderedDict() for activity in list_activities: intents_activities[activity] = check_for_intents( join_dir(analyze_apk.replace('.apk', ''), 'AndroidManifest.xml'), activity, 'activity') static_analysis_dict['Activities'] = intents_activities # Intents of services intents_services = collections.OrderedDict() for service in list_services: intents_services[service] = check_for_intents( join_dir(analyze_apk.replace('.apk', ''), 'AndroidManifest.xml'), service, 'service') static_analysis_dict['Services'] = intents_services # Intents of receivers intents_receivers = collections.OrderedDict() for intent in list_receivers: intents_receivers[intent] = check_for_intents( join_dir(analyze_apk.replace('.apk', '/'), 'AndroidManifest.xml'), intent, 'receiver') static_analysis_dict['Receivers'] = intents_receivers row = standardData(pre_static_dict, static_analysis_dict) if md5 in ARRNAME: index = -1 if md5 in ARRNAME: index = ARRNAME.index(md5) if sha256 in ARRNAME: index = ARRNAME.index(sha256) if index != -1: label = ARRLABELS[index] try: if label not in LABELSNUMANDTEXT: if 'SINGLETON' in label: continue continue # maxLabelsNum += 1 # temp = collections.OrderedDict() # temp[label] = maxLabelsNum # LABELSNUMANDTEXT[label] = maxLabelsNum except: continue labelNum = [LABELSNUMANDTEXT[label]] labelNum.extend(row) writer.writerow(labelNum) # apk_total_analysis = collections.OrderedDict([("Pre_static_analysis", pre_static_dict), # ("Static_analysis", static_analysis_dict)]) # # save_as_json(apk_total_analysis, output_name=join_dir(output_folder, apk_name_no_extensions + # "-analysis.json")) #save labelsnum neu co them nhan moo with open(str(LabelsNum_file), 'w+') as fp: json.dump(LABELSNUMANDTEXT, fp, indent=4) fp.close() # Save data config partData += 1 dataConfig['partData'] = partData dataConfig['maxLabelsNum'] = maxLabelsNum with open(str(config_file), 'w+') as fp: json.dump(dataConfig, fp, indent=4) fp.close() csvFile.close()