def testcode(self): skipped_methods = [] fname = "examples/android/TestsAndroguard/bin/classes.dex" parsed = parse_dex.read_dex(fname) with open(fname, "rb") as f: d = DalvikVMFormat(f.read()) dif = Differ() for m in d.get_methods(): if not m.get_code(): continue if m.get_method_idx() in skipped_methods: continue code = hexlify(m.get_code().get_raw()) self.assertEqual(parsed[m.get_method_idx()], code, "incorrect code for " "[{}]: {} --> {}:\n" "{}\ntries_size: {}, insns_size: {}\nSHOULD BE {}\n{}\n{}".format(m.get_method_idx(), m.get_class_name(), m.get_name(), "".join(dif.compare(parsed[m.get_method_idx()], code)), m.get_code().tries_size, m.get_code().insns_size, hexlify(m.get_code().get_raw()), parsed[m.get_method_idx()], hexlify(m.get_code().code.get_raw())))
def testClassManager(self): """Test if the classmanager has the same items""" from androguard.core.bytecodes.mutf8 import decode, patch_string fname = "examples/android/TestsAndroguard/bin/classes.dex" parsed = parse_dex.read_dex(fname) with open(fname, "rb") as f: d = DalvikVMFormat(f.read()) cm = d.get_class_manager() self.assertFalse(cm.get_odex_format()) ERR_STR = 'AG:IS: invalid string' ## Testing Strings... for idx in range(parsed.string_ids_size): self.assertNotEqual(cm.get_string(idx), ERR_STR) self.assertNotEqual(cm.get_raw_string(idx), ERR_STR) self.assertEqual(cm.get_raw_string(idx), patch_string(decode(parsed.str_raw[idx]))) self.assertEqual(cm.get_string(parsed.string_ids_size), ERR_STR) self.assertEqual(cm.get_raw_string(parsed.string_ids_size), ERR_STR) self.assertEqual(cm.get_string(parsed.string_ids_size + 100), ERR_STR) self.assertEqual(cm.get_raw_string(parsed.string_ids_size + 100), ERR_STR)
class GetFieldType: predictions = {} def __init__(self, args): self.apk = args.apk self.verbosity = args.verbosity self.output_location = args.output_location self.file_identifier = args.apk.split('.')[0] self.file_identifier = self.file_identifier[-24:] # print "Analyzing " + self.apk # print " Output Location " + self.output_location # print "File Identifier " + self.file_identifier # analyze the dex file print "From LOCATION = ",self.apk self.a = APK(self.apk) # get the vm analysis self.d = DalvikVMFormat(self.a.get_dex()) self.dx = VMAnalysis(self.d) self.gx = GVMAnalysis(self.dx, None) self.d.set_vmanalysis(self.dx) self.d.set_gvmanalysis(self.gx) # create the cross reference self.d.create_xref() self.d.create_dref() print 'CWD: ', os.getcwd() predictor = Predict_Input(self.output_location,self.file_identifier) self.predictions = predictor.predict(self.apk, self.apk[:-4],self.output_location,self.file_identifier) try: # get the classes for this apk # store them in a dict self.classes = self.get_class_dict() # Find the R$layout class self.Rlayout = self.get_RLayout(self.d.get_classes()) # Find the R$id class self.Rid = self.get_Rid(self.d.get_classes()) # Store all fields referenced in R$id self.fields, self.field_refs = self.get_fields(self.Rid) except Exception, e: print e
def __analyze_dex(self, dex_file, raw=False) : # DalvikVMFormat dalvik_vm_format = None if raw == False : dalvik_vm_format = DalvikVMFormat( open(dex_file, "rb").read() ) else : dalvik_vm_format = DalvikVMFormat( dex_file ) # VMAnalysis vm_analysis = VMAnalysis( dalvik_vm_format ) dalvik_vm_format.set_vmanalysis( vm_analysis ) return vm_analysis
def AnalyzeAPK(_file, session=None, raw=False): """ Analyze an android application and setup all stuff for a more quickly analysis! If session is None, no session is used at all. This is the default behaviour. If you like to continue your work later, it might be a good idea to use a session. A default session can be created by using :meth:`~get_default_session`. :param _file: the filename of the android application or a buffer which represents the application :type _file: string (for filename) or bytes (for raw) :param session: A session (default: None) :param raw: boolean if raw bytes are supplied instead of a filename :rtype: return the :class:`~androguard.core.bytecodes.apk.APK`, list of :class:`~androguard.core.bytecodes.dvm.DalvikVMFormat`, and :class:`~androguard.core.analysis.analysis.Analysis` objects """ log.debug("AnalyzeAPK") if session: log.debug("Using existing session {}".format(session)) if raw: data = _file filename = hashlib.md5(_file).hexdigest() else: with open(_file, "rb") as fd: data = fd.read() filename = _file digest = session.add(filename, data) return session.get_objects_apk(filename, digest) else: log.debug("Analysing without session") a = APK(_file, raw=raw) # FIXME: probably it is not necessary to keep all DalvikVMFormats, as # they are already part of Analysis. But when using sessions, it works # this way... d = [] dx = Analysis() for dex in a.get_all_dex(): df = DalvikVMFormat(dex, using_api=a.get_target_sdk_version()) dx.add(df) d.append(df) df.set_decompiler(decompiler.DecompilerDAD(d, dx)) dx.create_xref() return a, d, dx
class GetFieldType: def __init__(self, args): self.apk = args.apk self.verbosity = args.verbosity print "Analyzing " + self.apk # analyze the dex file self.a = APK(self.apk) # get the vm analysis self.d = DalvikVMFormat(self.a.get_dex()) self.dx = VMAnalysis(self.d) self.gx = GVMAnalysis(self.dx, None) self.d.set_vmanalysis(self.dx) self.d.set_gvmanalysis(self.gx) # create the cross reference self.d.create_xref() self.d.create_dref() try: # get the classes for this apk # store them in a dict self.classes = self.get_class_dict() # Find the R$layout class self.Rlayout = self.get_RLayout(self.d.get_classes()) # Find the R$id class self.Rid = self.get_Rid(self.d.get_classes()) # Store all fields referenced in R$id self.fields, self.field_refs = self.get_fields(self.Rid) except Exception, e: print e
def analyze_dex(filename, raw=False, decompiler=None): """ Analyze an android dex file and setup all stuff for a more quickly analysis ! :param filename: the filename of the android dex file or a buffer which represents the dex file :type filename: string :param raw: True is you would like to use a buffer (optional) :type raw: boolean :param decompiler: the type of decompiler to use ("dad", "dex2jad", "ded") :type decompiler: string :rtype: return the :class:`DalvikVMFormat`, and :class:`VMAnalysis` objects """ d = None if raw: d = DalvikVMFormat(filename) else: d = DalvikVMFormat(open(filename, "rb").read()) dx = analysis.Analysis(d) d.set_vmanalysis(dx) run_decompiler(d, dx, decompiler) dx.create_xref() return d, dx
def __init__(self, args): self.apk = args.apk self.verbosity = args.verbosity print "Analyzing " + self.apk # analyze the dex file self.a = APK(self.apk) # get the vm analysis self.d = DalvikVMFormat(self.a.get_dex()) self.dx = VMAnalysis(self.d) self.gx = GVMAnalysis(self.dx, None) self.d.set_vmanalysis(self.dx) self.d.set_gvmanalysis(self.gx) # create the cross reference self.d.create_xref() self.d.create_dref() try: # get the classes for this apk # store them in a dict self.classes = self.get_class_dict() # Find the R$layout class self.Rlayout = self.get_RLayout(self.d.get_classes()) # Find the R$id class self.Rid = self.get_Rid(self.d.get_classes()) # Store all fields referenced in R$id self.fields, self.field_refs = self.get_fields(self.Rid) except Exception, e: print e
def on_complete(self): receivers = self.get_results("apkinfo", {}).get("manifest", {}).get("receivers", {}) activities = self.get_results("apkinfo", {}).get("manifest", {}).get("activities", {}) services = self.get_results("apkinfo", {}).get("manifest", {}).get("services", {}) app_path = self.get_results("target", {}).get("file", {}).get("path", None) if not app_path: return False if not os.path.exists(app_path): return False app_apk = APK(app_path) dvm = DalvikVMFormat(app_apk.get_dex()) classes = set() for cls in dvm.get_classes(): classes.add(cls.name) for receiver in receivers: if self.convert_class(receiver) not in classes: return True for activity in activities: if self.convert_class(activity) not in classes: return True for service in services: if self.convert_class(service) not in classes: return True
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.uAnalysis(vm) d.set_Analysis(dx) d.set_decompiler(DecompilerDAD(d, dx)) except: return None return a.get_permissions() #it will return permission
def __analyze_dex(self, dex_file, raw=False): # DalvikVMFormat dalvik_vm_format = None if raw == False: dalvik_vm_format = DalvikVMFormat(open(dex_file, "rb").read()) else: dalvik_vm_format = DalvikVMFormat(dex_file) # VMAnalysis vm_analysis = VMAnalysis(dalvik_vm_format) dalvik_vm_format.set_vmanalysis(vm_analysis) return vm_analysis
def addDEX(self, filename, data, dx=None, postpone_xref=False): """ Add a DEX file to the Session and run analysis. :param filename: the (file)name of the DEX file :param data: binary data of the dex file :param dx: an existing Analysis Object (optional) :param postpone_xref: True if no xref shall be created, and will be called manually :return: A tuple of SHA256 Hash, DalvikVMFormat Object and Analysis object """ digest = hashlib.sha256(data).hexdigest() log.debug("add DEX:%s" % digest) log.debug("Parsing format ...") d = DalvikVMFormat(data) log.debug("added DEX:%s" % digest) self.analyzed_files[filename].append(digest) self.analyzed_digest[digest] = filename self.analyzed_dex[digest] = d if dx is None: dx = Analysis() dx.add(d) if not postpone_xref: dx.create_xref() # TODO: If multidex: this will called many times per dex, even if already set for d in dx.vms: # TODO: allow different decompiler here! d.set_decompiler(DecompilerDAD(d, dx)) d.set_vmanalysis(dx) self.analyzed_vms[digest] = dx if self.export_ipython: log.debug("Exporting in ipython") d.create_python_export() return digest, d, dx
def addDEX(self, filename, data, dx=None): """ Add a DEX file to the Session and run analysis. :param filename: the (file)name of the DEX file :param data: binary data of the dex file :param dx: an existing Analysis Object (optional) :return: A tuple of SHA256 Hash, DalvikVMFormat Object and Analysis object """ digest = hashlib.sha256(data).hexdigest() log.debug("add DEX:%s" % digest) log.debug("Parsing format ...") d = DalvikVMFormat(data) log.debug("added DEX:%s" % digest) self.analyzed_files[filename].append(digest) self.analyzed_digest[digest] = filename self.analyzed_dex[digest] = d if dx is None: dx = Analysis() dx.add(d) dx.create_xref() # TODO: If multidex: this will called many times per dex, even if already set for d in dx.vms: # TODO: allow different decompiler here! d.set_decompiler(DecompilerDAD(d, dx)) d.set_vmanalysis(dx) self.analyzed_vms[digest] = dx if self.export_ipython: log.debug("Exporting in ipython") d.create_python_export() return digest, d, dx
def init(apk_file): print_k(apk_file) dalvik_ctx = DalvikVMFormat( APK(apk_file) ) methods = dalvik_ctx.get_methods() return methods
def process_vm(self, apk=False, dex=False): """ Process the application's classes.dex Args: param1 = boolean param2 = boolean Results: None """ try: if apk: # Make sure the APK contains a classes.dex file if self.find_dex(): self.dex = self.apk.get_dex() if self.dex: self.logger.log("info", "Loading classes.dex ...") from androguard.core.bytecodes.dvm import DalvikVMFormat from androguard.core.analysis.analysis import VMAnalysis from androguard.core.analysis.ganalysis import GVMAnalysis # Create a DalvikVMFormat instance ... # In this case self.dex will be a file type self.vm = DalvikVMFormat(self.dex) if self.vm: print(self.t.yellow("\n\t--> Loaded classes.dex (!)\n")) self.logger.log("info", "Analyzing classes.dex ...") # Analyze the DalvikVMFormat instance and return # analysis instances of VMAnalysis and GVMAnalysis self.vmx = VMAnalysis(self.vm) self.gmx = GVMAnalysis(self.vmx, None) if self.vmx and self.gmx: print(self.t.yellow("\n\t--> Analyzed classes.dex (!)\n")) # Set the analysis properties on the # DalvikVMFormat instance self.vm.set_vmanalysis(self.vmx) self.vm.set_gvmanalysis(self.gmx) # Generate xref(s) and dref(s) self.vm.create_xref() self.vm.create_dref() return else: CommandError("process_vm : Cannot analyze VM instance (!)") return else: CommandError("process_vm : Cannot load VM instance (!)") return else: CommandError("process_vm : classes.dex not found (!)") return if dex: if self.dex: from androguard.core.bytecodes.dvm import DalvikVMFormat from androguard.core.analysis.analysis import VMAnalysis from androguard.core.analysis.ganalysis import GVMAnalysis # Analyze the DalvikVMFormat instance and return # analysis instances of VMAnalysis and GVMAnalysis self.vm = DalvikVMFormat(self.util.read(self.dex)) if self.vm: print(self.t.yellow("\n\t--> Loaded {} (!)\n" .format(self.dex .split("/")[-1]))) self.logger.log("info", "Analyzing {} ..." .format(self.dex .split("/")[-1])) # Set the analysis properties on the # DalvikVMFormat instance self.vmx = VMAnalysis(self.vm) self.gmx = GVMAnalysis(self.vmx, None) if self.vmx and self.gmx: print(self.t.yellow("\n\t--> Analyzed {} (!)\n" .format(self.dex .split("/")[-1]))) # Set the analysis properties on the # DalvikVMFormat instance self.vm.set_vmanalysis(self.vmx) self.vm.set_gvmanalysis(self.gmx) # Generate xref(s) and dref(s) self.vm.create_xref() self.vm.create_dref() return else: CommandError("process_vm :" + "Cannot analyze VM instance (!)") return else: CommandError("process_vm :" + "Cannot load VM instance (!)") return else: CommandError("process_vm : classes.dex not found (!)") return except Exception as e: CommandError("process_vm : {}".format(e))
class Run(Lobotomy): def __init__(self, ROOT_DIR): Lobotomy.__init__(self) self.ROOT_DIR = ROOT_DIR self.t = Terminal() self.logger = Logger() self.util = Util() self.apk = None self.package = None self.vm = None self.vmx = None self.gmx = None self.components = None self.dex = None self.strings = None self.permissions = None self.permissions_details = None self.files = None self.attack_surface = None def _cmd_completer(self, name, text, line, begidx, endidx): fn = getattr(self, 'do_'+name) if not hasattr(fn.im_func, "_expected_args"): return [] a = [arg for arg in fn.im_func._expected_args if arg.startswith(text)] return a def find_dex(self): """ Return True is classes.dex is found within the target APK. Args: None Returns: None """ if self.files: for f in self.files: if "classes" in f: return True break def process_vm(self, apk=False, dex=False): """ Process the application's classes.dex Args: param1 = boolean param2 = boolean Results: None """ try: if apk: # Make sure the APK contains a classes.dex file if self.find_dex(): self.dex = self.apk.get_dex() if self.dex: self.logger.log("info", "Loading classes.dex ...") from androguard.core.bytecodes.dvm import DalvikVMFormat from androguard.core.analysis.analysis import VMAnalysis from androguard.core.analysis.ganalysis import GVMAnalysis # Create a DalvikVMFormat instance ... # In this case self.dex will be a file type self.vm = DalvikVMFormat(self.dex) if self.vm: print(self.t.yellow("\n\t--> Loaded classes.dex (!)\n")) self.logger.log("info", "Analyzing classes.dex ...") # Analyze the DalvikVMFormat instance and return # analysis instances of VMAnalysis and GVMAnalysis self.vmx = VMAnalysis(self.vm) self.gmx = GVMAnalysis(self.vmx, None) if self.vmx and self.gmx: print(self.t.yellow("\n\t--> Analyzed classes.dex (!)\n")) # Set the analysis properties on the # DalvikVMFormat instance self.vm.set_vmanalysis(self.vmx) self.vm.set_gvmanalysis(self.gmx) # Generate xref(s) and dref(s) self.vm.create_xref() self.vm.create_dref() return else: CommandError("process_vm : Cannot analyze VM instance (!)") return else: CommandError("process_vm : Cannot load VM instance (!)") return else: CommandError("process_vm : classes.dex not found (!)") return if dex: if self.dex: from androguard.core.bytecodes.dvm import DalvikVMFormat from androguard.core.analysis.analysis import VMAnalysis from androguard.core.analysis.ganalysis import GVMAnalysis # Analyze the DalvikVMFormat instance and return # analysis instances of VMAnalysis and GVMAnalysis self.vm = DalvikVMFormat(self.util.read(self.dex)) if self.vm: print(self.t.yellow("\n\t--> Loaded {} (!)\n" .format(self.dex .split("/")[-1]))) self.logger.log("info", "Analyzing {} ..." .format(self.dex .split("/")[-1])) # Set the analysis properties on the # DalvikVMFormat instance self.vmx = VMAnalysis(self.vm) self.gmx = GVMAnalysis(self.vmx, None) if self.vmx and self.gmx: print(self.t.yellow("\n\t--> Analyzed {} (!)\n" .format(self.dex .split("/")[-1]))) # Set the analysis properties on the # DalvikVMFormat instance self.vm.set_vmanalysis(self.vmx) self.vm.set_gvmanalysis(self.gmx) # Generate xref(s) and dref(s) self.vm.create_xref() self.vm.create_dref() return else: CommandError("process_vm :" + "Cannot analyze VM instance (!)") return else: CommandError("process_vm :" + "Cannot load VM instance (!)") return else: CommandError("process_vm : classes.dex not found (!)") return except Exception as e: CommandError("process_vm : {}".format(e)) def complete_operate(self, *args): return self._cmd_completer("operate", *args) @cmd_arguments(["apk", "dex"]) def do_operate(self, *args): """ := operate apk path_to_apk := operate dex path_to_classes.dex """ # Locals arg0 = args[0].split(" ")[0] arg1 = args[0].split(" ")[1] try: if arg0 == "apk": if arg1: self.logger.log("info", "Loading : {} ..." .format(arg1.split("/")[-1])) from androguard.core.bytecodes.apk import APK self.apk = APK(arg1) if self.apk: print(self.t.yellow("\n\t--> Loaded : {} (!)\n" .format(arg1.split("/")[-1]))) self.package = self.apk.get_package() from core.brains.apk.components import Components # Load activies, services, broadcast receivers, and # content providers self.components = Components(self.apk) self.components.enumerate_components() self.permissions = self.apk.get_permissions() self.files = self.apk.get_files() self.files_type = self.apk.get_files_types() # Process DVM self.process_vm(apk=True) else: CommandError("APK not loaded (!)") elif arg0 == "dex": if arg1: self.logger.log("info", "Loading : {} ..." .format(arg1.split("/")[-1])) self.dex = arg1 self.process_vm(dex=True) except ImportError as e: CommandError("operate : {}".format(e)) def complete_surgical(self, *args): return self._cmd_completer("surgical", *args) def do_surgical(self, *args): """ := surgical """ try: if self.vm and self.vmx: from .surgical import Run run = Run(self.vm, self.vmx) run.prompt = self.t.yellow("(surgical) ") run.ruler = self.t.yellow("-") run.cmdloop() else: CommandError("classes.dex not loaded (!)") except Exception as e: CommandError("surgical : {}".format(e)) def complete_attacksurface(self, *args): return self._cmd_completer("attacksurface", *args) def do_attacksurface(self, *args): """ := attacksurface """ try: if self.apk and self.components: self.logger.log("info", "Loading attacksurface module ...") from core.brains.apk.attacksurface import AttackSurface self.attack_surface = AttackSurface(self.apk, self.components) self.attack_surface.run() # Helps with visual spacing after the results are printed print("\n") except ImportError as e: CommandError("attacksurface : {}".format(e)) def complete_permissions(self, *args): return self._cmd_completer("permissions", *args) @cmd_arguments(["list"]) def do_permissions(self, *args): """ := permissions list """ # Locals arg0 = args[0] try: if self.permissions: if args[0] == "list": self.logger.log("info", "Loading permissions ... \n") for p in self.permissions: print(self.t.yellow("\t--> {}".format(p))) print("\n") else: CommandError("Permissions not found (!)") except Exception as e: CommandError("permissions : {}".format(e)) def complete_binja(self, *args): return self._cmd_completer("binja", *args) def do_binja(self, *args): """ := binja """ try: from .binja import Run run = Run(self.files, self.apk) run.prompt = self.t.cyan("(binja) ") run.ruler = self.t.cyan("-") run.cmdloop() except Exception as e: CommandError("binja : {}".format(e)) def complete_files(self, *args): return self._cmd_completer("files", *args) @cmd_arguments(["all", "assets", "libs", "res"]) def do_files(self, *args): """ := files all := files assets := files libs := files res """ # Locals arg0 = args[0] try: if self.files: if arg0 == "assets": self.logger.log("info", "Loading files ... \n") for f in self.files: if f.startswith("assets"): print(self.t.yellow("\t--> {}".format(f))) print("\n") elif arg0 == "libs": self.logger.log("info", "Loading files ... \n") for f in self.files: if f.startswith("lib"): print(self.t.yellow("\t--> {}".format(f))) print("\n") elif arg0 == "res": self.logger.log("info", "Loading files ... \n") for f in self.files: if f.startswith("res"): print(self.t.yellow("\t--> {}".format(f))) print("\n") elif arg0 == "all": self.logger.log("info", "Loading files ... \n") for f in self.files: print(self.t.yellow("\t--> {}".format(f))) print("\n") else: CommandError("Files not populated (!)") except Exception as e: CommandError("files : {}".format(e)) def complete_strings(self, *args): return self._cmd_completer("strings", *args) @cmd_arguments(["list", "search"]) def do_strings(self, *args): """ List and search for strings found in classes.dex := strings list := strings search """ # Locals arg0 = args[0] strings = None try: if arg0 == "list": if self.vm: strings = self.vm.get_strings() if strings: for s in strings: print(self.t.cyan("--> {}".format(s.encode("utf-8", errors="ignore")))) else: CommandError("Strings not found (!)") else: CommandError("classes.dex not loaded (!)") elif arg0 == "search": if self.vm: strings = self.vm.get_strings() if strings: target = raw_input(self.t.yellow("\n\t--> Enter string : ")) for s in strings: if target in s: print(self.t.cyan("\t\t --> {}".format(s.encode("utf-8", errors="ignore")))) print("\n") else: CommandError("Strings not found (!)") else: CommandError("classes.dex not loaded (!)") except Exception as e: CommandError("strings : {}".format(e)) def complete_components(self, *args): return self._cmd_completer("components", *args) @cmd_arguments(["list"]) def do_components(self, *args): """ := components list """ # Locals arg0 = args[0] try: if arg0 == "list": if self.apk: self.logger.log("info", "Enumerating components ...\n") if self.components.activities: for a in self.components.activities: print(self.t.yellow("\t--> activity : {}" .format(a))) print("\n") if self.components.services: for s in self.components.services: print(self.t.yellow("\t--> service : {}" .format(s))) print("\n") if self.components.receivers: for r in self.components.receivers: print(self.t.yellow("\t--> receiver : {}" .format(r))) print("\n") if self.components.providers: for r in self.components.providers: print(self.t.yellow("\t--> provider : {}" .format(s))) print("\n") else: CommandError("APK not loaded (!)") except Exception as e: CommandError("components : {}".format(e)) def complete_interact(self, *args): return self._cmd_completer("interact", *args) def do_interact(self, *args): """ Drop into an interactive IPython session. := interact """ try: if self.vm and self.vmx: from core.brains.interact.interact import Interact i = Interact(self.vm, self.vmx) i.run() else: CommandError("classes.dex not loaded (!)") except Exception as e: CommandError("interact : {}".format(e.message)) def complete_class_tree(self, *args): return self._cmd_completer("class_tree", *args) def do_class_tree(self, *args): """ := class_tree """ try: if self.vm: for c in self.vm.get_classes(): # We don't care about Android support classes or resource # classes if c.name.startswith("Landroid") or \ c.name.split("/")[-1].startswith("R"): continue print("\n") print(self.t.yellow("\t--> class : {} {}".format(c.get_access_flags_string(), c.name))) for f in c.get_fields(): print(self.t.white("\t\t--> field : {} {} {}".format(f.get_access_flags_string(), f.get_descriptor(), f.name))) for m in c.get_methods(): print(self.t.cyan("\t\t\t--> method : {} {} {}".format(m.get_access_flags_string(), m.name, m.get_descriptor()))) print("\n") else: CommandError("class_tree : classes.dex not loaded (!)") except Exception as e: CommandError("class_tree : {}".format(e)) def complete_native(self, *args): return self._cmd_completer("native", *args) def do_native(self, *args): """ := native """ # Locals native_methods = list() try: if self.vm: for method in self.vm.get_methods(): if method.get_access_flags() & 0x100: native_methods.append((method.get_class_name(), method.get_name())) if native_methods: print("\n") for n in native_methods: print(self.t.cyan("\t--> {} : {}".format(n[0], n[1]))) print("\n") else: self.logger.log("info", "class_tree : classes.dex not loaded (!)") except Exception as e: CommandError("native : {}".format(e)) def complete_ui(self, *args): return self._cmd_completer("ui", *args) def do_ui(self, *args): """ := ui """ try: if self.vm and self.vmx: from core.brains.ui.terminal import TerminalApp ui = TerminalApp(self.vm, self.vmx) ui.run() except Exception as e: CommandError("ui : {}".format(e)) def complete_macro(self, *args): return self._cmd_completer("macro", *args) def do_macro(self, args): """ := macro """ # Locals directory_items = None macro = path.join(self.ROOT_DIR, "macro") selection = None apk_path = None json = None try: print("\n") directory_items = listdir(macro) for i, item in enumerate(directory_items): print(self.t.cyan("\t--> [{}] {}" .format(i, item))) print("\n") selection = raw_input(self.t.yellow("[{}] Select config : ".format(datetime.now()))) try: index = int(selection) except ValueError: index = -1 print("\n") if selection: for i, item in enumerate(directory_items): if selection == item or i == index: selection = item break with open("".join([macro, "/", selection]), "rb") as config: # Load the config as JSON json = loads(config.read()) if json: for k, v in json.items(): if k == "apk": if v: apk_path = str(v) # Call operate() with the path to apk self.do_operate("apk {}" .format(apk_path)) return else: CommandError("macro : Path to APK not found in {}" .format(selection)) else: CommandError("macro : Error loading {} as JSON" .format(selection)) except Exception as e: CommandError("macro : {}".format(e))
def main(): for path in samples(): print(path) logging.error("Processing" + path) tests_apk = ["is_valid_APK", "get_filename", "get_app_name", "get_app_icon", "get_package", "get_androidversion_code", "get_androidversion_name", "get_files", "get_files_types", "get_files_crc32", "get_files_information", "get_raw", "get_dex", "get_all_dex", "get_main_activity", "get_activities", "get_services", "get_receivers", "get_providers", "get_permissions", "get_details_permissions", "get_requested_aosp_permissions", "get_requested_aosp_permissions_details", "get_requested_third_party_permissions", "get_declared_permissions", "get_declared_permissions_details", "get_max_sdk_version", "get_min_sdk_version", "get_target_sdk_version", "get_libraries", "get_android_manifest_axml", "get_android_manifest_xml", "get_android_resources", "get_signature_name", "get_signature_names", "get_signature", "get_signatures"] tests_dex = ["get_api_version", "get_classes_def_item", "get_methods_id_item", "get_fields_id_item", "get_codes_item", "get_string_data_item", "get_debug_info_item", "get_header_item", "get_class_manager", "show", "save", "get_classes_names", "get_classes", "get_all_fields", "get_fields", "get_methods", "get_len_methods", "get_strings", "get_format_type", "create_python_export", "get_BRANCH_DVM_OPCODES", "get_determineNext", "get_determineException", "print_classes_hierarchy", "list_classes_hierarchy", "get_format"] try: # Testing APK a = APK(path) for t in tests_apk: print(t) x = getattr(a, t) try: x() except Exception as aaa: print(aaa) traceback.print_exc() print(path, aaa, file=sys.stderr) logging.exception("{} .. {}".format(path, t)) # Testing DEX for dex in a.get_all_dex(): d = DalvikVMFormat(dex) dx = Analysis(d) d.set_vmanalysis(dx) # Test decompilation for c in d.get_classes(): for m in c.get_methods(): mx = dx.get_method(m) ms = DvMethod(mx) try: ms.process(doAST=True) except Exception as aaa: print(aaa) traceback.print_exc() print(path, aaa, file=sys.stderr) logging.exception("{} .. {} .. {}".format(path, c.get_name(), m.get_name())) ms2 = DvMethod(mx) try: ms2.process(doAST=False) except Exception as aaa: print(aaa) traceback.print_exc() print(path, aaa, file=sys.stderr) logging.exception("{} .. {} .. {}".format(path, c.get_name(), m.get_name())) # Other tests for t in tests_dex: print(t) x = getattr(d, t) try: x() except Exception as aaa: print(aaa) traceback.print_exc() print(path, aaa, file=sys.stderr) logging.exception("{} .. {}".format(path, t)) except KeyboardInterrupt: raise except FileNotFoundError: pass except Exception as e: print(e) traceback.print_exc() print(path, e, file=sys.stderr) logging.exception(path)
if depth == 0: print(m.class_name + " -> " + m.name) for item in m.XREFfrom.items: if item[0].class_name != class_name or item[ 0].name != method_name: for x in range(1, depth): sys.stdout.write('--') sys.stdout.write('>' + item[0].class_name + "->" + item[0].name + "\n") XrefTraverse(methods, item[0].class_name, item[0].name, depth) if len(sys.argv) > 2: filename = sys.argv[1] class_name = sys.argv[2] class_name = 'L' + class_name.replace(".", "/") + ";" #print class_name method_name = '<init>' d = DalvikVMFormat(APK(filename, False).get_dex()) d.create_python_export() dx = uVMAnalysis(d) gx = GVMAnalysis(dx, None) d.set_vmanalysis(dx) d.set_gvmanalysis(gx) d.create_xref() XrefTraverse(d.get_methods(), class_name, method_name, 0) else: print "usage: XrefTree.py [filename] [class_name]" print "usage: XrefTree.py filename.apk com.xyz.abc"
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
class FCG(): ##/////////////Changed for testing///////////////////// def __init__(self, filename): self.filename = filename # print(os.path.exists(filename)) # a,d,dx = AnalyzeAPK(filename) # print(dx.get_call_graph()) try: self.a = APK(filename) self.d = DalvikVMFormat(self.a.get_dex()) self.d.create_python_export() self.dx = Analysis(self.d) except zipfile.BadZipfile: # if file is not an APK, may be a dex object _, self.d, self.dx = AnalyzeDex(self.filename) self.d.set_vmanalysis(self.dx) self.dx.create_xref() self.fcg = self.build_fcg() def get_fcg(self): return self.fcg def get_lock_graph(self): graph_list = [] # print("LockGraphs", self.dx) call_graph = self.dx.get_call_graph() # print("Call Graphs") for m in (self.dx.find_methods( classname='Landroid.os.PowerManager.WakeLock' )): ##//////////Work fine but found 3 method so will use when done # print("Method=", m.get_method()) ancestors = nx.ancestors(call_graph, m.get_method()) ancestors.add(m.get_method()) graph = call_graph.subgraph(ancestors) graph_list.append(graph) wake_graph = nx.compose_all(graph_list) return wake_graph def build_fcg(self): """ Using NX and Androguard, build a directed graph NX object so that: - node names are analysis.MethodClassAnalysis objects - each node has a label that encodes the method behavior """ fcg = self.get_lock_graph() ##/////////My changes/////////////// for n in fcg.nodes: instructions = [] try: ops = n.get_instructions() for i in ops: instructions.append(i.get_name()) encoded_label = self.color_instructions(instructions) except AttributeError: encoded_label = np.array([0] * 15) fcg.node[n]["label"] = encoded_label return fcg def color_instructions(self, instructions): """ Node label based on coloring technique by Kruegel """ h = [0] * len(INSTRUCTION_CLASS_COLOR) for i in instructions: h[INSTRUCTION_SET_COLOR[i]] = 1 return np.array(h) def get_classes_from_label(self, label): classes = [ INSTRUCTION_CLASSES[i] for i in range(len(label)) if label[i] == 1 ] return classes
def analyze_dex(filepath_or_raw, needs_dalvik_vm_format=True, needs_vm_analysis=True, needs_gvm_analysis=True, needs_xref=True, needs_dref=True, raw=False, decompiler="dad"): ''' Open the classes.dex file `needs_dalvik_vm_format` and set up an analyzer for it `needs_vm_analysis`. Parameters ---------- filepath_or_raw : path to file or raw data Set raw to True if `filepath_or_raw` is raw data. needs_dalvik_vm_format : bool, optional (default is True) needs_vm_analysis : bool, optional (default is True) needs_gvm_analysis : bool, optional (default is True) needs_xref : bool, optional (default is True) needs_dref : bool, optional (default is True) raw : bool, optional (default is False) decompiler : str, optional (default is "dad") Returns ------- tuple<DalvikVMFormat, VMAnalysis, GVMAnalysis> Raises ------ DexError If an error occurred while creating the analysis objects. ''' dalvik_vm_format, vm_analysis, gvm_analysis = None, None, None # every requirement implies the need for the `dalvik_vm_format` needs_dalvik_vm_format = any((needs_dalvik_vm_format, needs_vm_analysis, needs_gvm_analysis, needs_xref, needs_dref)) cross_ref = any((needs_xref, needs_dref)) try: if needs_dalvik_vm_format: if raw == False: with open(filepath_or_raw, "rb") as f: dalvik_vm_format = DalvikVMFormat(f.read()) else: dalvik_vm_format = DalvikVMFormat(filepath_or_raw) if needs_vm_analysis or cross_ref or needs_gvm_analysis: vm_analysis = uVMAnalysis(dalvik_vm_format) dalvik_vm_format.set_vmanalysis(vm_analysis) if needs_gvm_analysis or cross_ref: gvm_analysis = GVMAnalysis(vm_analysis, None) dalvik_vm_format.set_gvmanalysis(gvm_analysis) if dalvik_vm_format: RunDecompiler(dalvik_vm_format, vm_analysis, decompiler) # create references, gvm_analysis needed! # we optimize through not exporting the references into the python objects if needs_xref: dalvik_vm_format.create_xref(python_export=False) if needs_dref: dalvik_vm_format.create_dref(python_export=False) except Exception as e: # androguard caused error -> propagate as DexError raise DexError(caused_by=e), None, sys.exc_info()[2] return dalvik_vm_format, vm_analysis, gvm_analysis
def extract_features(file_path): result = {} try: a = APK(file_path) d = DalvikVMFormat(a.get_dex()) dx = VMAnalysis(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()] class_names = [c.get_name() for c in d.get_classes()] method_names = [m.get_name() for m in d.get_methods()] 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']) s_list.extend(class_names) s_list.extend(method_names) s_list.extend(method_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.tainted_packages.search_methods(".", 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) 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) opt_seq = [] for m in d.get_methods(): for i in m.get_instructions(): opt_seq.append(i.get_name()) optngramlist = [tuple(opt_seq[i:i+NGRAM]) for i in xrange(len(opt_seq) - NGRAM)] optngram = Counter(optngramlist) optcodes = dict() tmpCodes = dict(optngram) #for k,v in optngram.iteritems(): # if v>=NGRAM_THRE: #optcodes[str(k)] = v # optcodes[str(k)] = 1 tmpCodes = sorted(tmpCodes.items(),key =lambda d:d[1],reverse=True) for value in tmpCodes[:NGRAM_THRE]: optcodes[str(value[0])] = 1 result['feature_vectors']['opt_codes'] = optcodes return result
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()
class MyAPK: def __init__(self, name_file, conf, file_log, tag, string_to_find, logger, api_monitor_dict=None, network_dict=None, dynamic_time=0, use_smaliparser=True): self.name_apk = name_file self.name_only_apk = self.name_apk.split("/")[-1].rsplit(".", 1)[0] self.conf = conf self.apk = APK(name_file) self.app_name = self.apk.get_app_name() self.package_name = self.apk.get_package() self.target_sdk = self.apk.get_target_sdk_version() self.dalviks_format = None self.analysis_object = None self.dict_file_with_string = dict( ) # file che contengono la stringa ricercata self.string_to_find = string_to_find # stringa da cercare self.is_contain_permission = False # se contiene i permessi del file conf self.url_loaded = list() # list url that has been loaded # se contiene i file ibridi --> probabilmente app ibrida self.is_contain_file_hybrid = False # pagine_html con iframe se contengono csp [True o False] self.find_csp = dict() # se contiene i metodi all'interno del file conf.json self.is_contains_all_methods = False self.zip = zipfile.ZipFile(self.name_apk) # get zip object from apk self.list_file = self.zip.namelist() # tutti i file all'interno self.html_file = FileAnalysis.find_html_file(self.list_file) self.file_log = file_log # name to file log self.javascript_enabled = False self.internet_enabled = False self.file_vulnerable_frame_confusion = list() self.file_with_string_iframe = list() self.isHybrid = None # dict indexes with name method and get encoded methods where function was called self.method = dict() self.all_url = list() # all url in the apk self.file_download_to_analyze = dict() self.search_tag = tag self.md5_file_to_url = dict( ) # dict with indexes with name and get url remote self.file_config_hybrid = None self.list_origin_access = list() self.logger = logger self.api_monitor_dict = api_monitor_dict self.network_dict = network_dict self.file_hybrid = list() self.javascript_interface = False self.javascript_file = FileAnalysis.find_js_file(self.list_file) self.src_iframe = dict() self.page_xss_vuln = dict() self.is_vulnerable_frame_confusion = False self.http_connection = list() self.http_connection_static = list() self.all_http_connection = list() self.url_dynamic = list() self.use_smaliparser = use_smaliparser self.use_analyze = not use_smaliparser self.method_2_value = dict() self.dynamic_javascript_enabled = False self.analysis_dynamic_done = api_monitor_dict is not None or network_dict is not None self.dynamic_javascript_interface = False self.dynamic_time = dynamic_time # time execution analysis dynamic self.all_url_dynamic = list() self.load_url_dynamic = list() self.app_use_sandbox = False self.file_with_sandbox = dict() # app use sandbox def read(self, filename, binary=True): with open(filename, 'rb' if binary else 'r') as f: return f.read() def check_permission(self, list_permission_to_find): """ check permission hybrid app """ use_permission_checker = True if not use_permission_checker: permission_find = list() for permission_to_check in list_permission_to_find: if permission_to_check in self.apk.get_permissions(): permission_find.append(True) # contenere tutti i permessi if permission_to_check == "android.permission.INTERNET": self.internet_enabled = True # print(permission_to_check) self.logger.logger.info("[Permission declared Start]") for p in self.apk.get_permissions(): self.logger.logger.info(p) self.logger.logger.info("[Permission End]\n") self.is_contain_permission = len(permission_find) == len( list_permission_to_find) else: if "PermissionChecker.jar" in os.listdir("."): dir_permission_checker = "PermissionChecker.jar" else: dir_permission_checker = os.path.join("FCDroid", "PermissionChecker.jar") try: cmd_permission_checker = [ "java", "-jar", dir_permission_checker, self.name_apk ] process = subprocess.Popen(cmd_permission_checker, stdout=subprocess.PIPE) result = process.communicate()[0] # error here result = json.loads(result) # requiredAndUsed = result['requiredAndUsed'] notRequiredButUsed = result['notRequiredButUsed'] declared = result['declared'] # requiredButNotUsed = result['requiredButNotUsed'] list_permission = list(set().union(notRequiredButUsed, declared)) permission_find = list() for permission_to_check in list_permission_to_find: if permission_to_check in list_permission: permission_find.append( True) # contenere tutti i permessi if permission_to_check == "android.permission.INTERNET": self.internet_enabled = True self.logger.logger.info( "[Permission declared and not required but used Start]") for p in list_permission: self.logger.logger.info(p) self.logger.logger.info("[Permission End]\n") self.is_contain_permission = len(permission_find) == len( list_permission_to_find) except Exception as e: permission_find = list() for permission_to_check in list_permission_to_find: if permission_to_check in self.apk.get_permissions(): permission_find.append( True) # contenere tutti i permessi if permission_to_check == "android.permission.INTERNET": self.internet_enabled = True # print(permission_to_check) self.logger.logger.info("[Permission declared Start]") for p in self.apk.get_permissions(): self.logger.logger.info(p) self.logger.logger.info("[Permission End]\n") self.is_contain_permission = len(permission_find) == len( list_permission_to_find) def is_hybird(self): """ function to check se apk is hybrid, 1) if contain file from conf.json (cordova/plugin/phonegap/config) 2) if present permission internet (inutile) """ if self.isHybrid is None: list_file_to_find = self.conf["file_to_check"] list_permission_to_find = self.conf["permissions_to_check"] self.is_contain_file_hybrid, self.file_hybrid = FileAnalysis.check_file_hybrid( self.list_file, list_file_to_find) if self.is_contain_file_hybrid: self.logger.logger.info("Hybrid file found are: " + str(self.file_hybrid)) self.check_permission(list_permission_to_find) self.isHybrid = self.is_contain_permission and self.is_contain_file_hybrid # using apktool FNULL = open(os.devnull, 'w') print(bcolors.WARNING + "[*] Starting apktool " + bcolors.ENDC) self.logger.logger.info("Starting apktool") cmd = [ "apktool", "d", "-o", "temp_dir_" + self.name_only_apk, self.name_apk, "-f" ] subprocess.call(cmd, stdout=FNULL, stderr=subprocess.STDOUT) try: if self.isHybrid: # now can search file in temp_dir if os.path.exists("temp_dir_{0}/res/xml/config.xml".format( self.name_only_apk)): file_xml = open( "temp_dir_{0}/res/xml/config.xml".format( self.name_only_apk)) file_data_xml = str(file_xml.read()) self.file_config_hybrid = file_data_xml # parsing file config self.check_whitelist() except OSError as e: print( bcolors.FAIL + "File config.xml not found, it is necessary to decompile the application first" + bcolors.ENDC) # remove dir self.logger.logger.error( "[ERROR file config.xmls] {0} \n".format(e)) return self.isHybrid def check_whitelist(self): """ function that obtain access origin from file config.xml """ # get xml_object ElementTree if self.file_config_hybrid is not None and self.isHybrid: self.list_origin_access = list() root = ET.fromstring(self.file_config_hybrid) xmlns = "{http://www.w3.org/ns/widgets}" # default namespace # TODO aggiungere altri elementi della whitelist # 1) <allow-navigation href="http://*/*" /> # Controls which URLs the WebView itself can be navigated to. Applies to top-level navigations only. # 2) <allow-intent href="http://*/*" /> # Controls which URLs the app is allowed to ask the system to open. By default, no external URLs are allowed # 3) <access origin="http://google.com" /> # Controls which network requests (images, XHRs, etc) are allowed to be made (via cordova native hooks). for child in root.findall(xmlns + "access"): # print( child.tag, child.attrib.get("origin")) self.list_origin_access.append(child.attrib.get("origin")) self.logger.logger.info("[INIT ACCESS ORIGIN LIST]") for value in self.list_origin_access: self.logger.logger.info("origin: %s", value) self.logger.logger.info("[END ACCESS ORIGIN LIST]\n") def analyze_xss_dom(self, file_name, file_content): """ search static dom xss based on regex """ # TODO se file_name end with js use TaintJS altrimenti usare questo # per usare taint js salvare il contenuto in una dir temporanea e usarlo # da li dentro try: print("file xss dom analyze {0}".format(file_name)) if file_name.endswith(".js"): file_open_temp = "FCDroid/TaintJS/temp_file_to_analyze.js" file_to_write = open(file_open_temp, "w") file_to_write.write(file_content) file_to_write.close() cmd_node = [ "node", "--max-old-space-size=4096", "FCDroid/TaintJS/app.js", file_open_temp ] process = subprocess.Popen(cmd_node, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = process.communicate() out = out.decode('utf-8').strip() err = err.decode('utf-8') os.remove(file_open_temp) # no error if err != '': # no error if out == 'true': # is vuln self.page_xss_vuln[file_name] = True else: page_analyze = XSScanner(file_name, file_content) page_analyze.analyze_page() if len(page_analyze.sink) > 0 or len( page_analyze.source) > 0: self.page_xss_vuln[file_name] = page_analyze else: soup = BeautifulSoup(file_content, 'html.parser') scripts = soup.find_all("script") for script in scripts: value = script.get_text().strip() file_open_temp = "FCDroid/TaintJS/temp_file_to_analyze.js" file_to_write = open(file_open_temp, "w") file_to_write.write(value) file_to_write.close() cmd_node = [ "node", "--max-old-space-size=4096", "FCDroid/TaintJS/app.js", file_open_temp ] process = subprocess.Popen(cmd_node, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = process.communicate() out = out.decode('utf-8').strip() err = err.decode('utf-8') os.remove(file_open_temp) # no error if err != '': # no error if out == 'true': # is vuln self.page_xss_vuln[file_name] = True else: page_analyze = XSScanner(file_name, file_content) page_analyze.analyze_page() if len(page_analyze.sink) > 0 or len( page_analyze.source) > 0: self.page_xss_vuln[file_name] = page_analyze except Exception: page_analyze = XSScanner(file_name, file_content) page_analyze.analyze_page() if len(page_analyze.sink) > 0 or len(page_analyze.source) > 0: self.page_xss_vuln[file_name] = page_analyze def find_string(self, file_to_search, remote=False, debug=False): """ find string inside file of apk(html,xml,ecc..) (not yet decompiled) """ debug = True # print(self.md5_file_to_url.keys()) if remote: self.logger.logger.info("[START REMOTE FILE ANALYZE]") else: self.logger.logger.info("[START FILE ANALYZE]") for file_to_inspect, insideAPK in file_to_search.items(): if not remote and debug: self.logger.logger.info("File: " + file_to_inspect) else: if debug: try: m = hashlib.md5() m.update(file_to_inspect.encode('utf-8')) self.logger.logger.info( "Remote File in: {0}".format(file_to_inspect)) if m.hexdigest() in self.md5_file_to_url.keys(): self.logger.logger.info("URL: {0}".format( self.md5_file_to_url[str(m.hexdigest())])) except KeyError as e: self.logger.logger.warning( "Key error as {0} ".format(e)) file_to_inspect_split = file_to_inspect.split( "?", 1)[0] # remove parameter if remote and not (file_to_inspect_split.endswith(".js") or file_to_inspect_split.endswith(".html")): # add extension html on file # of default wget add this extension file_to_inspect = file_to_inspect + ".html" if insideAPK: data = self.zip.open(file_to_inspect) else: data = open(file_to_inspect, "r") ####################################################################################################### # start xss analysis on this file try: content_file = data.read() thread = threading.Thread(name="xss_" + file_to_inspect, target=self.analyze_xss_dom, args=( file_to_inspect, str(content_file), )) thread.start() ####################################################################################################### file_read = str(content_file) soup = BeautifulSoup(file_read, 'lxml') try: find_iframe, list_row_string, list_src_iframe, find_string_not_tag, file_with_sandbox = FileAnalysis.find_string( self.string_to_find, self.search_tag, file_to_inspect, file_read, soup, self.logger) self.file_with_sandbox = { **self.file_with_sandbox, **file_with_sandbox } # merge dict ####################################################################################################### # TODO insert in method --> String Analysis if find_iframe and self.string_to_find == "iframe": if not find_string_not_tag: self.dict_file_with_string[ file_to_inspect] = list_row_string self.src_iframe[file_to_inspect] = list_src_iframe # TODO search id iframe in file js in script src if not self.search_tag or file_to_inspect_split.endswith( ".js") or find_string_not_tag: self.file_with_string_iframe.append( file_to_inspect) # append file with iframe print(bcolors.FAIL + "Found " + self.string_to_find + " in line " + str(list_row_string) + bcolors.ENDC) self.logger.logger.info( "Found %s file %s in line %s", self.string_to_find, file_to_inspect, str(list_row_string)) else: print(bcolors.FAIL + "Found tag " + self.string_to_find + ", " + str(len(list_row_string)) + " times " + bcolors.ENDC) self.logger.logger.info( "Found in file %s tag %s , %s times", file_to_inspect, self.string_to_find, str(len(list_row_string))) if len(self.src_iframe[file_to_inspect]) > 0: self.logger.logger.info( "Founded this src {0} in iframe tag inside file {1}" .format( str(self.src_iframe[file_to_inspect]), file_to_inspect)) else: self.logger.logger.info( "No src founded in iframe tag inside file {0}" .format(file_to_inspect)) ####################################################################################################### # TODO aggiungere il content e fare conclusioni su di esso e per i file JavaScript find_csp = soup.find( "meta", {"http-equiv": "Content-Security-Policy"}) if find_csp is not None: print(bcolors.OKGREEN + "Find CSP with content: [" + find_csp["content"] + "]" + bcolors.ENDC) self.logger.logger.info( "Find CSP with content: [" + find_csp["content"] + "]") self.find_csp[file_to_inspect] = True # only file html elif not file_to_inspect_split.endswith(".js"): print(bcolors.FAIL + "No CSP found!" + bcolors.ENDC) self.logger.logger.info("No CSP found!") self.find_csp[file_to_inspect] = False elif file_to_inspect_split.endswith(".js"): print(bcolors.FAIL + "It is a JS file, no CSP found!" + bcolors.ENDC) self.logger.logger.info( "It is a JS file, no CSP found!, investigate manually\n" ) self.find_csp[file_to_inspect] = False else: print(bcolors.OKGREEN + "No " + self.string_to_find + " in " + file_to_inspect + bcolors.ENDC) self.logger.logger.info("No " + self.string_to_find + " in " + file_to_inspect + "\n") except zipfile.BadZipfile as e: self.logger.error("Error bad zip file {0}".format(e)) continue except ValueError as e: self.logger.error("Error value error {0}".format(e)) continue except UnicodeDecodeError as e: self.logger.logger.error("Error unicode error {0}".format(e)) continue self.logger.logger.info("[END ANALYZE FILE]") return None def find_method_used(self): """ funzione per ricercare i metodi che sono usati all'interno dell'apk, tanto lenta """ used_jadx = False if used_jadx: # Create DalvikVMFormat Object self.dalvik_format = DalvikVMFormat(self.apk) # Create Analysis Object self.analysis_object = Analysis(self.dalvik_format) # Load the decompiler # Make sure that the jadx executable is found in $PATH # or use the argument jadx="/path/to/jadx" to point to the executable decompiler = DecompilerJADX(self.dalvik_format, self.analysis_object) # propagate decompiler and analysis back to DalvikVMFormat self.dalvik_format.set_decompiler(decompiler) self.dalvik_format.set_vmanalysis(self.analysis_object) # Now you can do stuff like: list_method_analysis = self.analysis_object.get_methods() for method_analys in list_method_analysis: method_name = method_analys.get_method().get_name() # print(method_encoded.get_method().get_source()) self.method[method_name] = list(method_analys.get_xref_from()) elif self.use_analyze: # return apk, list dex , object analysis apk, self.dalvik_format, self.analysis_object = AnalyzeAPK( self.name_apk) for method_analys in self.analysis_object.get_methods(): method_name = method_analys.get_method().get_name() # from method_name get list dove esso viene chiamato self.method[method_name] = list(method_analys.get_xref_from()) elif self.use_smaliparser: # use smali parser, apktool and grep invece di Androguard dir_apk_tool = "temp_dir_" + self.name_only_apk + "/" list_method_to_analyze = self.conf["method_smali_parser"] self.method_2_value, self.all_url = smaliparser.start( dir_apk_tool, list_method_to_analyze) else: # TODO to make faster analysis but not work well self.dalvik_format = DalvikVMFormat(self.apk) for encoded_method in self.dalvik_format.get_methods(): method_analysis = MethodClassAnalysis(encoded_method) method_name = method_analysis.get_method().get_name() # print(method_name) # from method_name get list dove esso viene chiamato self.method[method_name] = list( method_analysis.get_xref_from()) # print(self.method[method_name]) def check_method_conf(self): """ function to check se methods inside conf.json method_to_check is used inside apk """ method_to_find = self.conf["method_to_check"] method_present = dict() try: if self.use_smaliparser: if "setJavaScriptEnabled" in self.method_2_value.keys(): if "0x1" in self.method_2_value["setJavaScriptEnabled"]: self.javascript_enabled = True method_present["setJavaScriptEnabled"] = True if "addJavascriptInterface" in self.method_2_value.keys(): self.javascript_interface = True method_present["addJavascriptInterface"] = True else: for mf in method_to_find: method_present[mf] = False for mapk in self.method.keys(): if mf in mapk: method_present[mf] = True if method_present["setJavaScriptEnabled"]: for value in self.method["setJavaScriptEnabled"]: try: if value[1] is not None: encoded_method = value[1] source_code = FileAnalysis.get_list_source_code( encoded_method) if FileAnalysis.check_method_used_value( source_code, "setJavaScriptEnabled", "1"): # volendo si possono memorizzare tutti i file che lo settano atrue self.javascript_enabled = True break except (TypeError, AttributeError, KeyError) as e: self.logger.logger.error( "Exception during check method used {0}". format(e)) continue print() if self.dynamic_javascript_enabled: self.logger.logger.info( "[JavaScript enabled (check dynamically) :" + str(self.dynamic_javascript_enabled) + "]") else: self.logger.logger.info( "[JavaScript enabled (check static): " + str(self.javascript_enabled) + "]") except Exception as e: self.logger.logger.error( "File conf.json without method setJavaScriptEnabled {0}". format(e)) try: if not self.use_smaliparser: if self.dynamic_javascript_interface: self.logger.logger.info( "[Add interface WebView (check dynamically): " + str(self.dynamic_javascript_interface) + "]") self.javascript_interface = self.dynamic_javascript_interface else: self.logger.logger.info( "[Add interface WebView (check static): " + str(method_present["addJavascriptInterface"]) + "]") self.javascript_interface = method_present[ "addJavascriptInterface"] else: if self.dynamic_javascript_interface: method_present[ "addJavascriptInterface"] = self.dynamic_javascript_interface self.logger.logger.info( "[Add interface WebView (check dynamically): " + str(self.dynamic_javascript_interface) + "]") else: method_present[ "addJavascriptInterface"] = self.javascript_interface self.logger.logger.info( "[Add interface WebView (check static): " + str(self.javascript_interface) + "]") except Exception as e: # nothing self.logger.logger.error( "File conf.json without method addJavascriptInterface {0}\n". format(e)) self.is_contains_all_methods = len(method_present) == len( method_to_find) return self.is_contains_all_methods def find_url_in_apk(self): """ find all url/uri inside apk """ # add url using dynamic analysis if self.api_monitor_dict is not None and self.network_dict is not None: self.add_url_dynamic() ############################################################################## # use smali_parser if self.use_smaliparser: # add url loaded for smali_parsr if "loadUrl" in self.method_2_value.keys(): all_url_loaded = self.method_2_value["loadUrl"] # da queste devo filtrare ottenendo solo quelle http/https temp_url_loaded = list( filter( lambda x: x is not None and (x.startswith("http") or x.startswith("https")), all_url_loaded)) self.url_loaded = list(set().union(self.url_loaded, temp_url_loaded)) else: # ALL string inside apk # use AndroGuard # url regularp expression # url_re = "(http:\/\/|https:\/\/|file:\/\/\/)?[-a-zA-Z0-9@:%._\+~#=]\.[a-z]([-a-zA-Z0-9@:%_\+.~#?&//=]*)" url_re = "^(http:\/\/|https:\/\/)\w+" list_string_analysis = list() # list of string analysis object # se uso aalysis object if self.analysis_object is not None: list_string_analysis = self.analysis_object.find_strings( url_re) # --> gen object else: list_string = self.dalvik_format.get_regex_strings(url_re) # get all string inside apk for string_value in list_string: list_string_analysis.append(StringAnalysis(string_value)) ################################################################################## temp_string_value = list() # string- tuple with classAnalysis e encodeMethod that use the string dict_class_method_analysis = dict() for string_analysis in list_string_analysis: temp_string_value.append( string_analysis.get_value()) # tutte le url dict_class_method_analysis[string_analysis.get_value()] = list( string_analysis.get_xref_from() ) # url e relativo codice dove le ho trovate ################################################################################## # per ogni file, otteniamo una lista di tupla # class analysis e encoded_method for key in dict_class_method_analysis.keys(): for value in dict_class_method_analysis[key]: # class_analysis = value[0] try: if value[1] is not None: encoded_method = value[1] # split the instruction in a list source_code = FileAnalysis.get_list_source_code( encoded_method) if source_code is not None: self.all_url.append(key) # appendo l'url if FileAnalysis.check_method_used_value( source_code, "loadUrl", key): self.url_loaded.append( key ) # appendo url se caricata dentro loadUrl except (TypeError, AttributeError, KeyError) as e: self.logger.logger.error( "Exception during find url in apk {0}".format(e)) continue ####################################################################################################### # debug part if len(self.url_loaded) > 0: # print(self.url_loaded) self.logger.logger.info( "[START URL LOADED INSIDE LOADURL FUNCTION]") self.url_loaded = list(set(self.url_loaded)) for u in self.url_loaded: if u.startswith("http://"): self.http_connection_static.append(u) self.logger.logger.info( "Url inside load function: {0}".format(u)) self.logger.logger.info("[END URL LOADED INSIDE LOADURL FUNCTION]") md5_file_to_url, file_download_to_analyze = utility.download_page_with_wget( self.name_only_apk, self.url_loaded) for key in md5_file_to_url.keys(): if key not in self.md5_file_to_url.keys(): self.md5_file_to_url[key] = md5_file_to_url[key] for key in file_download_to_analyze.keys(): if key not in self.file_download_to_analyze.keys(): self.file_download_to_analyze[ key] = file_download_to_analyze[key] # self.download_page_loaded_with_wget() self.find_string(self.file_download_to_analyze, remote=True) if len(self.all_url) > 0: self.all_url = list(set(self.all_url)) self.logger.logger.info("[START ALL URL INSIDE APK]") for u in self.all_url: if u.startswith("http://"): self.all_http_connection.append(u) self.logger.logger.info("Url inside apk {0}".format(u)) self.logger.logger.info("[END ALL URL INSIDE APK]") html_dir = "temp_html_code/html_downloaded_{0}/".format( self.name_only_apk) # TODO eliminare save_page_html = False if os.path.exists(html_dir) and len( os.listdir(html_dir)) > 0 and save_page_html: # zip -r squash.zip dir1 subprocess.call([ "zip", "-r", "temp_html_code/html_{0}.zip".format( self.name_only_apk), html_dir ], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) # delete dir o provare a zip subprocess.Popen(["rm", "-rf", html_dir], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) # check vulnerability def vulnerable_frame_confusion(self): """ check if app is vulnerable on frame confusion 1) iframe nella stringa di ricerca 2) metodi addJavascriptInterface e setJavaScriptEnabled usati 3) permesso internet 4) almeno un file html con l'iframe all'interno e senza csp """ # se esiste almeno un file con iframe senza csp --> vulnerble # se è false --> vulnerabile csp_in_file_iframe = True app_use_sandbox = True # print("File in dict_file_with_string: {}".format(self.dict_file_with_string.keys())) # print("File in find_csp: {}".format(self.find_csp.keys())) # print("File in file_with_sandbox: {}".format(self.file_with_sandbox.keys())) for file_with_iframe in self.dict_file_with_string.keys(): csp_in_file_iframe = csp_in_file_iframe and self.find_csp[ file_with_iframe] app_use_sandbox = app_use_sandbox and self.file_with_sandbox[ file_with_iframe] if not self.find_csp[ file_with_iframe] or not self.file_with_sandbox[ file_with_iframe]: self.file_vulnerable_frame_confusion.append(file_with_iframe) # print("sandbox in app {}".format(self.app_use_sandbox)) # se vero whitelist implementato male white_list_bug = len( self.list_origin_access) == 0 or "*" in self.list_origin_access self.is_vulnerable_frame_confusion = ( "iframe" in self.string_to_find and self.check_method_conf() and (len(self.dict_file_with_string) > 0 or len(self.file_with_string_iframe) > 0) and self.is_contain_permission and not csp_in_file_iframe and white_list_bug and not self.app_use_sandbox) def add_url_dynamic(self): """ function that aggiunge le url caricate diamicamente attraverso che sono state trovate precendetemente dall'analisi dinamica """ ####################################################################################################### function_load_url = ["loadUrl"] # funzioni che caricano url in Android url_api_monitor = list() for keys in self.api_monitor_dict.keys(): if keys in function_load_url: url_api_monitor = list(set().union( url_api_monitor, self.api_monitor_dict[keys]["args"])) # dynamic interface and javascript enabled if keys == "addJavascriptInterface": self.dynamic_javascript_interface = True # TODO check --> considero javascriptenabled se ho solo l'interface abilitata if keys == "setJavaScriptEnabled" and True in self.api_monitor_dict[ keys]["args"]: self.dynamic_javascript_enabled = True # get all http/https/file in load function self.url_dynamic = filter( lambda x: x.startswith("http://") or x.startswith("https://") or x. startswith("file://"), url_api_monitor) self.load_url_dynamic = self.url_dynamic ####################################################################################################### # TODO mettere la funzione evaluateJavaScript o loadUrl javascript: --> come se fosse un file javascript javascript_load_url = filter(lambda x: x.startswith("javascript:"), url_api_monitor) # method that exec js in recent api javascript_evaluate = list() method_evaluate_js = ["evaluateJavascript"] for keys in self.api_monitor_dict.keys(): if keys in method_evaluate_js: javascript_evaluate = list(set().union( javascript_evaluate, self.api_monitor_dict[keys]["args"])) # now write this code in a file and analyze them javascript_code_exec = list(set().union(javascript_load_url, javascript_evaluate)) name_file = "code_js_loaded_" i = 1 list_file_js_dynamic = dict() dir_write = os.path.join("temp_html_code", "html_downloaded_" + self.name_only_apk) if not os.path.isdir(dir_write): os.makedirs(dir_write) for code in javascript_code_exec: file_js = os.path.join(dir_write, name_file + "{0}.js".format(i)) file = open(file_js, "w") file.write(code) file.close() list_file_js_dynamic[file_js] = False self.javascript_file[file_js] = False self.logger.logger.info("[Start javascript code dynamic]") self.find_string(list_file_js_dynamic) self.logger.logger.info("[End javascript code dynamic]\n") ####################################################################################################### # TODO mettere metodi cordova ####################################################################################################### # ora devo filtrare solo le url che sono http/https url_network = list() for keys in self.network_dict.keys(): # TODO check url_list_new = list() for url in self.network_dict[keys]["url"]: # search ip ip = re.findall(r"[0-9]+(?:\.[0-9]+){3}", url) if ip != None and len(ip) > 0: # change ip with host # get only first element of every list --> every list are max 1 element url_new = url.replace(ip[0], self.network_dict[keys]["host"][0]) url_list_new.append(url_new) else: url_list_new.append(url) # add new url self.network_dict[keys]["url"] = url_list_new url_network = list(set().union(url_network, self.network_dict[keys]["url"])) ########################################################################################################## # remove url google # url effettivamente caricate nell'applicazione self.url_dynamic = list(set().union(self.url_dynamic, url_network)) self.all_url_dynamic = self.url_dynamic url_dynamic_to_remove = list() for url_dyn in self.url_dynamic: for url_to_check in self.conf["url_to_remove"]: if url_to_check in url_dyn: url_dynamic_to_remove.append(url_dyn) # TODO maybe to add url_dynamic_to_remove = list(set(url_dynamic_to_remove)) for url_to_remove in url_dynamic_to_remove: self.url_dynamic.remove(url_to_remove) ####################################################################################################### self.url_loaded = list(set().union(self.url_loaded, self.url_dynamic)) self.all_url = list(set().union(self.all_url, self.url_loaded)) self.logger.logger.info("[Init add url dynamic ]") for u in self.url_dynamic: if u.startswith("http://"): self.http_connection.append(u) if u in self.load_url_dynamic: self.logger.logger.info( "Url dynamic inside loadUrl{0}".format(u)) else: self.logger.logger.info("Url dynamic {0}".format(u)) self.logger.logger.info("[End url dynamic]\n")
def get_apis(path): methods = set() error_file = open("error_files.txt", "w") """ Get the APIs from an application. Parameters: path - The path of the application to be decompiled Returns: A sorted list of APIs with parameters """ try: # You can see the documents of androguard to get the further details # of the decompilation procedures. # 获取APK文件对象 # application:表示APK对象,在其中可以找到有关 APK 的信息,例如包名、权限、AndroidManifest.xml、resources # application_dex:DalvikVMFormat 对象数组,DalvikVMFormat 对应 apk 文件中的 dex 文件,从 dex 文件中我们可以获取类、方法和字符串。 # application_x:表示 Analysis 对象,其包含链接了关于 classes.dex 信息的特殊的类,甚至可以一次处理许多 dex 文件。 application = APK(path) application_dex = DalvikVMFormat(application.get_dex()) application_x = Analysis(application_dex) # 获得class 对象 classesList = [classes.get_name() for classes in application_dex.get_classes()] # print("classesList:", classesList) # 获得methods方法 for method in application_dex.get_methods(): methodAnalysis = application_x.get_method(method) if method.get_code() is None: continue for basicBlocks in methodAnalysis.get_basic_blocks().get(): # 获得jvm指令 for instructions in basicBlocks.get_instructions(): # 这是一个包含方法,变量或其他任何内容的字符串 output = instructions.get_output() # print("output", output) # Here we use regular expression to check if it is a function # call. A function call comprises four parts: a class name, a # function name, zero or more parameters, and a return type. # The pattern is actually simple: # # CLASS NAME: starts with a character L and ends in a right # arrow. # FUNCTION NAME: starts with the right arrow and ends in a # left parenthesis. # PARAMETERS: are between the parentheses. # RETURN TYPE: is the rest of the string. # # 这里拿到的classList是应用本身的类,第二个匹配的组(一个括号一个组)是调用的类不是应用本身的类,是系统的类 # 这里就是通过系统接口调用来做判断。 match = re.search(r'(L[^;]*;)->[^\(]*\([^\)]*\).*', output) # print("----") # if match: # log(match.group() + "----" + match.group(1), "->" + (match.group(1) not in classesList)) # print(match.group() + "----" + match.group(1), "->", (match.group(1) not in classesList)) # print("isInClassList:", match.group(1), "->", (match.group(1) not in classesList)) # match.group():Landroid/app/IntentService;-><init>(Ljava/lang/String;)V # match.group(1):Landroid/app/IntentService; if match and match.group(1) not in classesList: # print(match.group() + "----" + match.group(1)) methods.add(match.group()) methods = list(methods) except Exception as e: print(e) print("path", path) error_file.write(path) return methods
): # inserisce la virgola fin tanto che non � l'ultimo oggetto toReturn += "," #toReturn += "]\n}" toReturn += "]" return toReturn # cattura del percorso del file apk apkToBeAnalyzed = sys.argv[1] #variabile che rappresenta il file apk a = APK(apkToBeAnalyzed) #variabile che rappresenta il file dex dexFile = DalvikVMFormat(a.get_dex()) #variabile che rappresenta il file dex dopo essere stato analizzato dexAnalyzed = analysis.uVMAnalysis(dexFile) #print a.show() #print "package name " + a.get_package() #print a.get_permissions() #analysis.show_Permissions(dexAnalyzed) #print "\n" # mostra dove vengono usati i permessi permissions = dexAnalyzed.get_permissions([]) permissionDictionary = toDictionary(dexFile, permissions)
from androguard.core.analysis.analysis import VMAnalysis from androguard.core.bytecodes.apk import APK from androguard.core.bytecodes.dvm import DalvikVMFormat from core.analysis import * if __name__ == '__main__': a = APK("1_1.apk") print len(a.get_activities()) print a.get_main_activity() d = DalvikVMFormat(a.get_dex()) dx = VMAnalysis(d) print dx.get_method_signature()
if apkf.get_element('activity', 'exported', name=activity) == 'true': exported_activities.append(activity) else: filters = apkf.get_intent_filters("activity", activity) if len(filters) > 0: exported_activities.append(activity) for receiver in receivers: if apkf.get_element('receiver', 'exported', name=receiver) == 'true': exported_receivers.append(receiver) else: filters = apkf.get_intent_filters("receiver", receiver) if len(filters) > 0: exported_receivers.append(receiver) dexf = DalvikVMFormat(apkf.get_dex()) for item in dexf.get_classes_def_item().get_obj(): if "BroadcastReceiver" in str(item): dynamic_exported_receivers.append(item) for service in services: if apkf.get_element('service', 'exported', name=service) == 'true': exported_services.append(service) else: filters = apkf.get_intent_filters("service", service) if len(filters) > 0: exported_services.append(service) if int(apkf.get_target_sdk_version()) < 17: exported_providers = providers
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"]: return from androguard.core.bytecodes.apk import APK from androguard.core.bytecodes.dvm import DalvikVMFormat from androguard.core.analysis.analysis import uVMAnalysis from androguard.core.analysis import analysis 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() # manifest["permissions"]=a.get_details_permissions_new() 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"]=a.get__extended_receivers() manifest["providers"] = a.get_providers() manifest["libraries"] = a.get_libraries() apkinfo["manifest"] = manifest # apkinfo["certificate"] = a.get_certificate() static_calls = {} if self.check_size(apkinfo["files"]): vm = DalvikVMFormat(a.get_dex()) vmx = uVMAnalysis(vm) static_calls["all_methods"] = self.get_methods(vmx) static_calls[ "is_native_code"] = analysis.is_native_code(vmx) static_calls["is_dynamic_code"] = analysis.is_dyn_code( vmx) static_calls[ "is_reflection_code"] = analysis.is_reflection_code( vmx) # static_calls["dynamic_method_calls"]= analysis.get_show_DynCode(vmx) # static_calls["reflection_method_calls"]= analysis.get_show_ReflectionCode(vmx) # static_calls["permissions_method_calls"]= analysis.get_show_Permissions(vmx) # static_calls["crypto_method_calls"]= analysis.get_show_CryptoCode(vmx) # static_calls["native_method_calls"]= analysis.get_show_NativeMethods(vmx) else: log.warning("Dex size bigger than: %s", self.options.decompilation_threshold) apkinfo["static_method_calls"] = static_calls except (IOError, OSError, zipfile.BadZipfile) as e: raise CuckooProcessingError("Error opening file %s" % e) return apkinfo
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 analyze_dex(filepath_or_raw, needs_dalvik_vm_format=True, needs_vm_analysis=True, needs_gvm_analysis=True, needs_xref=True, needs_dref=True, raw=False, decompiler="dad"): ''' Open the classes.dex file `needs_dalvik_vm_format` and set up an analyzer for it `needs_vm_analysis`. Parameters ---------- filepath_or_raw : path to file or raw data Set raw to True if `filepath_or_raw` is raw data. needs_dalvik_vm_format : bool, optional (default is True) needs_vm_analysis : bool, optional (default is True) needs_gvm_analysis : bool, optional (default is True) needs_xref : bool, optional (default is True) needs_dref : bool, optional (default is True) raw : bool, optional (default is False) decompiler : str, optional (default is "dad") Returns ------- tuple<DalvikVMFormat, VMAnalysis, GVMAnalysis> Raises ------ DexError If an error occurred while creating the analysis objects. ''' dalvik_vm_format, vm_analysis, gvm_analysis = None, None, None # every requirement implies the need for the `dalvik_vm_format` needs_dalvik_vm_format = any((needs_dalvik_vm_format, needs_vm_analysis, needs_gvm_analysis, needs_xref, needs_dref)) cross_ref = any((needs_xref, needs_dref)) try: if needs_dalvik_vm_format: if raw == False: with open(filepath_or_raw, "rb") as f: dalvik_vm_format = DalvikVMFormat(f.read()) else: dalvik_vm_format = DalvikVMFormat(filepath_or_raw) if needs_vm_analysis or cross_ref or needs_gvm_analysis: vm_analysis = uVMAnalysis(dalvik_vm_format) dalvik_vm_format.set_vmanalysis(vm_analysis) if needs_gvm_analysis or cross_ref: gvm_analysis = GVMAnalysis(vm_analysis, None) dalvik_vm_format.set_gvmanalysis(gvm_analysis) if dalvik_vm_format: RunDecompiler(dalvik_vm_format, vm_analysis, decompiler) # create references, gvm_analysis needed! # we optimize through not exporting the references into the python objects if needs_xref: dalvik_vm_format.create_xref(python_export = False) if needs_dref: dalvik_vm_format.create_dref(python_export = False) except Exception as e: # androguard caused error -> propagate as DexError raise DexError(caused_by = e), None, sys.exc_info()[2] return dalvik_vm_format, vm_analysis, gvm_analysis
class Run(Lobotomy): def __init__(self): Lobotomy.__init__(self) self.t = Terminal() self.logger = Logger() self.util = Util() self.apk = None self.package = None self.vm = None self.vmx = None self.gmx = None self.components = None self.dex = None self.strings = None self.permissions = None self.permissions_details = None self.files = None self.attack_surface = None def find_dex(self): """ Return True is classes.dex is found within the target APK. Args: None Returns: None """ if self.files: for f in self.files: if "classes" in f: return True break def process_vm(self): """ Process the application's classes.dex Args: None Results: None """ # Make sure classes.dex exists if self.find_dex(): self.dex = self.apk.get_dex() # Analyze classes.dex # TODO Throw in a progress bar, this can take awhile if self.dex: self.logger.log("info", "Loading classes.dex ...") from androguard.core.bytecodes.dvm import DalvikVMFormat from androguard.core.analysis.analysis import VMAnalysis from androguard.core.analysis.ganalysis import GVMAnalysis # Create a new virtual machine instance self.vm = DalvikVMFormat(self.dex) if self.vm: print(self.t.yellow("\n\t--> Loaded classes.dex (!)\n")) self.logger.log("info", "Analyzing classes.dex ...") # Analyze the virtual machine instance self.vmx = VMAnalysis(self.vm) self.gmx = GVMAnalysis(self.vmx, None) if self.vmx and self.gmx: print(self.t.yellow("\n\t--> Analyzed classes.dex (!)\n")) self.vm.set_vmanalysis(self.vmx) self.vm.set_gvmanalysis(self.gmx) # Generate xref(s) self.vm.create_xref() self.vm.create_dref() else: CommandError("Cannot analyze VM instance (!)") else: CommandError("Cannot load VM instance (!)") else: CommandError("classes.dex not found (!)") def do_operate(self, args): """ := operate apk path_to_apk := operate dex path_to_classes.dex """ try: if args.split()[0] == "apk": if args.split()[1]: self.logger.log("info", "Loading : {} ...".format(args.split()[1].split("/")[-1])) from androguard.core.bytecodes.apk import APK self.apk = APK(args.split()[1]) if self.apk: print(self.t.yellow("\n\t--> Loaded : {} (!)\n".format(args.split()[1].split("/")[-1]))) self.package = self.apk.get_package() from core.brains.apk.components import Components # Load activies, services, broadcast receivers, and # content providers self.components = Components(self.apk) self.components.enumerate_components() self.permissions = self.apk.get_permissions() self.files = self.apk.get_files() self.files_type = self.apk.get_files_types() # Process virtual machine self.process_vm() else: CommandError("APK not loaded (!)") else: CommandError("Unkown command (!)") except ImportError as e: CommandError(e.message) except IndexError as e: CommandError("Not enough arguments (!)") def do_surgical(self, args): """ := surgical """ try: if self.vm and self.vmx: from .surgical import Run run = Run(self.vm, self.vmx) run.prompt = self.t.yellow("(surgical) ") run.ruler = self.t.yellow("-") run.cmdloop() else: CommandError("classes.dex not loaded (!)") except Exception as e: CommandError(e.message) def do_attacksurface(self, args): """ := attacksurface """ try: if self.apk and self.components: self.logger.log("info", "Loading attacksurface module ...") from core.brains.apk.attacksurface import AttackSurface self.attack_surface = AttackSurface(self.apk, self.components) self.attack_surface.run() except ImportError as e: CommandError(e.message) def do_permissions(self, args): """ := permissions list """ try: if self.permissions: if args.split()[0] == "list": self.logger.log("info", "Loading permissions ... \n") for p in self.permissions: print(self.t.yellow("\t--> {}".format(p))) print("\n") else: CommandError("Permissions not found (!)") except Exception as e: CommandError(e.message) def do_files(self, args): """ := files all := files assets := files libs := files res """ try: if self.files: if args.split()[0]: if args.split()[0] == "assets": self.logger.log("info", "Loading files ... \n") for f in self.files: if f.startswith("assets"): print(self.t.yellow("\t--> {}".format(f))) print("\n") elif args.split()[0] == "libs": self.logger.log("info", "Loading files ... \n") for f in self.files: if f.startswith("lib"): print(self.t.yellow("\t--> {}".format(f))) print("\n") elif args.split()[0] == "res": self.logger.log("info", "Loading files ... \n") for f in self.files: if f.startswith("res"): print(self.t.yellow("\t--> {}".format(f))) print("\n") elif args.split()[0] == "all": self.logger.log("info", "Loading files ... \n") for f in self.files: print(self.t.yellow("\t--> {}".format(f))) print("\n") else: CommandError("Files not populated (!)") except Exception as e: CommandError(e.message) def do_strings(self, args): """ List and search for strings found in classes.dex := strings list := strings search """ # Locals strings = None try: if args.split()[0] == "list": if self.vm: strings = self.vm.get_strings() if strings: for s in strings: print(self.t.cyan("--> {}".format(s.encode("utf-8")))) else: CommandError("Strings not found (!)") else: CommandError("classes.dex not loaded (!)") elif args.split()[0] == "search": if self.vm: strings = self.vm.get_strings() if strings: target = raw_input(self.t.yellow("\n\t--> Enter string : \n")) for s in strings: if target in s: print(self.t.cyan("\t\t --> {}".format(s))) print("\n") else: CommandError("Strings not found (!)") else: CommandError("classes.dex not loaded (!)") else: CommandError("Command not found (!)") except Exception as e: # We might be see an exception like this: # 'utf8' codec can't decode byte 0xc0 in position 0: invalid start byte raise e CommandError(e.message) def do_components(self, args): """ := components list """ try: if args.split()[0] == "list": if self.apk: self.logger.log("info", "Enumerating components ...\n") if self.components.activities: for a in self.components.activities: print(self.t.yellow("\t--> activity : {}".format(a))) print("\n") if self.components.services: for s in self.components.services: print(self.t.yellow("\t--> service : {}".format(s))) print("\n") if self.components.receivers: for r in self.components.receivers: print(self.t.yellow("\t--> receiver : {}".format(s))) print("\n") if self.components.providers: for r in self.components.providers: print(self.t.yellow("\t--> provider : {}".format(s))) print("\n") else: CommandError("APK not loaded (!)") else: CommandError("Command not found (!)") except Exception as e: CommandError(e.message) def do_interact(self, args): """ Drop into an interactive IPython session. := interact """ try: if self.vm and self.vmx: from core.brains.interact.interact import Interact i = Interact(self.vm, self.vmx) i.run() else: CommandError("classes.dex not loaded (!)") except Exception as e: CommandError(e.message) def do_macro(self, args): """ """ return
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
class Run(Lobotomy): def __init__(self, ROOT_DIR): Lobotomy.__init__(self) self.ROOT_DIR = ROOT_DIR self.t = Terminal() self.logger = Logger() self.util = Util() self.apk = None self.package = None self.vm = None self.vmx = None self.gmx = None self.components = None self.dex = None self.strings = None self.permissions = None self.permissions_details = None self.files = None self.attack_surface = None def find_dex(self): """ Return True is classes.dex is found within the target APK. Args: None Returns: None """ if self.files: for f in self.files: if "classes" in f: return True break def process_vm(self, apk=False, dex=False): """ Process the application's classes.dex Args: param1 = boolean param2 = boolean Results: None """ try: if apk: # Make sure the APK contains a classes.dex file if self.find_dex(): self.dex = self.apk.get_dex() if self.dex: self.logger.log("info", "Loading classes.dex ...") from androguard.core.bytecodes.dvm import DalvikVMFormat from androguard.core.analysis.analysis import VMAnalysis from androguard.core.analysis.ganalysis import GVMAnalysis # Create a DalvikVMFormat instance ... # In this case self.dex will be a file type self.vm = DalvikVMFormat(self.dex) if self.vm: print(self.t.yellow("\n\t--> Loaded classes.dex (!)\n")) self.logger.log("info", "Analyzing classes.dex ...") # Analyze the DalvikVMFormat instance and return # analysis instances of VMAnalysis and GVMAnalysis self.vmx = VMAnalysis(self.vm) self.gmx = GVMAnalysis(self.vmx, None) if self.vmx and self.gmx: print(self.t.yellow("\n\t--> Analyzed classes.dex (!)\n")) # Set the analysis properties on the # DalvikVMFormat instance self.vm.set_vmanalysis(self.vmx) self.vm.set_gvmanalysis(self.gmx) # Generate xref(s) and dref(s) self.vm.create_xref() self.vm.create_dref() return else: CommandError("process_vm : Cannot analyze VM instance (!)") return else: CommandError("process_vm : Cannot load VM instance (!)") return else: CommandError("process_vm : classes.dex not found (!)") return if dex: if self.dex: from androguard.core.bytecodes.dvm import DalvikVMFormat from androguard.core.analysis.analysis import VMAnalysis from androguard.core.analysis.ganalysis import GVMAnalysis # Analyze the DalvikVMFormat instance and return # analysis instances of VMAnalysis and GVMAnalysis self.vm = DalvikVMFormat(self.util.read(self.dex)) if self.vm: print(self.t.yellow("\n\t--> Loaded {} (!)\n" .format(self.dex .split("/")[-1]))) self.logger.log("info", "Analyzing {} ..." .format(self.dex .split("/")[-1])) # Set the analysis properties on the # DalvikVMFormat instance self.vmx = VMAnalysis(self.vm) self.gmx = GVMAnalysis(self.vmx, None) if self.vmx and self.gmx: print(self.t.yellow("\n\t--> Analyzed {} (!)\n" .format(self.dex .split("/")[-1]))) # Set the analysis properties on the # DalvikVMFormat instance self.vm.set_vmanalysis(self.vmx) self.vm.set_gvmanalysis(self.gmx) # Generate xref(s) and dref(s) self.vm.create_xref() self.vm.create_dref() return else: CommandError("process_vm :" + "Cannot analyze VM instance (!)") return else: CommandError("process_vm :" + "Cannot load VM instance (!)") return else: CommandError("process_vm : classes.dex not found (!)") return except Exception as e: CommandError("process_vm : {}".format(e)) def do_operate(self, args): """ := operate apk path_to_apk := operate dex path_to_classes.dex """ try: if args.split()[0] == "apk": if args.split()[1]: self.logger.log("info", "Loading : {} ..." .format(args.split()[1].split("/")[-1])) from androguard.core.bytecodes.apk import APK self.apk = APK(args.split()[1]) if self.apk: print(self.t.yellow("\n\t--> Loaded : {} (!)\n" .format(args.split()[1] .split("/")[-1]))) self.package = self.apk.get_package() from core.brains.apk.components import Components # Load activies, services, broadcast receivers, and # content providers self.components = Components(self.apk) self.components.enumerate_components() self.permissions = self.apk.get_permissions() self.files = self.apk.get_files() self.files_type = self.apk.get_files_types() # Process DVM self.process_vm(apk=True) else: CommandError("APK not loaded (!)") elif args.split()[0] == "dex": self.logger.log("info", "Loading : {} ..." .format(args.split()[1].split("/")[-1])) if args.split()[1]: self.dex = args.split()[1] # Process DVM self.process_vm(dex=True) else: CommandError("Unkown command (!)") except ImportError as e: CommandError(e.message) except IndexError as e: CommandError("Not enough arguments (!)") def do_surgical(self, args): """ := surgical """ try: if self.vm and self.vmx: from .surgical import Run run = Run(self.vm, self.vmx) run.prompt = self.t.yellow("(surgical) ") run.ruler = self.t.yellow("-") run.cmdloop() else: CommandError("classes.dex not loaded (!)") except Exception as e: CommandError(e.message) def do_attacksurface(self, args): """ := attacksurface """ try: if self.apk and self.components: self.logger.log("info", "Loading attacksurface module ...") from core.brains.apk.attacksurface import AttackSurface self.attack_surface = AttackSurface(self.apk, self.components) self.attack_surface.run() # Helps with visual spacing after the results are printed print("\n") except ImportError as e: CommandError(e.message) def do_permissions(self, args): """ := permissions list """ try: if self.permissions: if args.split()[0] == "list": self.logger.log("info", "Loading permissions ... \n") for p in self.permissions: print(self.t.yellow("\t--> {}".format(p))) print("\n") else: CommandError("Permissions not found (!)") except Exception as e: CommandError(e.message) def do_binja(self, args): """ := binja """ rpc = None functions = None try: import xmlrpclib rpc = xmlrpclib.ServerProxy('http://localhost:6666/lobotomy') functions = rpc.jni() if functions: self.logger.log("info", "Found JNI methods (!)") print("\n") for f in functions: print(self.t.cyan("\t--> {}".format(f))) print("\n") else: self.logger.info("Registered JNI functions not found (!)") except Exception as e: CommandError("binja : {}".format(e)) def do_files(self, args): """ := files all := files assets := files libs := files res """ try: if self.files: if args.split()[0]: if args.split()[0] == "assets": self.logger.log("info", "Loading files ... \n") for f in self.files: if f.startswith("assets"): print(self.t.yellow("\t--> {}".format(f))) print("\n") elif args.split()[0] == "libs": self.logger.log("info", "Loading files ... \n") for f in self.files: if f.startswith("lib"): print(self.t.yellow("\t--> {}".format(f))) print("\n") elif args.split()[0] == "res": self.logger.log("info", "Loading files ... \n") for f in self.files: if f.startswith("res"): print(self.t.yellow("\t--> {}".format(f))) print("\n") elif args.split()[0] == "all": self.logger.log("info", "Loading files ... \n") for f in self.files: print(self.t.yellow("\t--> {}".format(f))) print("\n") else: CommandError("Files not populated (!)") except Exception as e: CommandError(e.message) def do_strings(self, args): """ List and search for strings found in classes.dex := strings list := strings search """ # Locals strings = None try: if args.split()[0] == "list": if self.vm: strings = self.vm.get_strings() if strings: for s in strings: print(self.t.cyan("--> {}" .format(s.encode("utf-8")))) else: CommandError("Strings not found (!)") else: CommandError("classes.dex not loaded (!)") elif args.split()[0] == "search": if self.vm: strings = self.vm.get_strings() if strings: target = raw_input(self.t.yellow("\n\t--> Enter string : ")) for s in strings: if target in s: print(self.t.cyan("\t\t --> {}".format(s))) print("\n") else: CommandError("Strings not found (!)") else: CommandError("classes.dex not loaded (!)") else: CommandError("Command not found (!)") except Exception as e: # We might be see an exception like this: # 'utf8' codec can't decode byte 0xc0 in position 0: # invalid start byte raise e CommandError(e.message) def do_components(self, args): """ := components list """ try: if args.split()[0] == "list": if self.apk: self.logger.log("info", "Enumerating components ...\n") if self.components.activities: for a in self.components.activities: print(self.t.yellow("\t--> activity : {}" .format(a))) print("\n") if self.components.services: for s in self.components.services: print(self.t.yellow("\t--> service : {}" .format(s))) print("\n") if self.components.receivers: for r in self.components.receivers: print(self.t.yellow("\t--> receiver : {}" .format(r))) print("\n") if self.components.providers: for r in self.components.providers: print(self.t.yellow("\t--> provider : {}" .format(s))) print("\n") else: CommandError("APK not loaded (!)") else: CommandError("Command not found (!)") except Exception as e: CommandError(e.message) def do_interact(self, args): """ Drop into an interactive IPython session. := interact """ try: if self.vm and self.vmx: from core.brains.interact.interact import Interact i = Interact(self.vm, self.vmx) i.run() else: CommandError("classes.dex not loaded (!)") except Exception as e: CommandError(e.message) def do_class_tree(self, args): """ := class_tree """ try: if self.vm: for c in self.vm.get_classes(): print("\n") print(self.t.yellow("\t--> class : {}".format(c.name))) for f in c.get_fields(): print(self.t.white("\t\t--> field : {}".format(f.name))) for m in c.get_methods(): print(self.t.cyan("\t\t\t--> method : {}".format(m.name))) print("\n") else: CommandError("class_tree : classes.dex not loaded (!)") except Exception as e: CommandError("class_tree : {}".format(e)) def do_native(self, args): """ := native """ native_methods = list() try: if self.vm: for method in self.vm.get_methods(): if method.get_access_flags() & 0x100: native_methods.append((method.get_class_name(), method.get_name())) if native_methods: print("\n") for n in native_methods: print(self.t.cyan("\t--> {} : {}".format(n[0], n[1]))) print("\n") else: self.logger.log("info", "class_tree : classes.dex not loaded (!)") except Exception as e: CommandError("native : {}".format(e)) def do_ui(self, args): """ := ui """ try: if self.vm and self.vmx: from core.brains.ui.terminal import TerminalApp ui = TerminalApp(self.vm, self.vmx) ui.run() except Exception as e: CommandError("ui : {}".format(e)) def do_macro(self, args): """ := macro """ # Locals directory_items = None macro = path.join(self.ROOT_DIR, "macro") selection = None apk_path = None json = None try: print("\n") directory_items = listdir(macro) for i in range(0, len(directory_items)): print(self.t.cyan("\t--> [{}] {}" .format(i, directory_items[i]))) print("\n") selection = raw_input(self.t.yellow("\t--> Select config : ")) print("\n") if selection: for f in directory_items: if selection == f: with open("".join([macro, "/", f]), "rb") as config: # Load the config as JSON json = loads(config.read()) if json: for k, v in json.items(): if k == "apk": if v: apk_path = str(v) # Call operate() with the path to # apk self.do_operate("apk {}" .format(apk_path)) return else: CommandError("macro : Path to APK not found in {}" .format(selection)) else: CommandError("macro : Error loading {} as JSON" .format(selection)) except Exception as e: CommandError("macro : {}".format(e))
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"] = 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 = uVMAnalysis(vm) static_calls["all_methods"] = get_methods(vmx) static_calls["is_native_code"] = analysis.is_native_code(vmx) static_calls["is_dynamic_code"] = analysis.is_dyn_code(vmx) static_calls["is_reflection_code"] = analysis.is_reflection_code(vmx) static_calls["is_crypto_code"] = is_crypto_code(vmx) static_calls["dynamic_method_calls"] = get_show_DynCode(vmx) static_calls["reflection_method_calls"] = get_show_ReflectionCode(vmx) static_calls["permissions_method_calls"] = get_show_Permissions(vmx) static_calls["crypto_method_calls"] = get_show_CryptoCode(vmx) static_calls["native_method_calls"] = get_show_NativeMethods(vmx) classes = list() for cls in vm.get_classes(): classes.append(cls.name) static_calls["classes"] = classes else: log.warning("Dex size bigger than: %s", self.options.decompilation_threshold) apkinfo["static_method_calls"] = static_calls except (IOError, OSError, BadZipfile) as e: raise CuckooProcessingError("Error opening file %s" % e) return apkinfo
def main(): for path in samples(): print(path) logging.error("Processing" + path) tests_apk = [ "is_valid_APK", "get_filename", "get_app_name", "get_app_icon", "get_package", "get_androidversion_code", "get_androidversion_name", "get_files", "get_files_types", "get_files_crc32", "get_files_information", "get_raw", "get_dex", "get_all_dex", "get_main_activity", "get_activities", "get_services", "get_receivers", "get_providers", "get_permissions", "get_details_permissions", "get_requested_aosp_permissions", "get_requested_aosp_permissions_details", "get_requested_third_party_permissions", "get_declared_permissions", "get_declared_permissions_details", "get_max_sdk_version", "get_min_sdk_version", "get_target_sdk_version", "get_libraries", "get_android_manifest_axml", "get_android_manifest_xml", "get_android_resources", "get_signature_name", "get_signature_names", "get_signature", "get_signatures" ] tests_dex = [ "get_api_version", "get_classes_def_item", "get_methods_id_item", "get_fields_id_item", "get_codes_item", "get_string_data_item", "get_debug_info_item", "get_header_item", "get_class_manager", "show", # "save", # FIXME broken "get_classes_names", "get_classes", "get_all_fields", "get_fields", "get_methods", "get_len_methods", "get_strings", "get_format_type", "create_python_export", "get_BRANCH_DVM_OPCODES", "get_determineNext", "get_determineException", "print_classes_hierarchy", "list_classes_hierarchy", "get_format" ] try: # Testing APK a = APK(path) for t in tests_apk: print(t) x = getattr(a, t) try: x() except Exception as aaa: print(aaa) traceback.print_exc() print(path, aaa, file=sys.stderr) logging.exception("{} .. {}".format(path, t)) # Testing DEX dx = Analysis() for dex in a.get_all_dex(): d = DalvikVMFormat(dex) dx.add(d) # Test decompilation for c in d.get_classes(): for m in c.get_methods(): mx = dx.get_method(m) ms = DvMethod(mx) try: ms.process(doAST=True) except Exception as aaa: print(aaa) traceback.print_exc() print(path, aaa, file=sys.stderr) logging.exception("{} .. {} .. {}".format( path, c.get_name(), m.get_name())) ms2 = DvMethod(mx) try: ms2.process(doAST=False) except Exception as aaa: print(aaa) traceback.print_exc() print(path, aaa, file=sys.stderr) logging.exception("{} .. {} .. {}".format( path, c.get_name(), m.get_name())) # DEX tests for t in tests_dex: print(t) x = getattr(d, t) try: x() except Exception as aaa: print(aaa) traceback.print_exc() print(path, aaa, file=sys.stderr) logging.exception("{} .. {}".format(path, t)) # Analysis Tests try: dx.create_xref() except Exception as aaa: print(aaa) traceback.print_exc() print(path, aaa, file=sys.stderr) logging.exception("{} .. {} at Analysis".format(path, t)) # MethodAnalysis tests for m in dx.methods.values(): for bb in m.get_basic_blocks(): try: list(bb.get_instructions()) except Exception as aaa: print(aaa) traceback.print_exc() print(path, aaa, file=sys.stderr) logging.exception("{} .. {} at BasicBlock {}".format( path, t, m)) except KeyboardInterrupt: raise except FileNotFoundError: pass except Exception as e: print(e) traceback.print_exc() print(path, e, file=sys.stderr) logging.exception(path)
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))
class PDG(): def __init__(self, filename): """ :type self: object """ self.filename = filename try: self.a = APK(filename) self.d = DalvikVMFormat(self.a.get_dex()) self.d.create_python_export() self.dx = Analysis(self.d) except zipfile.BadZipfile: # if file is not an APK, may be a dex object _, self.d, self.dx = AnalyzeDex(self.filename) self.d.set_vmanalysis(self.dx) self.dx.create_xref() self.fcg = self.dx.get_call_graph() self.icfg = self.build_icfg() def get_graph(self): return self.icfg def build_icfg(self): icfg = nx.DiGraph() methods = self.d.get_methods() for method in methods: for bb in self.dx.get_method(method).basic_blocks.get(): children = [] label = self.get_bb_label(bb) children = self.get_children(bb, self.dx) icfg.add_node(label) icfg.add_edges_from([(label, child) for child in children]) return icfg def get_bb_label(self, bb): """ Return the descriptive name of a basic block """ return self.get_method_label(bb.method) + (bb.name, ) def get_method_label(self, method): """ Return the descriptive name of a method """ return (method.get_class_name(), method.get_name(), method.get_descriptor()) def get_children(self, bb, dx): """ Return the labels of the basic blocks that are children of the input basic block in and out of its method """ return self.get_bb_intra_method_children( bb) + self.get_bb_extra_method_children(bb, dx) def get_bb_intra_method_children(self, bb): """ Return the labels of the basic blocks that are children of the input basic block within a method """ child_labels = [] for c_in_bb in bb.get_next(): next_bb = c_in_bb[2] child_labels.append(self.get_bb_label(next_bb)) return child_labels def get_bb_extra_method_children(self, bb, dx): """ Given a basic block, find the calls to external methods and return the label of the first basic block in these methods """ call_labels = [] # iterate over calls from bb method to external methods try: xrefs = dx.get_method_analysis(bb.method).get_xref_to() except AttributeError: return call_labels for xref in xrefs: remote_method_offset = xref[2] if self.call_in_bb(bb, remote_method_offset): try: remote_method = dx.get_method( self.d.get_method_by_idx(remote_method_offset)) if remote_method: remote_bb = next(remote_method.basic_blocks.get()) call_labels.append(self.get_bb_label(remote_bb)) except StopIteration: pass return call_labels def call_in_bb(self, bb, idx): return bb.get_start() <= idx <= bb.get_end()
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) apkinfo["APKiD"] = self._scan_APKiD(self.file_path) try: a = APK(self.file_path) if a.is_valid_APK(): manifest = {} apkinfo["files"] = self._apk_files(a) apkinfo["encrypted_assets"] = self.find_encrypted_assets(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["receivers_info"] = get_receivers_info(a) manifest["providers"] = a.get_providers() manifest["libraries"] = 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) for subdir, dirs, files in os.walk(self.dropped_path): for file in files: path = os.path.join(subdir, file) try: extra_strings = self._get_strings(path) strings = list(set(extra_strings + strings)) except: pass apkinfo["dex_strings"] = strings static_calls = {} if self.options.decompilation: if self.check_size(apkinfo["files"]): vm = DalvikVMFormat(a.get_dex()) vmx = uVMAnalysis(vm) # Be less verbose about androguard logging messages. logging.getLogger("andro.runtime").setLevel(logging.CRITICAL) static_calls["all_methods"] = get_methods(vmx) static_calls["is_native_code"] = analysis.is_native_code(vmx) static_calls["is_dynamic_code"] = analysis.is_dyn_code(vmx) static_calls["is_reflection_code"] = analysis.is_reflection_code(vmx) static_calls["is_crypto_code"] = is_crypto_code(vmx) static_calls["dynamic_method_calls"] = get_show_DynCode(vmx) static_calls["reflection_method_calls"] = get_show_ReflectionCode(vmx) static_calls["permissions_method_calls"] = get_show_Permissions(vmx) static_calls["crypto_method_calls"] = get_show_CryptoCode(vmx) static_calls["native_method_calls"] = get_show_NativeMethods(vmx) classes = list() for cls in vm.get_classes(): classes.append(cls.name) static_calls["classes"] = classes else: log.warning("Dex size bigger than: %s", self.options.decompilation_threshold) apkinfo["static_method_calls"] = static_calls except (IOError, OSError, BadZipfile) as e: raise CuckooProcessingError("Error opening file %s" % e) return apkinfo
class Run(Lobotomy): def __init__(self, ROOT_DIR): Lobotomy.__init__(self) self.ROOT_DIR = ROOT_DIR self.t = Terminal() self.logger = Logger() self.util = Util() self.apk = None self.package = None self.vm = None self.vmx = None self.gmx = None self.components = None self.dex = None self.strings = None self.permissions = None self.permissions_details = None self.files = None self.attack_surface = None def _cmd_completer(self, name, text, line, begidx, endidx): fn = getattr(self, 'do_'+name) if not hasattr(fn.im_func, "_expected_args"): return [] a = [arg for arg in fn.im_func._expected_args if arg.startswith(text)] return a def find_dex(self): """ Return True is classes.dex is found within the target APK. Args: None Returns: None """ if self.files: for f in self.files: if "classes" in f: return True break def process_vm(self, apk=False, dex=False): """ Process the application's classes.dex Args: param1 = boolean param2 = boolean Results: None """ try: if apk: # Make sure the APK contains a classes.dex file if self.find_dex(): self.dex = self.apk.get_dex() if self.dex: self.logger.log("info", "Loading classes.dex ...") from androguard.core.bytecodes.dvm import DalvikVMFormat from androguard.core.analysis.analysis import VMAnalysis from androguard.core.analysis.ganalysis import GVMAnalysis # Create a DalvikVMFormat instance ... # In this case self.dex will be a file type self.vm = DalvikVMFormat(self.dex) if self.vm: print(self.t.yellow("\n\t--> Loaded classes.dex (!)\n")) self.logger.log("info", "Analyzing classes.dex ...") # Analyze the DalvikVMFormat instance and return # analysis instances of VMAnalysis and GVMAnalysis self.vmx = VMAnalysis(self.vm) self.gmx = GVMAnalysis(self.vmx, None) if self.vmx and self.gmx: print(self.t.yellow("\n\t--> Analyzed classes.dex (!)\n")) # Set the analysis properties on the # DalvikVMFormat instance self.vm.set_vmanalysis(self.vmx) self.vm.set_gvmanalysis(self.gmx) # Generate xref(s) and dref(s) self.vm.create_xref() self.vm.create_dref() return else: CommandError("process_vm : Cannot analyze VM instance (!)") return else: CommandError("process_vm : Cannot load VM instance (!)") return else: CommandError("process_vm : classes.dex not found (!)") return if dex: if self.dex: from androguard.core.bytecodes.dvm import DalvikVMFormat from androguard.core.analysis.analysis import VMAnalysis from androguard.core.analysis.ganalysis import GVMAnalysis # Analyze the DalvikVMFormat instance and return # analysis instances of VMAnalysis and GVMAnalysis self.vm = DalvikVMFormat(self.util.read(self.dex)) if self.vm: print(self.t.yellow("\n\t--> Loaded {} (!)\n" .format(self.dex .split("/")[-1]))) self.logger.log("info", "Analyzing {} ..." .format(self.dex .split("/")[-1])) # Set the analysis properties on the # DalvikVMFormat instance self.vmx = VMAnalysis(self.vm) self.gmx = GVMAnalysis(self.vmx, None) if self.vmx and self.gmx: print(self.t.yellow("\n\t--> Analyzed {} (!)\n" .format(self.dex .split("/")[-1]))) # Set the analysis properties on the # DalvikVMFormat instance self.vm.set_vmanalysis(self.vmx) self.vm.set_gvmanalysis(self.gmx) # Generate xref(s) and dref(s) self.vm.create_xref() self.vm.create_dref() return else: CommandError("process_vm :" + "Cannot analyze VM instance (!)") return else: CommandError("process_vm :" + "Cannot load VM instance (!)") return else: CommandError("process_vm : classes.dex not found (!)") return except Exception as e: CommandError("process_vm : {}".format(e)) def complete_operate(self, *args): return self._cmd_completer("operate", *args) @cmd_arguments(["apk", "dex"]) def do_operate(self, *args): """ := operate apk path_to_apk := operate dex path_to_classes.dex """ # Locals arg0 = args[0].split(" ")[0] arg1 = args[0].split(" ")[1] try: if arg0 == "apk": if arg1: self.logger.log("info", "Loading : {} ..." .format(arg1.split("/")[-1])) from androguard.core.bytecodes.apk import APK self.apk = APK(arg1) if self.apk: print(self.t.yellow("\n\t--> Loaded : {} (!)\n" .format(arg1.split("/")[-1]))) self.package = self.apk.get_package() from core.brains.apk.components import Components # Load activies, services, broadcast receivers, and # content providers self.components = Components(self.apk) self.components.enumerate_components() self.permissions = self.apk.get_permissions() self.files = self.apk.get_files() self.files_type = self.apk.get_files_types() # Process DVM self.process_vm(apk=True) else: CommandError("APK not loaded (!)") elif arg0 == "dex": if arg1: self.logger.log("info", "Loading : {} ..." .format(arg1.split("/")[-1])) self.dex = arg1 self.process_vm(dex=True) except ImportError as e: CommandError("operate : {}".format(e)) def complete_surgical(self, *args): return self._cmd_completer("surgical", *args) def do_surgical(self, *args): """ := surgical """ try: if self.vm and self.vmx: from .surgical import Run run = Run(self.vm, self.vmx) run.prompt = self.t.yellow("(surgical) ") run.ruler = self.t.yellow("-") run.cmdloop() else: CommandError("classes.dex not loaded (!)") except Exception as e: CommandError("surgical : {}".format(e)) def complete_attacksurface(self, *args): return self._cmd_completer("attacksurface", *args) def do_attacksurface(self, *args): """ := attacksurface """ try: if self.apk and self.components: self.logger.log("info", "Loading attacksurface module ...") from core.brains.apk.attacksurface import AttackSurface self.attack_surface = AttackSurface(self.apk, self.components) self.attack_surface.run() # Helps with visual spacing after the results are printed print("\n") except ImportError as e: CommandError("attacksurface : {}".format(e)) def complete_permissions(self, *args): return self._cmd_completer("permissions", *args) @cmd_arguments(["list"]) def do_permissions(self, *args): """ := permissions list """ # Locals arg0 = args[0] try: if self.permissions: if args[0] == "list": self.logger.log("info", "Loading permissions ... \n") for p in self.permissions: print(self.t.yellow("\t--> {}".format(p))) print("\n") else: CommandError("Permissions not found (!)") except Exception as e: CommandError("permissions : {}".format(e)) def complete_binja(self, *args): return self._cmd_completer("binja", *args) def do_binja(self, *args): """ := binja """ try: from .binja import Run run = Run(self.files, self.apk) run.prompt = self.t.cyan("(binja) ") run.ruler = self.t.cyan("-") run.cmdloop() except Exception as e: CommandError("binja : {}".format(e)) def complete_files(self, *args): return self._cmd_completer("files", *args) @cmd_arguments(["all", "assets", "libs", "res"]) def do_files(self, *args): """ := files all := files assets := files libs := files res """ # Locals arg0 = args[0] try: if self.files: if arg0 == "assets": self.logger.log("info", "Loading files ... \n") for f in self.files: if f.startswith("assets"): print(self.t.yellow("\t--> {}".format(f))) print("\n") elif arg0 == "libs": self.logger.log("info", "Loading files ... \n") for f in self.files: if f.startswith("lib"): print(self.t.yellow("\t--> {}".format(f))) print("\n") elif arg0 == "res": self.logger.log("info", "Loading files ... \n") for f in self.files: if f.startswith("res"): print(self.t.yellow("\t--> {}".format(f))) print("\n") elif arg0 == "all": self.logger.log("info", "Loading files ... \n") for f in self.files: print(self.t.yellow("\t--> {}".format(f))) print("\n") else: CommandError("Files not populated (!)") except Exception as e: CommandError("files : {}".format(e)) def complete_strings(self, *args): return self._cmd_completer("strings", *args) @cmd_arguments(["list", "search"]) def do_strings(self, *args): """ List and search for strings found in classes.dex := strings list := strings search """ # Locals arg0 = args[0] strings = None try: if arg0 == "list": if self.vm: strings = self.vm.get_strings() if strings: for s in strings: print(self.t.cyan("--> {}".format(s.encode("utf-8", errors="ignore")))) else: CommandError("Strings not found (!)") else: CommandError("classes.dex not loaded (!)") elif arg0 == "search": if self.vm: strings = self.vm.get_strings() if strings: target = raw_input(self.t.yellow("\n\t--> Enter string : ")) for s in strings: if target in s: print(self.t.cyan("\t\t --> {}".format(s.encode("utf-8", errors="ignore")))) print("\n") else: CommandError("Strings not found (!)") else: CommandError("classes.dex not loaded (!)") except Exception as e: CommandError("strings : {}".format(e)) def complete_components(self, *args): return self._cmd_completer("components", *args) @cmd_arguments(["list"]) def do_components(self, *args): """ := components list """ # Locals arg0 = args[0] try: if arg0 == "list": if self.apk: self.logger.log("info", "Enumerating components ...\n") if self.components.activities: for a in self.components.activities: print(self.t.yellow("\t--> activity : {}" .format(a))) print("\n") if self.components.services: for s in self.components.services: print(self.t.yellow("\t--> service : {}" .format(s))) print("\n") if self.components.receivers: for r in self.components.receivers: print(self.t.yellow("\t--> receiver : {}" .format(r))) print("\n") if self.components.providers: for r in self.components.providers: print(self.t.yellow("\t--> provider : {}" .format(s))) print("\n") else: CommandError("APK not loaded (!)") except Exception as e: CommandError("components : {}".format(e)) def complete_interact(self, *args): return self._cmd_completer("interact", *args) def do_interact(self, *args): """ Drop into an interactive IPython session. := interact """ try: if self.vm and self.vmx: from core.brains.interact.interact import Interact i = Interact(self.vm, self.vmx) i.run() else: CommandError("classes.dex not loaded (!)") except Exception as e: CommandError("interact : {}".format(e.message)) def complete_class_tree(self, *args): return self._cmd_completer("class_tree", *args) def do_class_tree(self, *args): """ := class_tree """ try: if self.vm: for c in self.vm.get_classes(): # We don't care about Android support classes or resource # classes if c.name.startswith("Landroid") or \ c.name.split("/")[-1].startswith("R") or \ "google" in c.name or \ "android" in c.name or \ "log4j" in c.name: continue print("\n") print(self.t.yellow("\t--> class : {} {}".format(c.get_access_flags_string(), c.name))) for f in c.get_fields(): print(self.t.white("\t\t--> field : {} {} {}".format(f.get_access_flags_string(), f.get_descriptor(), f.name))) for m in c.get_methods(): print(self.t.cyan("\t\t\t--> method : {} {} {}".format(m.get_access_flags_string(), m.name, m.get_descriptor()))) print("\n") else: CommandError("class_tree : classes.dex not loaded (!)") except Exception as e: CommandError("class_tree : {}".format(e)) def complete_native(self, *args): return self._cmd_completer("native", *args) def do_native(self, *args): """ := native """ # Locals native_methods = list() try: if self.vm: for method in self.vm.get_methods(): if method.get_access_flags() & 0x100: native_methods.append((method.get_class_name(), method.get_name())) if native_methods: print("\n") for n in native_methods: print(self.t.cyan("\t--> {} : {}".format(n[0], n[1]))) print("\n") else: self.logger.log("info", "class_tree : classes.dex not loaded (!)") except Exception as e: CommandError("native : {}".format(e)) def complete_ui(self, *args): return self._cmd_completer("ui", *args) def do_ui(self, *args): """ := ui """ try: if self.vm and self.vmx: from core.brains.ui.terminal import TerminalApp ui = TerminalApp(self.vm, self.vmx) ui.run() except Exception as e: CommandError("ui : {}".format(e)) def complete_macro(self, *args): return self._cmd_completer("macro", *args) def do_macro(self, args): """ := macro """ # Locals directory_items = None macro = path.join(self.ROOT_DIR, "macro") selection = None apk_path = None json = None try: print("\n") directory_items = listdir(macro) for i, item in enumerate(directory_items): print(self.t.cyan("\t--> [{}] {}" .format(i, item))) print("\n") selection = raw_input(self.t.yellow("[{}] Select config : ".format(datetime.now()))) try: index = int(selection) except ValueError: index = -1 print("\n") if selection: for i, item in enumerate(directory_items): if selection == item or i == index: selection = item break with open("".join([macro, "/", selection]), "rb") as config: # Load the config as JSON json = loads(config.read()) if json: for k, v in json.items(): if k == "apk": if v: apk_path = str(v) # Call operate() with the path to apk self.do_operate("apk {}" .format(apk_path)) return else: CommandError("macro : Path to APK not found in {}" .format(selection)) else: CommandError("macro : Error loading {} as JSON" .format(selection)) except Exception as e: CommandError("macro : {}".format(e))
else: pass except: print("except error") except PermissionError: pass dir_path = 'G:/dataset_share/images/drebin(mal)/' filename = '000a067df9235aea987cd1e6b7768bcc1053e640b267c5b1f0deefc18be5dbe1.apk' img_path = 'G:/dataset_share/androguard/drebin(mal)_img/' apk_path = dir_path + filename apk = APK(apk_path) dalvik = DalvikVMFormat(apk) code_item = dalvik.get_codes_item() code_item_str = code_item.show() binary = int(code_item_str, 16) cnt = 0 try: photo_image = PIL.Image.frombytes( 'P', (299, 299), binary.to_bytes(int(len(code_item_str) / 2), sys.byteorder)) img_name = filename.split('.') img_name = img_name[0] + '.png'
def XrefTraverse(methods, class_name, method_name, depth): depth += 1 for m in methods: if m.class_name == class_name and m.name == method_name: if depth == 0: print (m.class_name + " -> " + m.name) for item in m.XREFfrom.items: if item[0].class_name != class_name or item[0].name != method_name: for x in range(1, depth): sys.stdout.write('--') sys.stdout.write ('>' + item[0].class_name + "->" + item[0].name + "\n") XrefTraverse(methods, item[0].class_name, item[0].name, depth) if len(sys.argv) > 2: filename = sys.argv[1] class_name = sys.argv[2] class_name = 'L' + class_name.replace(".", "/") + ";" #print class_name method_name = '<init>' d = DalvikVMFormat(APK(filename, False).get_dex()) d.create_python_export() dx = uVMAnalysis(d) gx = GVMAnalysis(dx, None) d.set_vmanalysis(dx) d.set_gvmanalysis(gx) d.create_xref() XrefTraverse(d.get_methods(), class_name, method_name, 0) else: print "usage: XrefTree.py [filename] [class_name]" print "usage: XrefTree.py filename.apk com.xyz.abc"