def analyzeAPK(self): """ Uses androguard to retrieve metadata about the app e.g. activities, permissions, intent filters, etc. """ try: prettyPrint("Analyzing app") logEvent("Analyzing app: \"%s\"" % self.APKPath) # 1. Load the APK using androguard analysisSession = Session() analysisSession.add(self.APKPath, open(self.APKPath).read()) # 2. Retrieve handles to APK and its dex code self.APK = analysisSession.analyzed_apk.values()[0] self.DEX = analysisSession.analyzed_dex.values()[0][0] self.VMAnalysis = analysisSession.analyzed_dex.values()[0][1] # 3. Retrieve information for each activity prettyPrint("Analyzing activities") self.activitiesInfo = analyzeActivities(self.APK, self.DEX) # 4. Do the same for services and broadcast receivers prettyPrint("Analyzing services") self.servicesInfo = analyzeServices(self.APK, self.DEX) prettyPrint("Analyzing broadcast receivers") self.receiversInfo = analyzeReceivers(self.APK, self.DEX) except Exception as e: prettyPrintError(e) return False prettyPrint("Success") return True
def extractStaticFeatures(apkPath): """Extracts static numerical features from APK using Androguard""" try: features = [[], [], [], []] # Tuples are immutable if os.path.exists(apkPath.replace(".apk",".static")): prettyPrint("Found a pre-computed static features file") bFeatures, pFeatures, aFeatures, allFeatures = [], [], [], [] try: possibleExtensions = [".basic", ".perm", ".api", ".static"] for ext in possibleExtensions: if os.path.exists(apkPath.replace(".apk", ext)): content = open(apkPath.replace(".apk", ext)).read() if len(content) > 0: features[possibleExtensions.index(ext)] = [float(f) for f in content[1:-1].split(',') if len(f) > 0] return tuple(features) except Exception as e: prettyPrintError(e) prettyPrint("Could not extract features from \".static\" file. Continuing as usual", "warning") if verboseON(): prettyPrint("Starting analysis on \"%s\"" % apkPath, "debug") analysisSession = Session() if not os.path.exists(apkPath): prettyPrint("Could not find the APK file \"%s\"" % apkPath, "warning") return [], [], [], [] # 1. Analyze APK and retrieve its components #t = threading.Timer(300.0, returnEmptyFeatures) # Guarantees not being stuck on analyzing an APK #t.start() analysisSession.add(apkPath, open(apkPath).read()) if type(analysisSession.analyzed_apk.values()) == list: apk = analysisSession.analyzed_apk.values()[0][0] else: apk = analysisSession.analyzed_apk.values()[0] dex = analysisSession.analyzed_dex.values()[0][0] vm = analysisSession.analyzed_dex.values()[0][1] # 2. Add features to the features vector basicFeatures, permissionFeatures, apiCallFeatures, allFeatures = [], [], [], [] # 2.a. The APK-related features if verboseON(): prettyPrint("Extracting basic features", "debug") minSDKVersion = 0.0 if not apk.get_min_sdk_version() else float(apk.get_min_sdk_version()) maxSDKVersion = 0.0 if not apk.get_max_sdk_version() else float(apk.get_max_sdk_version()) basicFeatures.append(minSDKVersion) basicFeatures.append(maxSDKVersion) basicFeatures.append(float(len(apk.get_activities()))) # No. of activities basicFeatures.append(float(len(apk.get_services()))) # No. of services basicFeatures.append(float(len(apk.get_receivers()))) # No. of broadcast receivers basicFeatures.append(float(len(apk.get_providers()))) # No. of providers # 2.b. Harvest permission-related features if verboseON(): prettyPrint("Extracting permissions-related features", "debug") aospPermissions = float(len(apk.get_requested_aosp_permissions())) # Android permissions requested by the app declaredPermissions = float(len(apk.get_declared_permissions())) # Custom permissions declared by the app dangerousPermissions = float(len([p for p in apk.get_requested_aosp_permissions_details().values() if p["protectionLevel"] == "dangerous"])) totalPermissions = float(len(apk.get_permissions())) permissionFeatures.append(totalPermissions) # No. of permissions if totalPermissions > 0: permissionFeatures.append(aospPermissions/totalPermissions) # AOSP permissions : Total permissions permissionFeatures.append(declaredPermissions/totalPermissions) # Third-party permissions : Total permissions permissionFeatures.append(dangerousPermissions/totalPermissions) # Dangerous permissions : Total permissions else: permissionFeatures.append(0.0) permissionFeatures.append(0.0) permissionFeatures.append(0.0) # 2.c. The DEX-related features (API calls) if verboseON(): prettyPrint("Extracting API calls from dex code", "debug") apiCallFeatures.append(float(len(dex.get_classes()))) # Total number of classes apiCallFeatures.append(float(len(dex.get_strings()))) # Total number of strings apiCategories = sensitiveAPICalls.keys() apiCategoryCount = [0.0] * len(apiCategories) for c in dex.classes.get_names(): currentClass = dex.get_class(c) if not currentClass: continue code = currentClass.get_source() if len(code) < 1: continue for category in apiCategories: if code.find(category) != -1: for call in sensitiveAPICalls[category]: apiCategoryCount[apiCategories.index(category)] += float(len(re.findall(call, code))) apiCallFeatures += apiCategoryCount except Exception as e: prettyPrintError(e) return [], [], [], [] allFeatures = basicFeatures + permissionFeatures + apiCallFeatures return basicFeatures, permissionFeatures, apiCallFeatures, allFeatures
def run(self): """ Runs the Droidutan test against the [processTarget] for [processDuration] """ try: # A timer to guarante the process exits if verboseON(): prettyPrint( "Setting timer for %s seconds" % str(float(self.processDuration) * 5.0), "debug") t = threading.Timer(float(self.processDuration) * 5.0, self.stop) t.start() # Step 1. Analyze APK #APKType = "malware" if self.processTarget.find("malware") != -1 else "goodware" if verboseON(): prettyPrint("Analyzing APK: \"%s\"" % self.processTarget, "debug") s = Session() s.add(self.processTarget, open(self.processTarget).read()) if len(s.analyzed_apk.values()) > 0: apk = s.analyzed_apk.values()[0] if type(apk) == list: apk = s.analyzed_apk.values()[0][0] else: prettyPrint("Could not retrieve an APK to analyze. Skipping", "warning") return False # Step 2. Get the Ip address assigned to the AVD getAVDIPCmd = [ "VBoxManage", "guestproperty", "enumerate", self.processVM ] avdIP = "" result = subprocess.Popen( getAVDIPCmd, stderr=subprocess.STDOUT, stdout=subprocess.PIPE).communicate()[0].replace(' ', '') if result.lower().find("error") != -1: prettyPrint("Unable to retrieve the IP address of the AVD", "error") print result return False index = result.find("androvm_ip_management,value:") + len( "androvm_ip_management,value:") while result[index] != ',': avdIP += result[index] index += 1 adbID = "%s:5555" % avdIP # Step 3. Define frequently-used commands droidbotOut = self.processTarget.replace(".apk", "_droidbot") droidbotCmd = [ "droidbot", "-d", adbID, "-a", self.processTarget, "-o", droidbotOut, "-timeout", str(self.processDuration), "-random", "-keep_env", "-grant_perm" ] # Step 4. Test the APK using Droidbot (Assuming machine is already on) prettyPrint("Testing the APK \"%s\" using Droidbot" % apk.package) # 4.a. Start Droidbot status = subprocess.Popen(droidbotCmd, stderr=subprocess.STDOUT, stdout=subprocess.PIPE).communicate()[0] # 4.b. Check for existence of output directory if not os.path.exists(droidbotOut): prettyPrint( "No output folder found for \"%s\"" % self.processTarget, "warning") return False # 4.c. Filter the logcat dumped by droidbot logFile = open("%s/logcat_filtered.log" % droidbotOut, "w") catlog = subprocess.Popen(("cat", "%s/logcat.txt" % droidbotOut), stdout=subprocess.PIPE) output = subprocess.check_output( ("grep", "-i", "droidmon-apimonitor-%s" % apk.package), stdin=catlog.stdout) logFile.write(output) logFile.close() except subprocess.CalledProcessError as cpe: prettyPrint( "Unable to find the tag \"Droidmon-apimonitor-%s\" in the log file" % apk.package, "warning") except Exception as e: prettyPrintError(e) return False return True
def display_PERMISSION(a, x, classes): # Show methods used by permission perms_access = x.get_tainted_packages().get_permissions([]) for perm in perms_access: print("PERM : ", perm) analysis.show_Paths(a, perms_access[perm]) def display_OBJECT_CREATED(a, x, class_name): print("Search object", class_name) analysis.show_Paths(a, x.get_tainted_packages().search_objects(class_name)) s = Session() with open(TEST, "r") as fd: s.add(TEST, fd.read()) a, d, dx = s.get_objects_apk(TEST) print(d.get_strings()) print(d.get_regex_strings("access")) print(d.get_regex_strings("(long).*2")) print(d.get_regex_strings(".*(t\_t).*")) classes = d.get_classes_names() display_CFG(d, dx, classes) display_STRINGS(dx) display_FIELDS(d, dx) display_PACKAGES(d, dx) display_PACKAGES_IE(d, dx)