def run(self): Log.info("Preparing to re-compile the application") # get identifier manifest_module = ManifestModule() manifest_module.decompiled_apk = self.decompiled_apk self.manifest = manifest_module.run() if "print" not in self.manifest: identifier = self.manifest.popitem()[1].package() recompiled_apk = "{}/{}-recompiled.apk".format(self.output, identifier) # unzip Log.info("Re-compiling application") output = recompile(self.decompiled_apk, recompiled_apk) if "Exception" in output: return { "print": "Failed to re-compile the application:\n{}".format(output) } return { "{}_recompiled".format(identifier): recompiled_apk, "print": "Application re-compiled to {}".format(recompiled_apk) }
def run(self): result = { "title": "Application Has Secret Codes", "details": "", "severity": "Low", "report": False } # create manifest manifest_module = ManifestModule() manifest_module.decompiled_apk = self.decompiled_apk self.manifest = manifest_module.run() if "print" in self.manifest: return {"print": "Could not get the manifest"} self.manifest = self.manifest.popitem()[1] Log.info("Analysing application's manifest for secret codes") secret_codes = self.manifest.secret_codes() if secret_codes: details = "* Secret Codes:\n * {}".format( "\n * ".join(secret_codes)) details += """ * Test the secret codes using the following command: adb shell su -c "am broadcast -a {} -d android_secret_code://CODE" """.format(self._secret_code_activity) result.update({"report": True, "details": details}) return { "{}_result".format(self.name()): result, "{}_secret_codes".format(self.manifest.package()): secret_codes }
def run(self): Log.info("Creating decompilation directory") # create decompiled directory identifier = self.apk.rsplit("/", 1)[-1].lower().rsplit(".", 1)[0] output_path = "{}/{}.decompiled".format(self.output, identifier) execute("mkdir -p {}".format(output_path)) # unzip Log.info("Decompiling application") decompile(self.apk, output_path) # get identifier manifest_module = ManifestModule() manifest_module.decompiled_apk = output_path self.manifest = manifest_module.run() if "print" not in self.manifest: identifier = self.manifest.popitem()[1].package() # move decompiled app to new path old_output_path = output_path output_path = "{}/{}.decompiled".format(self.output, identifier) execute("mv {} {}".format(old_output_path, output_path)) return { "{}_decompiled".format(identifier): output_path, "print": "Application decompiled to {}".format(output_path) }
def run(self): result = { "title": "Application Allows Backups", "details": "", "severity": "Low", "report": False } # create manifest manifest_module = ManifestModule() manifest_module.decompiled_apk = self.decompiled_apk manifest = manifest_module.run() if "print" in manifest: return {"print": "Could not get the manifest"} manifest = manifest.popitem()[1] Log.info("Analysing application's manifest") if manifest.allow_backup(): result.update({"report": True}) return { "{}_result".format(self.name()): result }
def run(self): result = { "title": "Application Has Browsable Activities", "details": "", "severity": "Informational", "report": False } # create manifest manifest_module = ManifestModule() manifest_module.decompiled_apk = self.decompiled_apk self.manifest = manifest_module.run() if "print" in self.manifest: return {"print": "Could not get the manifest"} self.manifest = self.manifest.popitem()[1] Log.info("Getting browsable activities and uris") browsable_classes = self.manifest.browsable_activities() browsable_uris = self.manifest.browsable_uris() if browsable_classes or browsable_uris: details = "* URIs:\n * {}".format("\n * ".join(browsable_uris)) details += "\n\n* Classes:\n * {}".format( "\n * ".join(browsable_classes)) result.update({"report": True, "details": details}) return { "{}_result".format(self.name()): result, "{}_browsable_classes".format(self.manifest.package()): browsable_classes, "{}_browsable_uris".format(self.manifest.package()): browsable_uris }
def run(self): result = { "title": "Application Has Inadequate Permissions", "details": "", "severity": "Medium", "report": False } # create manifest manifest_module = ManifestModule() manifest_module.decompiled_apk = self.decompiled_apk self.manifest = manifest_module.run() if "print" in self.manifest: return {"print": "Could not get the manifest"} self.manifest = self.manifest.popitem()[1] Log.info("Analysing application's manifest permissions") # setup vars permissions = [ permission.strip() for permission in self.permissions.split(";") ] app_permissions = self.manifest.permissions() inadequate_permissions = [] for permission in app_permissions: if permission in self.permissions: inadequate_permissions.append(permission) if inadequate_permissions: result.update({ "report": True, "details": "* {}".format("\n* ".join(inadequate_permissions)) }) return { "{}_result".format(self.name()): result, "{}_permissions".format(self.manifest.package()): app_permissions } return {"{}_result".format(self.name()): result}
def run(self): Log.info("Checking for apktool.yml file") # find apktool yml file filename = "{}/apktool.yml".format(self.decompiled_apk) if exists(filename): Log.info("Creating apktool yaml object") # get info yaml = ApktoolYaml(filename) # get identifier identifier = yaml.apk_filename().lower().rsplit(".", 1)[0] manifest_module = ManifestModule() manifest_module.decompiled_apk = self.decompiled_apk self.manifest = manifest_module.run() if "print" not in self.manifest: identifier = self.manifest.popitem()[1].package() return {"{}_yaml".format(identifier): yaml} return {"print": "Could not find apktool.yml"}
def run(self): Log.info("Checking output folders") if not self.output: self.output = "/tmp/scrounger-tmp" # create the required dirs execute("mkdir -p {}".format(self.output)) # get identifier manifest_module = ManifestModule() manifest_module.decompiled_apk = self.decompiled_apk manifest = manifest_module.run() if "print" not in manifest: manifest = manifest.popitem()[1] identifier = manifest.package() # set filenames debuggable_apk = "{}/{}-debuggable.apk".format(self.output, identifier) # read manifest content Log.info("Modifying AndroidManifest.xml") with open(manifest.file_path(), "r") as fd: manifest_content = fd.read() # look for <application> and modify debuggable new_manifest_content = "" for line in manifest_content.split("\n"): if "<application" in line: if "debuggable" in line: line = line.replace("android:debuggable=\"false\"", "android:debuggable=\"true\"") else: line_split = line.split(">", 1) line = "{} android:debuggable=\"true\">{}".format( line_split[0], line_split[1]) new_manifest_content = "{}\n{}".format(new_manifest_content, line) new_manifest_content = "\n".join(new_manifest_content.split("\n")[1:]) # overwrite the manifest with the new content with open(manifest.file_path(), "w") as fd: fd.write(new_manifest_content) # recompiled the application Log.info("Re-compiling application") output = recompile(self.decompiled_apk, debuggable_apk) if "Exception" in output: return { "print": "Failed to re-compile the application:\n{}".format(output) } # signing the application sign_module, signed_apk = SignApkModule(), None sign_module.recompiled_apk = debuggable_apk sign_module.output = self.output sign_result = sign_module.run() for key in sign_result: if key.endswith("_signed"): signed_apk = sign_result[key] if signed_apk: execute("mv {} {}".format(signed_apk, debuggable_apk)) # install the application if self.install: Log.info("Uninstalling previously installed application") self.device.uninstall(identifier) Log.info("Installing new debuggable application") self.device.install(debuggable_apk) return { "{}_debuggable".format(identifier): debuggable_apk, "print": "Application re-compiled and signed to {}".format(debuggable_apk) }
def run(self): result = { "title": "Application Does Not Use Obfuscation", "details": "", "severity": "Medium", "report": False } exceptions = [] # preparing variable to run ignore = [filepath.strip() for filepath in self.ignore.split(";")] # get identifier Log.info("Checking identifier package only") if self.check_package_only: manifest_module = ManifestModule() manifest_module.decompiled_apk = self.decompiled_apk self.manifest = manifest_module.run() if "print" not in self.manifest: identifier = self.manifest.popitem()[1].package() else: identifier = None exceptions += [Exception(self.manifest["print"])] Log.info("Identifying class names") class_names_list = class_names(self.decompiled_apk, ignore, identifier) Log.info("Identifying method names") method_names_list = method_names(self.decompiled_apk, ignore, identifier) Log.info("Identifying strings") strings_list = app_strings(self.decompiled_apk, ignore, identifier) Log.info("Identifying resources") resources_list = app_used_resources(self.decompiled_apk, ignore, identifier) Log.info("Analysing identified strings") # start by analysing class names class_detect_lang = detect_langs(" ".join(class_names_list))[0] class_small_names = [ class_name for class_name in class_names_list if len(class_name) < 4 ] # check if lang != expected or probability lower than required for class # names if class_detect_lang.lang != self.language or \ class_detect_lang.prob*100 < self.min_percentage: result.update({ "title": "Application shows evidence of obfuscation", "details": "Detected language {} with probability {}% on \ class names.".format(class_detect_lang.lang, class_detect_lang.prob * 100), "report": True }) # check small_classes/total_classes >= min_percent_class_names sclass_percent = len(class_small_names) * 1.0 / len( class_names_list) * 100 if sclass_percent >= self.min_percentage_small_names: result.update({ "title": "Application shows evidence of obfuscation", "details": "{}\n\nDetected small class names: {}%".format( result["details"], sclass_percent), "report": True }) Log.debug("Classes detected {} with probability of {}%".format( class_detect_lang.lang, class_detect_lang.prob * 100)) Log.debug("Small len classes {}/{} = {}%".format( len(class_small_names), len(class_names_list), sclass_percent)) Log.debug("Unique small len classes {}/{} = {}%".format( len(set(class_small_names)), len(set(class_names_list)), len(set(class_small_names)) * 1.0 / len(set(class_names_list)) * 100)) # analyse method names method_detect_lang = detect_langs(" ".join(method_names_list))[0] method_small_names = [ method_name for method_name in method_names_list if len(method_name) < 4 ] # check if lang != expected or probability lower than required for # method names if method_detect_lang.lang != self.language or \ method_detect_lang.prob*100 < self.min_percentage: result.update({ "title": "Application shows evidence of obfuscation", "details": "{}\n\nDetected language {} with probability {}% on \ method names.".format(result["details"], method_detect_lang.lang, method_detect_lang.prob * 100), "report": True }) # check small_methods/total_methods >= min_percent_mathod_names smthod_percent = len(method_small_names) * 1.0 / len( method_names_list) * 100 if smthod_percent >= self.min_percentage_small_names: result.update({ "title": "Application shows evidence of obfuscation", "details": "{}\n\nDetected small method names: {}%".format( result["details"], smthod_percent), "report": True }) Log.debug("Methods detected {} with probability of {}%".format( method_detect_lang.lang, method_detect_lang.prob * 100)) Log.debug("Small len methods {}/{} = {}%".format( len(method_small_names), len(method_names_list), smthod_percent)) Log.debug("Unique small len classes {}/{} = {}%".format( len(set(method_small_names)), len(set(method_names_list)), len(set(method_small_names)) * 1.0 / len(set(method_names_list)) * 100)) # analyse strings and resources strings_detect_lang = detect_langs(" ".join(strings_list + resources_list))[0] # check if lang != expected or probability lower than required for # strings and resources if strings_detect_lang.lang != self.language or \ strings_detect_lang.prob*100 < self.min_percentage: result.update({ "title": "Application shows evidence of obfuscation", "details": "{}\n\nDetected language {} with probability {}% on \ strings and resources.".format(result["details"], strings_detect_lang.lang, strings_detect_lang.prob * 100), "report": True }) Log.debug("Strings detected {} with probability of {}%".format( strings_detect_lang.lang, strings_detect_lang.prob * 100)) if not result["report"]: result.update({ "details": "No evidence of obfuscation found.", "report": True }) return { "{}_result".format(self.name()): result, "exceptions": exceptions }