def __init__(self, apk): self.logger = Logger() self.t = Terminal() self.apk = apk self.activities = list() self.services = list() self.receivers = list() self.providers = list()
def __init__(self, target_module, vmx, vm, k, selection, methods): self.logger = Logger() self.target_module = target_module self.vmx = vmx self.vm = vm self.clazz = k self.selection = selection self.methods = methods
def __init__(self, files, apk): Binja.__init__(self) self.t = Terminal() self.logger = Logger() self.files = files self.apk = apk self.libs = list() self.rpc = None self.target_library = None self._init_binja()
class Components(object): def __init__(self, apk): self.logger = Logger() self.t = Terminal() self.apk = apk self.activities = list() self.services = list() self.receivers = list() self.providers = list() def sort_unique(self): """ """ return def enumerate_components(self): """ Enumerate the activities, broadcast receivers, services, and content providers from the target application's AndroidManifest.xml. Args: None Returns: None """ # TODO List comprehension # This is ugly f*****g code ... self.logger.log("info", "Loading components ...\n") try: if self.apk.get_activities(): for a in self.apk.get_activities(): self.activities.append(a) if self.activities: print(self.t.yellow("\t--> Loaded activities (!)")) if self.apk.get_services(): for s in self.apk.get_services(): self.services.append(s) if self.services: print(self.t.yellow("\t--> Loaded services (!)")) if self.apk.get_receivers(): for r in self.apk.get_receivers(): self.receivers.append(r) if self.receivers: print(self.t.yellow("\t--> Loaded receivers (!)")) if self.apk.get_providers(): for p in self.apk.get_providers(): self.providers.append(p) if self.providers: print(self.t.yellow("\t--> Loaded providers (!)")) print("\n") self.logger.log("info", "Finished loading components ...") except Exception as e: ComponentsError(e.message)
def __init__(self, vm, vmx): SurgicalCmd.__init__(self) self.logger = Logger() self.t = Terminal() self.u = Util() self.vm = vm self.vmx = vmx self.methods = self.vm.get_methods() self.web = None self.intent = IntentModule() self.modules = [m for m in self.web, self.intent] self.target_module = None self.methods_api_usage = list()
def __init__(self, vm, vmx): SurgicalCmd.__init__(self) self.logger = Logger() self.t = Terminal() self.u = Util() self.vm = vm self.vmx = vmx self.methods = self.vm.get_methods() self.intent = IntentModule() self.zip = ZipModule() self.socket = SocketModule() self.system = SystemModule() self.modules = [ m for m in self.zip, self.intent, self.socket, self.system ] self.target_module = None self.methods_api_usage = list()
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 __init__(self, apk, components): self.t = Terminal() self.logger = Logger() self.apk = apk self.xml = self.apk.get_AndroidManifest() # Populate XML elements self.xml_activities = self.xml.getElementsByTagName("activity") self.xml_services = self.xml.getElementsByTagName("service") self.xml_receivers = self.xml.getElementsByTagName("receiver") self.xml_providers = self.xml.getElementsByTagName("provider") self.components = components
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
class AttackSurfaceError(Exception): def __init__(self, message): self.logger = Logger() self.message = message self.logger.log("critical", "AttackSurface : {}".format(self.message))
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 __init__(self, message): self.logger = Logger() self.message = message self.logger.log("critical", "AttackSurface : {}".format(self.message))
class Run(SurgicalCmd): def __init__(self, vm, vmx): SurgicalCmd.__init__(self) self.logger = Logger() self.t = Terminal() self.u = Util() self.vm = vm self.vmx = vmx self.methods = self.vm.get_methods() self.intent = IntentModule() self.zip = ZipModule() self.socket = SocketModule() self.system = SystemModule() self.modules = [ m for m in self.zip, self.intent, self.socket, self.system ] self.target_module = None self.methods_api_usage = list() def do_modules(self, args): """ List and select target API modules. := modules list := modules select """ # Locals selection = None try: if args.split()[0] == "list": if self.modules: print("\n") for m in self.modules: if m: print(self.t.cyan("\t--> {}".format(m.name))) print("\n") if args.split()[0] == "select": if self.modules: selection = raw_input( self.t.yellow("[{}] ".format(datetime.now())) + "Select module : ") for m in self.modules: if m: if selection == m.name: self.target_module = m self.logger.surgical_log( "info", "{} module selected (!)".format(m.name)) except Exception as e: SurgicalError(e.message) def do_api(self, args): """ List and select methods from a given loaded API module := api list := api select := api analyzed list := api analyzed select """ # Locals class_selection = None method_selection = None surgical_lib = None try: # List the available API methods from the target module if args.split()[0] == "list": if self.target_module: print("\n") for k, v in self.target_module.model.values.items(): print("\n") for m in v: print( self.t.cyan("\t--> {} : {} : {}".format( self.target_module.name, k.split(".")[-1], m))) print("\n") else: self.logger.surgical_log( "info", "Target module has not been loaded (!)") # Select an API method from the target module elif args.split()[0] == "select": if self.target_module: # TODO Consider building a wrapper around raw_input() class_selection = raw_input( self.t.yellow("[{}] ".format(datetime.now())) + "Select class : ") method_selection = raw_input( self.t.yellow("[{}] ".format(datetime.now())) + "Select method : ") for k, v in self.target_module.model.values.items(): # This is so we can support classes with identical # method names --> Ex: java.util.zip.ZipFile if class_selection == k.split(".")[-1]: for m in v: if m == method_selection: self.logger.surgical_log( "info", "Analyzing ...") from core.brains.surgical.lib.libsurgical import SurgicalLib # Begin processing and return the results # from the selected api surgical_lib = SurgicalLib( self.target_module, self.vmx, self.vm, k, method_selection, self.methods) # methods_api_usage will contain a list of # tuples self.methods_api_usage = surgical_lib.search( ) else: self.logger.surgical_log( "warn", "Method not found (!)") # Analyze the processed method list elif args.split()[0] == "analyzed": # List the methods that have been processed if args.split()[1] == "list": if self.methods_api_usage: print("\n") for m in self.methods_api_usage: print( self.t.cyan("\t--> {} -> {} ".format( m[0].class_name, m[0].name))) print("\n") else: SurgicalError("API usage not found (!)") # Select from the processed method list elif args.split()[1] == "select": if self.methods_api_usage: selection = raw_input( self.t.yellow("[{}] ".format(datetime.now())) + "Select method : ") for m in self.methods_api_usage: if selection == m[0].name: print("\n") print( self.t.cyan("\t--> Class : {}".format( m[0].class_name))) print( self.t.cyan("\t\t--> Method : {}".format( m[0].name))) print( self.t.cyan( "\t\t\t --> XREFS ###########")) self.u.print_xref("T", m[1].method.XREFto.items) self.u.print_xref("F", m[1].method.XREFfrom.items) print("\n") print( highlight(m[2], JavaLexer(), TerminalFormatter())) else: SurgicalError("API usage not found (!)") except Exception as e: SurgicalError(e.message)
def __init__(self, message): self.logger = Logger() self.message = message self.logger.log("critical", "Components : {}".format(self.message))
class SurgicalLib(object): def __init__(self, target_module, vmx, vm, k, selection, methods): self.logger = Logger() self.target_module = target_module self.vmx = vmx self.vm = vm self.clazz = k self.selection = selection self.methods = methods def process_methods(self, found_methods): """ Process and return a unique and analyzed list of methods based on usage findings. Args: param1: Discovered methods Returns: return: Processed methods """ # Locals seen = set() unique = list() processed = list() try: for m in found_methods: if m.get_class_name() not in seen: unique.append(m) seen.add(m.get_class_name()) for u in unique: if u.get_code(): analyzed = self.vmx.get_method(u) src = decompile.DvMethod(analyzed) src.process() processed.append((u, analyzed, src.get_source())) else: analyzed = self.vmx.get_method(u) processed.append((u, analyzed, None)) return processed except Exception as e: SurgicalLibError("process_methods : {}".format(e)) if "Instruction31c" in e.message: pass def search(self): """ Search for API usage within the target module Args: None Returns: return: Method """ # Locals paths = None method = None found_methods = list() try: paths = self.vmx.get_tainted_packages().search_methods(self.clazz, self.selection, ".") if paths: for p in paths: for method in self.methods: if method.get_name() == p.get_src(self.vm.get_class_manager())[1]: if method.get_class_name() == p.get_src(self.vm.get_class_manager())[0]: found_methods.append(method) if found_methods: self.logger.surgical_log("info", "Results found (!)") process_methods = self.process_methods(found_methods) if process_methods: return process_methods else: self.logger.surgical_log("info", "No results found (!)") except Exception as e: SurgicalLibError(e.message)
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))
def __init__(self, message): self.logger = Logger() self.message = message self.logger.log("critical", "TerminalApp : {}".format(self.message))
class TerminalAppError(Exception): def __init__(self, message): self.logger = Logger() self.message = message self.logger.log("critical", "TerminalApp : {}".format(self.message))
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))
class ComponentsError(Exception): def __init__(self, message): self.logger = Logger() self.message = message self.logger.log("critical", "Components : {}".format(self.message))
class SurgicalError(Exception): def __init__(self, message): self.logger = Logger() self.message = message self.logger.log("critical", "Surgical : {}".format(self.message))
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
class Run(SurgicalCmd): def __init__(self, vm, vmx): SurgicalCmd.__init__(self) self.logger = Logger() self.t = Terminal() self.u = Util() self.vm = vm self.vmx = vmx self.methods = self.vm.get_methods() self.web = None self.intent = IntentModule() self.modules = [m for m in self.web, self.intent] self.target_module = None self.methods_api_usage = list() def do_modules(self, args): """ List and select target API modules. := modules list := modules select """ try: if args.split()[0] == "list": if self.modules: print("\n") for m in self.modules: if m: print(self.t.cyan("\t--> {}".format(m.name))) print("\n") if args.split()[0] == "select": if self.modules: selection = raw_input( self.t.yellow("[{}] ".format(datetime.now())) + "Select module : ") for m in self.modules: if m: if selection == m.name: self.target_module = m self.logger.surgical_log( "info", "{} module selected (!)".format(m.name)) except Exception as e: SurgicalError(e.message) def do_api(self, args): """ List and select methods from a given loaded API module := api list := api select := api analyzed list := api analyzed select """ try: # List the available API methods from the target module if args.split()[0] == "list": if self.target_module: print("\n") for k, v in self.target_module.model.values.items(): for m in v: print( self.t.cyan("\t--> {} : {}".format( self.target_module.name, m))) print("\n") else: self.logger.surgical_log( "info", "Target module has not been loaded (!)") # Select an API method from the target module elif args.split()[0] == "select": if self.target_module: selection = raw_input( self.t.yellow("[{}] ".format(datetime.now())) + "Select method : ") for k, v in self.target_module.model.values.items(): for m in v: if m == selection: self.logger.surgical_log( "info", "Searching ...") from core.brains.surgical.lib.libsurgical import SurgicalLib # Begin processing and return the results fomr the selected method surgical_lib = SurgicalLib( self.target_module, self.vmx, self.vm, k, selection, self.methods) # methods_api_usage will contain a list of tuples self.methods_api_usage = surgical_lib.search() else: self.logger.surgical_log( "warn", "Method not found (!)") # Analyze the processed method list elif args.split()[0] == "analyzed": # List the methods that have been processed if args.split()[1] == "list": if self.methods_api_usage: print("\n") for m in self.methods_api_usage: print( self.t.cyan("\t--> {} -> {} ".format( m[0].class_name, m[0].name))) print("\n") else: SurgicalError("API usage not found (!)") SurgicalError("Try running --> 'api select' again (!)") # Select from the processed method list elif args.split()[1] == "select": if self.methods_api_usage: selection = raw_input( self.t.yellow("[{}] ".format(datetime.now())) + "Select method : ") for m in self.methods_api_usage: if selection == m[0].name: print("\n") print( self.t.cyan("\t--> Class : {}".format( m[0].class_name))) print( self.t.cyan("\t\t--> Method : {}".format( m[0].name))) print( self.t.cyan( "\t\t\t --> XREFS ###########")) self.u.print_xref("T", m[1].method.XREFto.items) self.u.print_xref("F", m[1].method.XREFfrom.items) print("\n") print( highlight(m[2], JavaLexer(), TerminalFormatter())) else: SurgicalError("API usage not found (!)") SurgicalError("Try running --> 'api select' again (!)") except Exception as e: SurgicalError(e.message)
class CommandError(Exception): def __init__(self, message): self.logger = Logger() self.message = message self.logger.log("critical", "Command : {}".format(self.message))
class Run(Binja): def __init__(self, files, apk): Binja.__init__(self) self.t = Terminal() self.logger = Logger() self.files = files self.apk = apk self.libs = list() self.rpc = None self.target_library = None self._init_binja() 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 _init_binja(self): """ Initialize the Binja module """ # Locals endpoint = "http://*****:*****@cmd_arguments(["list", "select"]) def do_libraries(self, *args): """ := libraries select """ # Locals arg0 = args[0] selection = None index = None try: if self.libs: if arg0 == "list": print("\n") for i, lib in enumerate(self.libs): print("\t--> [{}] {} ".format(i, lib[1].split("/")[-1])) print("\n") if arg0 == "select": print("\n") for i, lib in enumerate(self.libs): print("\t--> [{}] {} ".format(i, lib[1].split("/")[-1])) print("\n") selection = raw_input("[{}] Select library : ".format(datetime.now())) try: index = int(selection) except ValueError: index = -1 if selection: for i, lib in enumerate(self.libs): if selection in lib[1] or i == index: self.target_library = lib self.logger.binja_log("info", "Selected {} (!)".format(self.target_library[1].split("/")[-1])) break except Exception as e: BinjaError("library : {}".format(e)) def complete_symbols(self, *args): return self._cmd_completer("symbols", *args) def do_symbols(self, *args): """ := symbols """ # Locals elf = None try: if self.target_library: # Create a new ELFFile() instance elf = ELFFile(self.target_library[0]) for section in elf.iter_sections(): # Once we find the symbol table, print each symbol if isinstance(section, SymbolTableSection): self.logger.binja_log("info", "Found symbol table (!)") for i, symbol in enumerate(section.iter_symbols()): self.logger.binja_log("info", symbol.name) else: self.logger.binja_log("info", "Target library not selected (!)") except Exception as e: BinjaError("function : {}".format(e))
class SurgicalLibError(Exception): def __init__(self, message): self.logger = Logger() self.message = message self.logger.surgical_log("critical", "SurgicalLib : {}".format(self.message))
class SurgicalLib(object): def __init__(self, target_module, vmx, vm, k, selection, methods): self.logger = Logger() self.target_module = target_module self.vmx = vmx self.vm = vm self.clazz = k self.selection = selection self.methods = methods def process_methods(self, found_methods): """ Process and return a unique and analyzed list of methods based on usage findings. Args: param1: Discovered methods Returns: return: Processed methods """ # Locals seen = set() unique = list() processed = list() for m in found_methods: if m.get_class_name() not in seen: unique.append(m) seen.add(m.get_class_name()) for u in unique: if u.get_code(): analyzed = self.vmx.get_method(u) src = decompile.DvMethod(analyzed) src.process() processed.append((u, analyzed, src.get_source())) else: analyzed = self.vmx.get_method(u) processed.append((u, analyzed, None)) return processed def search(self): """ Search for API usage within the target module Args: None Returns: return: Method """ # Locals paths = None method = None found_methods = list() try: paths = self.vmx.get_tainted_packages().search_methods(self.clazz, self.selection, ".") if paths: for p in paths: for method in self.methods: if method.get_name() == p.get_src(self.vm.get_class_manager())[1]: if method.get_class_name() == p.get_src(self.vm.get_class_manager())[0]: found_methods.append(method) if found_methods: self.logger.surgical_log("info", "Results found (!)") process_methods = self.process_methods(found_methods) if process_methods: return process_methods except Exception as e: SurgicalLibError(e.message)
def __init__(self, message): self.logger = Logger() self.message = message self.logger.surgical_log("critical", "SurgicalLib : {}".format(self.message))
def __init__(self, message): self.logger = Logger() self.message = message self.logger.log("critical", "Surgical : {}".format(self.message))
from core.logging.logger import Logger logger = Logger()
class Run(SurgicalCmd): def __init__(self, vm, vmx): SurgicalCmd.__init__(self) self.logger = Logger() self.t = Terminal() self.u = Util() self.vm = vm self.vmx = vmx self.methods = self.vm.get_methods() self.intent = IntentModule() self.zip = ZipModule() self.socket = SocketModule() self.system = SystemModule() self.crypto = CryptoModule() self.modules = [ m for m in self.zip, self.intent, self.socket, self.system, self.crypto ] self.target_module = None self.methods_api_usage = list() 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 complete_modules(self, *args): return self._cmd_completer("modules", *args) @cmd_arguments(["list", "select"]) def do_modules(self, *args): """ List and select target API modules. := modules list := modules select """ # Locals arg0 = args[0] selection = None try: if arg0 == "list": if self.modules: print("\n") for i, m in enumerate(self.modules): print(self.t.cyan("\t--> [{}] {}".format(i, m.name))) print("\n") if arg0 == "select": if self.modules: selection = raw_input( self.t.yellow("[{}] ".format(datetime.now())) + "Select module : ") try: index = int(selection) except ValueError: index = -1 for i, m in enumerate(self.modules): if selection == m.name or i == index: self.target_module = m break self.logger.surgical_log( "info", "{} module selected (!)".format( self.target_module.name)) except Exception as e: SurgicalError(e.message) def complete_api(self, *args): return self._cmd_completer("api", *args) @cmd_arguments(["list", "select", "analyzed"]) def do_api(self, *args): """ List and select methods from a given loaded API module := api list := api select := api analyzed list := api analyzed select """ # Locals arg0 = args[0].split(" ")[0] arg1 = None class_selection = None method_selection = None surgical_lib = None try: # List the available API methods from the target module if arg0 == "list": if self.target_module: print("\n") for k, v in self.target_module.model.values.items(): print("\n") for m in v: print( self.t.cyan("\t--> {} : {} : {}".format( self.target_module.name, k.split(".")[-1], m))) print("\n") else: self.logger.surgical_log( "info", "Target module has not been loaded (!)") # Select an API method from the target module elif arg0 == "select": if self.target_module: # TODO Consider building a wrapper around raw_input() class_selection = raw_input( self.t.yellow("[{}] ".format(datetime.now())) + "Select class : ") method_selection = raw_input( self.t.yellow("[{}] ".format(datetime.now())) + "Select method : ") for k, v in self.target_module.model.values.items(): # This is so we can support classes with identical # method names --> Ex: java.util.zip.ZipFile if class_selection == k.split(".")[-1]: for m in v: if m == method_selection: self.logger.surgical_log( "info", "Analyzing ...") from core.brains.surgical.lib.libsurgical import SurgicalLib # Begin processing and return the results # from the selected api surgical_lib = SurgicalLib( self.target_module, self.vmx, self.vm, k, method_selection, self.methods) # methods_api_usage will contain a list of # tuples self.methods_api_usage = surgical_lib.search( ) else: self.logger.surgical_log( "warn", "Method not found (!)") # Analyze the processed method list elif arg0 == "analyzed": if args[0].split(" ")[1]: arg1 = args[0].split(" ")[1] # List the methods that have been processed if arg1 == "list": if self.methods_api_usage: print("\n") for i, m in enumerate(self.methods_api_usage): print( self.t.cyan("\t--> [{}] {} -> {} ".format( i, m[0].class_name, m[0].name))) print("\n") else: SurgicalError("API usage not found (!)") # Select from the processed method list elif arg1 == "select": if self.methods_api_usage: selection = raw_input( self.t.yellow("[{}] ".format(datetime.now())) + "Select method : ") try: index = int(selection) except ValueError: index = -1 for i, m in enumerate(self.methods_api_usage): if selection == m[0].name or i == index: print("\n") print( self.t.cyan("\t--> Class : {}".format( m[0].class_name))) print( self.t.cyan("\t\t--> Method : {}".format( m[0].name))) print( self.t.cyan( "\t\t\t --> XREFS ###########")) self.u.print_xref("T", m[1].method.XREFto.items) self.u.print_xref("F", m[1].method.XREFfrom.items) print("\n") print( highlight(m[2], JavaLexer(), TerminalFormatter())) else: SurgicalError("API usage not found (!)") except Exception as e: SurgicalError(e.message)
class BinjaError(Exception): def __init__(self, message): self.logger = Logger() self.message = message self.logger.log("critical", "Command : {}".format(self.message))