def show_dyncode(self): if analysis.is_dyn_code(self.x) is False: self.__logger.log(Logger.WARNING,"No dynamic code was found!") return paths = [] paths.extend(self.x.get_tainted_packages().search_methods("Ldalvik/system/BaseDexClassLoader;", "<init>", ".")) paths.extend(self.x.get_tainted_packages().search_methods("Ldalvik/system/PathClassLoader;", "<init>", ".")) paths.extend(self.x.get_tainted_packages().search_methods("Ldalvik/system/DexClassLoader;", "<init>", ".")) paths.extend(self.x.get_tainted_packages().search_methods("Ldalvik/system/DexFile;", "<init>", ".")) paths.extend(self.x.get_tainted_packages().search_methods("Ldalvik/system/DexFile;", "loadDex", ".")) str_info_dyn="\t" for path in paths: str_info_dyn += (self.show_Path(self.x.get_vm(), path )+"\n\n\t") self.__logger.log_with_title("Usage of Dynamic Code",str_info_dyn)
def analyze(self, d): ret = False dvmx = analysis.VMAnalysis(d) if analysis.is_native_code(dvmx): ret = True self.extra += "NativeCodeFound; " if analysis.is_dyn_code(dvmx): ret = True self.extra += "DynCodeFound; " if analysis.is_reflection_code(dvmx): ret = True self.extra += "ReflexionCodeFound; " #if analysis.is_ascii_obfuscation(d): #ret = True #self.extra + "AsciiObfuscationCodeFound; " #if analysis.is_crypto_code(d): #ret = True #self.extra + "AsciiObfuscationCodeFound; " return ret
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() # 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, BadZipfile) as e: raise CuckooProcessingError("Error opening file %s" % e) return apkinfo
def getObf(self): self.ObfDic['REFLECTION'] = int(analysis.is_reflection_code(self.dx)) self.ObfDic['NATIVE'] = int(analysis.is_native_code(self.dx)) self.ObfDic['DYNAMIC'] = int(analysis.is_dyn_code(self.dx)) self.ObfDic['CRYPTO'] = int(analysis.is_crypto_code(self.dx)) return self.ObfDic
def load_app_info_table(self): self.info = {} self.info["Application Name"] = self.apk.get_app_name() self.info["Application Size"] = util.sizeof_fmt( os.path.getsize(self.apk_path)) self.info["Android Version Name"] = self.apk.get_androidversion_name() self.info["Android Version Code"] = self.apk.get_androidversion_code() self.info["Android Package Name"] = self.apk.get_package() self.info["Signature Name"] = self.apk.get_signature_name() self.info["Uses Dynamic Code Loading"] = str( analysis.is_dyn_code(self.x)) self.info["Uses Reflection"] = str(analysis.is_reflection_code(self.x)) self.info["Uses Crypto"] = str(analysis.is_crypto_code(self.x)) self.info["Privacy Leaks"] = str(len(self.get_privacy_leaks())) self.info["Number of Providers"] = str(len(self.apk.get_providers())) self.info["Number of Activities"] = str(len(self.apk.get_activities())) self.info["Number of Services"] = str(len(self.apk.get_services())) self.info["Number of Libraries"] = str(len(self.apk.get_libraries())) self.info["Number of Permissions"] = str( len(self.get_uses_permissions())) self.info_actions = {} self.info_actions["Application Name"] = None self.info_actions["Application Size"] = None self.info_actions["Android Version Name"] = None self.info_actions["Android Version Code"] = None self.info_actions["Android Package Name"] = None self.info_actions["Signature Name"] = self.show_signature self.info_actions["Uses Dynamic Code Loading"] = self.show_dyncode self.info_actions["Uses Reflection"] = self.show_reflection self.info_actions["Uses Crypto"] = self.show_cryptocode self.info_actions["Privacy Leaks"] = self.show_privacy_leaks self.info_actions["Number of Providers"] = self.show_providers self.info_actions["Number of Activities"] = self.show_activities self.info_actions["Number of Services"] = self.show_services self.info_actions["Number of Libraries"] = self.show_libraries self.info_actions["Number of Permissions"] = self.show_permissions info_table = self.ui.appInfoTable info_table.setRowCount(len(self.info)) info_table.setColumnWidth(1, 200) info_table.horizontalHeader().setResizeMode(0, QtGui.QHeaderView.Stretch) row = 0 for key in sorted(self.info): action = self.info_actions[key] action_button = None if action is not None: action_button = QtGui.QPushButton() action_button.setText("Show") action_button.clicked.connect(action) key_item = QtGui.QTableWidgetItem(key) value_item = QtGui.QTableWidgetItem(self.info[key]) info_table.setItem(row, 0, key_item) info_table.setItem(row, 1, value_item) if action_button is not None: info_table.setCellWidget(row, 2, action_button) row += 1
def do_build_apk_report(self, a): output = StringIO() a.get_files_types() output.write("[FILES] \n") for i in a.get_files(): try: output.write("\t%s %s %x\n" % (i, a.files[i], a.files_crc32[i], )) except KeyError: output.write("\t%s %x\n" % (i, a.files_crc32[i], )) output.write("\n[PERMISSIONS] \n") details_permissions = a.get_details_permissions() for i in details_permissions: output.write("\t%s %s\n" % (i, details_permissions[i], )) output.write("\n[MAIN ACTIVITY]\n\t%s\n" % (a.get_main_activity(), )) output.write("\n[ACTIVITIES] \n") activities = a.get_activities() for i in activities: filters = a.get_intent_filters("activity", i) output.write("\t%s %s\n" % (i, filters or "", )) output.write("\n[SERVICES] \n") services = a.get_services() for i in services: filters = a.get_intent_filters("service", i) output.write("\t%s %s\n" % (i, filters or "", )) output.write("\n[RECEIVERS] \n") receivers = a.get_receivers() for i in receivers: filters = a.get_intent_filters("receiver", i) output.write("\t%s %s\n" % (i, filters or "", )) output.write("\n[PROVIDERS]\n\t%s\n\n" % (a.get_providers(), )) vm = dvm.DalvikVMFormat(a.get_dex()) vmx = analysis.uVMAnalysis(vm) output.write("Native code : %s\n" % (analysis.is_native_code(vmx), )) output.write("Dynamic code : %s\n" % (analysis.is_dyn_code(vmx), )) output.write("Reflection code : %s\n" % (analysis.is_reflection_code(vmx), )) output.write("ASCII Obfuscation: %s\n\n" % (analysis.is_ascii_obfuscation(vm), )) for i in vmx.get_methods(): i.create_tags() if not i.tags.empty(): output.write("%s %s %s\n" % (i.method.get_class_name(), i.method.get_name(), i.tags, )) return output
def display_dvm_info(apk) : vm = dvm.DalvikVMFormat( apk.get_dex() ) vmx = analysis.uVMAnalysis( vm ) print "Native code:", analysis.is_native_code(vmx) print "Dynamic code:", analysis.is_dyn_code(vmx) print "Reflection code:", analysis.is_reflection_code(vmx) for i in vmx.get_methods() : i.create_tags() if not i.tags.empty() : print i.method.get_class_name(), i.method.get_name(), i.tags
def display_dvm_info(apk): vm = dvm.DalvikVMFormat(apk.get_dex()) vmx = analysis.uVMAnalysis(vm) print "Native code:", analysis.is_native_code(vmx) print "Dynamic code:", analysis.is_dyn_code(vmx) print "Reflection code:", analysis.is_reflection_code(vmx) for i in vmx.get_methods(): i.create_tags() if not i.tags.empty(): print i.method.get_class_name(), i.method.get_name(), i.tags
def load_app_info_table(self): self.info = {} self.info["Application Name"] = self.apk.get_app_name() self.info["Application Size"] = util.sizeof_fmt(os.path.getsize(self.apk_path)) self.info["Android Version Name"] = self.apk.get_androidversion_name() self.info["Android Version Code"] = self.apk.get_androidversion_code() self.info["Android Package Name"] = self.apk.get_package() self.info["Signature Name"] = self.apk.get_signature_name() self.info["Uses Dynamic Code Loading"] = str(analysis.is_dyn_code(self.x)) self.info["Uses Reflection"] = str(analysis.is_reflection_code(self.x)) self.info["Uses Crypto"] = str(analysis.is_crypto_code(self.x)) self.info["Privacy Leaks"] = str(len(self.get_privacy_leaks())) self.info["Number of Providers"] = str(len(self.apk.get_providers())) self.info["Number of Activities"] = str(len(self.apk.get_activities())) self.info["Number of Services"] = str(len(self.apk.get_services())) self.info["Number of Libraries"] = str(len(self.apk.get_libraries())) self.info["Number of Permissions"] = str(len(self.get_uses_permissions())) self.info_actions = {} self.info_actions["Application Name"] = None self.info_actions["Application Size"] = None self.info_actions["Android Version Name"] = None self.info_actions["Android Version Code"] = None self.info_actions["Android Package Name"] = None self.info_actions["Signature Name"] = self.show_signature self.info_actions["Uses Dynamic Code Loading"] = self.show_dyncode self.info_actions["Uses Reflection"] = self.show_reflection self.info_actions["Uses Crypto"] = self.show_cryptocode self.info_actions["Privacy Leaks"] = self.show_privacy_leaks self.info_actions["Number of Providers"] = self.show_providers self.info_actions["Number of Activities"] = self.show_activities self.info_actions["Number of Services"] = self.show_services self.info_actions["Number of Libraries"] = self.show_libraries self.info_actions["Number of Permissions"] = self.show_permissions info_table = self.ui.appInfoTable info_table.setRowCount(len(self.info)) info_table.setColumnWidth(1, 200) info_table.horizontalHeader().setResizeMode(0, QtGui.QHeaderView.Stretch) row = 0 for key in sorted(self.info): action = self.info_actions[key] action_button = None if action is not None: action_button = QtGui.QPushButton() action_button.setText("Show") action_button.clicked.connect(action) key_item = QtGui.QTableWidgetItem(key) value_item = QtGui.QTableWidgetItem(self.info[key]) info_table.setItem(row,0,key_item) info_table.setItem(row,1,value_item) if action_button is not None: info_table.setCellWidget(row,2,action_button) row += 1
def main(options, args) : print options.input print options.output if options.input == None or options.output == None : print "static_analysis.py -i <inputfile> -o <outputfolder>" sys.exit(2) else : ret_type = androconf.is_android( options.input ) if ret_type == "APK" : try : a = apk.APK(options.input, zipmodule=2) if a.is_valid_APK() : vm = dvm.DalvikVMFormat(a.get_dex()) vmx = analysis.uVMAnalysis(vm) data = { 'mainActivity' : a.get_main_activity(), 'activities' : a.get_activities(), 'providers' : a.get_providers(), 'receivers' : a.get_receivers(), 'services' : a.get_services(), 'androidVersion' : a.get_androidversion_code(), 'maxSdkVersion' : a.get_max_sdk_version(), 'minSdkVersion' : a.get_min_sdk_version(), 'targetSdkVersion' : a.get_target_sdk_version(), 'package' : a.get_package(), 'libraries' : a.get_libraries(), 'isCryptoCode' : analysis.is_crypto_code(vmx), 'isDynamicCode' : analysis.is_dyn_code(vmx), 'isNativeCode' : analysis.is_native_code(vmx), 'nativeMethodCount' : native_method_count(vm), 'isReflectionCode' : analysis.is_reflection_code(vmx), 'reflectionCount' : len(vmx.get_tainted_packages().search_methods("Ljava/lang/reflect/Method;", ".", ".")), 'isAsciiObfuscation' : analysis.is_ascii_obfuscation(vm), 'permissions' : a.get_permissions(), 'actualPermissions' : actual_permissions(vm, vmx), #'internalMethodCalls' : get_methods(vm.get_class_manager(), vmx.get_tainted_packages().get_internal_packages(), {}), 'externalMethodCalls' : get_methods(vm.get_class_manager(), vmx.get_tainted_packages().get_external_packages(), {}) } with io.open(options.output + "/" + hashfile(options.input) + ".json", 'w', encoding='utf-8') as f: f.write(unicode(json.dumps(data, sort_keys=False, indent=2, separators=(',', ': '), ensure_ascii=False))) else : print "INVALID APK" except Exception, e : print "ERROR", e import traceback traceback.print_exc()
def show_dyncode(self): if analysis.is_dyn_code(self.x) is False: self.__logger.log(Logger.WARNING, "No dynamic code was found!") return paths = [] paths.extend(self.x.get_tainted_packages().search_methods( "Ldalvik/system/BaseDexClassLoader;", "<init>", ".")) paths.extend(self.x.get_tainted_packages().search_methods( "Ldalvik/system/PathClassLoader;", "<init>", ".")) paths.extend(self.x.get_tainted_packages().search_methods( "Ldalvik/system/DexClassLoader;", "<init>", ".")) paths.extend(self.x.get_tainted_packages().search_methods( "Ldalvik/system/DexFile;", "<init>", ".")) paths.extend(self.x.get_tainted_packages().search_methods( "Ldalvik/system/DexFile;", "loadDex", ".")) str_info_dyn = "\t" for path in paths: str_info_dyn += (self.show_Path(self.x.get_vm(), path) + "\n\n\t") self.__logger.log_with_title("Usage of Dynamic Code", str_info_dyn)
def performAnalysis(apkPath): # Perform the analysis by recalling public method of androlyze.py a, d, dx = androlyze.AnalyzeAPK(apkPath) if not a.is_valid_APK(): print "[Exit] The selected resource is not a valid APK!" return sys.exit(FAILURE) if not analysis.is_dyn_code(dx): print "[Exit] No DexClassLoader use in this APK and so there is nothing to patch!" return sys.exit(SUCCESS) print "[In progress] Analyze target APK.." # Store app permissions (used later on while patching Android Manifest) app_permissions = set(a.get_permissions()) # app_permissions.add('android.permission.ACCESS_NETWORK_STATE') # app_permissions.add('android.permission.BLABLABLA') # Reference to global variable missing_permissions = list() for current_perm in required_permissions: if not (current_perm in app_permissions): missing_permissions.append(current_perm) # print missing_permissions # Flag variable for later use dynamicCallsWhereTraced = False # Save a reference for standard output stdout = sys.stdout # Redirect output to an helper variable # sys.stdout = open('./dynamicCalls', 'w') dynamicCallsFilePath = os.curdir + os.sep + "dynamicCalls" with open(dynamicCallsFilePath, "w") as dynamicCallsFile: # Redirect output to an helper variable sys.stdout = dynamicCallsFile # Highlight dynamic calls linked to a DexClassLoader. analysis.show_DynCode(dx) # Set back usual stdout sys.stdout = stdout with open(dynamicCallsFilePath, "r") as dynamicCallsFile: # print INTEGER.parseString("1") # print CLASS_STRING.parseString("Lcom/example/extractapp/MainActivity;") # print METHOD_DECL.parseString("setUpNormal()V") # print NUMBER_EXA.parseString("(0x66)") # print CLASS_STRING.parseString("Ldalvik/system/DexClassLoader;") # Define a grammar to parse line of the input file. parsing_format = ( INTEGER + CLASS_STRING + "->" + METHOD_DECL + NUMBER_EXA + "--->" + CLASS_STRING + "->" + METHOD_DECL ) # Reference to global variable classesWithDynCodeLoad = list() for line in dynamicCallsFile: # print line tokens = parsing_format.parseString(line) # This is a sort specific parsing constant(magic numbers).. className = tokens[1][1] # Extract only name of classes to patch which are not the ones of Grab'n Run if className != "it/necst/grabnrun/SecureDexClassLoader": classesWithDynCodeLoad.append(className) # In the end remove duplicates from this list (use a set) classesWithDynCodeLoad = set(classesWithDynCodeLoad) # print classesWithDynCodeLoad # Raise flag variable print "[In progress] Dynamic calls have been detected.." dynamicCallsWhereTraced = True # Now the helper file should be closed and erased. os.remove(dynamicCallsFilePath) if dynamicCallsWhereTraced: # This APK should be patched! return missing_permissions, classesWithDynCodeLoad # Something went wrong.. print "[Exit] Dynamic calls have not been detected!" return sys.exit(FAILURE)
def analyze_dex(self, d, dx, flags): flags["REFLECTION"] = int(analysis.is_reflection_code(dx)) flags["NATIVE"] = int(analysis.is_native_code(dx)) flags["DYNAMIC"] = int(analysis.is_dyn_code(dx)) flags["CRYPTO"] = int(analysis.is_crypto_code(dx))
def execute(self): AndroCommand.execute(self) if self.options.all_options: self.options.dynamic = True self.options.native = True self.options.obfuscation = True self.options.reflection = True dalvik_options= [self.options.dynamic, self.options.native, self.options.obfuscation, self.options.reflection] a = apk.APK(self.options.apk, zipmodule=2) if not a.is_valid_APK(): sys.stderr.write("Not a valid APK file.") exit(1) if not any(dalvik_options): sys.stderr.write("No output option selected.") exit(1) # create a session, get the underlying app and use a transaction to update # the values session = self.db.session() try: app = session.query(App).filter(App.id==self.options.index).first() if not app: sys.stderr.write("Could not find app by index.") exit(1) #print 'Doing vm analysis' dex = a.get_dex() vm = dvm.DalvikVMFormat(dex) vmx = analysis.uVMAnalysis(vm) if self.options.dynamic: print 'Checking if application uses dynamic code...' app.dynamic = analysis.is_dyn_code(vmx) session.flush() if self.options.native: print 'Checking if application uses native code...' app.native = analysis.is_native_code(vmx) session.flush() # androguard 1.9 no longer supports this """ if self.options.obfuscation: print 'Checking if application uses obfuscation...' app.obfuscation = analysis.is_ascii_obfuscation(vm) session.flush() """ if self.options.reflection: print 'Checking if application uses reflection...' app.reflection = analysis.is_reflection_code(vmx) session.flush() session.commit() print 'Success' except: session.rollback() exit(1) exit(0)
def print_dynLoad(dx, cm): if analysis.is_dyn_code(dx) == True: OutStream.write("***dynamic code loading***\n") paths = dx.get_tainted_packages().search_methods( "Ldalvik/system/DexClassLoader;", ".", ".") write_Paths(paths, cm, OutStream)
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 performAnalysis(apkPath): # Perform the analysis by recalling public method of androlyze.py a, d, dx = androlyze.AnalyzeAPK(apkPath) if not a.is_valid_APK(): print "[Exit] The selected resource is not a valid APK!" return sys.exit(FAILURE) if not analysis.is_dyn_code(dx): print "[Exit] No DexClassLoader use in this APK and so there is nothing to patch!" return sys.exit(SUCCESS) print "[In progress] Analyze target APK.." # Store app permissions (used later on while patching Android Manifest) app_permissions = set(a.get_permissions()) #app_permissions.add('android.permission.ACCESS_NETWORK_STATE') #app_permissions.add('android.permission.BLABLABLA') # Reference to global variable missing_permissions = list() for current_perm in required_permissions: if not (current_perm in app_permissions): missing_permissions.append(current_perm) #print missing_permissions # Flag variable for later use dynamicCallsWhereTraced = False # Save a reference for standard output stdout = sys.stdout # Redirect output to an helper variable # sys.stdout = open('./dynamicCalls', 'w') dynamicCallsFilePath = os.curdir + os.sep + "dynamicCalls" with open(dynamicCallsFilePath, 'w') as dynamicCallsFile: # Redirect output to an helper variable sys.stdout = dynamicCallsFile # Highlight dynamic calls linked to a DexClassLoader. analysis.show_DynCode(dx) # Set back usual stdout sys.stdout = stdout with open(dynamicCallsFilePath, 'r') as dynamicCallsFile: #print INTEGER.parseString("1") #print CLASS_STRING.parseString("Lcom/example/extractapp/MainActivity;") #print METHOD_DECL.parseString("setUpNormal()V") #print NUMBER_EXA.parseString("(0x66)") #print CLASS_STRING.parseString("Ldalvik/system/DexClassLoader;") # Define a grammar to parse line of the input file. parsing_format = INTEGER + CLASS_STRING + "->" + METHOD_DECL + NUMBER_EXA + "--->" + CLASS_STRING + "->" + METHOD_DECL # Reference to global variable classesWithDynCodeLoad = list() for line in dynamicCallsFile: # print line tokens = parsing_format.parseString(line) # This is a sort specific parsing constant(magic numbers).. className = tokens[1][1] # Extract only name of classes to patch which are not the ones of Grab'n Run if className != "it/necst/grabnrun/SecureDexClassLoader": classesWithDynCodeLoad.append(className) # In the end remove duplicates from this list (use a set) classesWithDynCodeLoad = set(classesWithDynCodeLoad) # print classesWithDynCodeLoad # Raise flag variable print "[In progress] Dynamic calls have been detected.." dynamicCallsWhereTraced = True # Now the helper file should be closed and erased. os.remove(dynamicCallsFilePath) if dynamicCallsWhereTraced: # This APK should be patched! return missing_permissions, classesWithDynCodeLoad # Something went wrong.. print "[Exit] Dynamic calls have not been detected!" return sys.exit(FAILURE)
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()] 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'] = {} # 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) return result
def has_dynamic(self): if analysis.is_dyn_code(self.dx): self.risk += 1 return True else: return False
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
def main(options, args) : print options.input if options.input == None or options.output == None : print "static_analysis.py -i <inputfile> -o <outputfolder>" sys.exit(2) elif db.static_features.find({"_id": hashfile(options.input)}, limit=1).count() == 1 : print "static analysis found.. skipping.." sys.exit(0) elif db.virustotal_features.find({"sha1": hashfile(options.input)}).count() == 0 : print "virus total metadata not found.. skipping.." sys.exit(0) elif db.virustotal_features.find({ "$or": [ { "positives": 0 }, { "positives": { "$gte": 35 } } ], "sha1": hashfile(options.input) }).count() == 0 : print "not clear enough benign or malicious.. skipping.." sys.exit(0) t_beginning = time.time() ret_type = androconf.is_android( options.input ) if ret_type == "APK" : try : a = apk.APK(options.input, zipmodule=2) if a.is_valid_APK() : vm = dvm.DalvikVMFormat(a.get_dex()) vmx = analysis.uVMAnalysis(vm) data = { '_id' : hashfile(options.input), 'validApk' : True, 'mainActivity' : a.get_main_activity(), 'activities' : a.get_activities(), 'providers' : a.get_providers(), 'receivers' : a.get_receivers(), 'services' : a.get_services(), 'androidVersion' : a.get_androidversion_code(), 'maxSdkVersion' : a.get_max_sdk_version(), 'minSdkVersion' : a.get_min_sdk_version(), 'targetSdkVersion' : a.get_target_sdk_version(), 'package' : a.get_package(), 'libraries' : a.get_libraries(), 'isCryptoCode' : analysis.is_crypto_code(vmx), 'isDynamicCode' : analysis.is_dyn_code(vmx), 'isNativeCode' : analysis.is_native_code(vmx), 'nativeMethodCount' : native_method_count(vm), 'isReflectionCode' : analysis.is_reflection_code(vmx), 'reflectionCount' : len(vmx.get_tainted_packages().search_methods("Ljava/lang/reflect/Method;", ".", ".")), 'isAsciiObfuscation' : analysis.is_ascii_obfuscation(vm), 'permissions' : a.get_permissions(), 'actualPermissions' : actual_permissions(vm, vmx), 'internalMethodCalls' : get_methods(vm.get_class_manager(), vmx.get_tainted_packages().get_internal_packages(), {}), 'externalMethodCalls' : get_methods(vm.get_class_manager(), vmx.get_tainted_packages().get_external_packages(), {}) } data['duration'] = time.time() - t_beginning db.static_features.insert(data) else : print "INVALID APK" data = { '_id' : hashfile(options.input), 'validApk' : False } db.static_features.insert(data) except Exception, e : print "ERROR", e import traceback traceback.print_exc()
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