def verifyChinaSMSStealer(self, apkfile): self.apkfile = apkfile iNum = 0 a = apk.APK(apkfile) szPermissions = " ".join(a.get_permissions()) matchObj = re.search( r'android\.permission\.INTERNET', szPermissions, re.DOTALL|re.UNICODE|re.M|re.I) if matchObj: iNum += 1 szActivities = "".join(a.get_activities()) matchObj = re.search( r'activity\.MainActivity', szActivities, re.DOTALL|re.UNICODE|re.M|re.I) if matchObj: iNum += 1 szReceivers = "".join(a.get_receivers()) matchObj = re.search( r'receiver\.SMSReceiver', szReceivers, re.DOTALL|re.UNICODE|re.M|re.I) if matchObj: iNum += 1 szServices = "".join(a.get_services()) matchObj = re.search( r'service\.SecondService', szServices, re.DOTALL|re.UNICODE|re.M|re.I) if matchObj: iNum += 1 if iNum==4: bRes = self.extract_config(apkfile) return bRes else: _log("[-] This is not ChinaSMSStealer")
def verifyFakeSpy(self, apkfile): self.apkfile = apkfile iNum = 0 a = apk.APK(self.apkfile) szPermissions = " ".join(a.get_permissions()) matchObj = re.search( r'android\.permission\.INTERNET', szPermissions, re.DOTALL|re.UNICODE|re.M|re.I) if matchObj: iNum += 1 szActivities = "".join(a.get_activities()) matchObj = re.search( r'\.MainActivity', szActivities, re.DOTALL|re.UNICODE|re.M|re.I) if matchObj: iNum += 1 szReceivers = "".join(a.get_receivers()) matchObj = re.search( r'\.MyReceiver', szReceivers, re.DOTALL|re.UNICODE|re.M|re.I) if matchObj: iNum += 1 szServices = "".join(a.get_services()) matchObj = re.search( r'\.M[e|y]Service', szServices, re.DOTALL|re.UNICODE|re.M|re.I) if matchObj: iNum += 1 if iNum==4: bRes = self.extract_config(apkfile) return bRes else: _log("[-] This is not FakeSpy")
def extract_config(self, apkfile): self.apkfile = apkfile string = "" a = apk.APK(self.apkfile) d = dvm.DalvikVMFormat(a.get_dex()) for cls in d.get_classes(): if '/app/AppController;'.lower() in cls.get_name().lower(): for cls in d.get_classes(): if '/app/a;'.lower() in cls.get_name().lower(): c2 = [] string = None for method in cls.get_methods(): if '<clinit>'.lower() in str(method).lower(): for inst in method.get_instructions(): if inst.get_name() == 'const-string': string = inst.get_output().split(',')[-1].strip(" '") if "http" in string: c2.append(string.replace("@", "/")) elif "&ht&" in string: c2.append(string.replace("&", "")) if len(c2)>0: _log('Extracting from %s' % apkfile) for i in range(len(c2)): _log('C&C: [ %s ]' % c2[i]) return True
def verifyMoqhao(self, apkfile): self.apkfile = apkfile iNum = 0 a = apk.APK(apkfile) szPermissions = " ".join(a.get_permissions()) matchObj = re.search(r'android\.permission\.INTERNET', szPermissions, re.DOTALL | re.UNICODE | re.M | re.I) if matchObj: iNum += 1 szActivities = "".join(a.get_activities()) matchObj = re.search(r'org\.[a-zA-Z]{1,3}bgsActivity', szActivities, re.DOTALL | re.UNICODE | re.M | re.I) if matchObj: iNum += 1 szReceivers = "".join(a.get_receivers()) matchObj = re.search(r'org\.[a-zA-Z]{1,3}vtyReceiver', szReceivers, re.DOTALL | re.UNICODE | re.M | re.I) if matchObj: iNum += 1 szServices = "".join(a.get_services()) matchObj = re.search(r'org\.[a-zA-Z]{1,3}rMainService', szServices, re.DOTALL | re.UNICODE | re.M | re.I) if matchObj: iNum += 1 if iNum == 4: szPayload = a.get_files() for actualPayload in szPayload: searchObj = re.search(r'assets/[a-d]/(.*?)', actualPayload, re.DOTALL | re.UNICODE | re.M | re.I) if searchObj: bRes = self.extract_config(apkfile, actualPayload) return bRes else: _log("[-] This is not Moqhao")
def extract_config(self, apkfile, actualPayload): a = apk.APK(apkfile) payload_bytes = a.get_file(actualPayload) dec_z = zlib.decompress(payload_bytes[4:]) # open.skip(4); dec_b = base64.b64decode(dec_z) dex = dvm.DalvikVMFormat(base64.b64decode(dec_z)) payload_dec = os.path.basename(actualPayload) + ".dec" with open(payload_dec, "wb") as fp: fp.write(dec_b) _log("[+] Payload is extracted as {}".format(payload_dec)) urls = self.extract_c2_accounts(dex.get_strings()) for url in urls: _log(url) for cls in dex.get_classes(): if '/loader$al;'.lower() in cls.get_name().lower(): credentials = [] string = None for method in cls.get_methods(): if 'loader$al;->run()v'.lower() in str(method).lower(): for inst in method.get_instructions(): if inst.get_name() == 'const-string': string = inst.get_output().split( ',')[-1].strip(" '") credentials.append(string) iNumber = len(credentials) _log('[+] Extracting credentials from %s' % payload_dec) _log('[+] Email address : %s' % credentials[iNumber - 2]) _log('[+] Email password : %s' % credentials[iNumber - 1]) return True
def extract_config(self, apkfile): self.apkfile = apkfile bEventBot = False a = apk.APK(self.apkfile) d = dvm.DalvikVMFormat(a.get_dex()) for cls in d.get_classes(): if '/example/eventbot/cfg'.lower() in cls.get_name().lower(): _log(" [+] This is EventBot.") bEventBot = True c2 = [] string = None for method in cls.get_methods(): if 'eventbot/cfg;-><clinit>()'.lower() in str( method).lower(): for inst in method.get_instructions(): if inst.get_name() == 'const-string': string = inst.get_output().split( ';') #.strip(" '") if "http" in string[0]: c2.append(string[0].strip("v0, '")) c2.append(string[1].strip(" '")) if self.isNotEmpty(c2[0]): _log(' [+] Extracting from %s' % self.apkfile) _log(' [+] C&C : [ %s ]' % c2[0]) _log(' [+] C&C : [ %s ]' % c2[1]) return True if bEventBot == False: _log("[-] This is not EventBot")
def verifyAPT_C_23(self, apkfile): self.apkfile = apkfile iNum = 0 a = apk.APK(apkfile) szPermissions = " ".join(a.get_permissions()) matchObj = re.search( r'android\.permission\.INTERNET', szPermissions, re.DOTALL|re.UNICODE|re.M|re.I) if matchObj: iNum += 1 szActivities = "".join(a.get_activities()) matchObj = re.search( r'MainActivity', szActivities, re.DOTALL|re.UNICODE|re.M|re.I) if matchObj: iNum += 1 szReceivers = "".join(a.get_receivers()) matchObj = re.search( r'eceivers\.CallReceiver', szReceivers, re.DOTALL|re.UNICODE|re.M|re.I) if matchObj: iNum += 1 szServices = "".join(a.get_services()) matchObj = re.search( r'services\.CellService', szServices, re.DOTALL|re.UNICODE|re.M|re.I) if matchObj: iNum += 1 if iNum==4: bRes = self.extract_config(self.apkfile) return bRes else: _log("[-] This is not APT-C-23")
def verifyMuddyWater(self, apkfile): self.apkfile = apkfile iNum = 0 a = apk.APK(apkfile) szPermissions = " ".join(a.get_permissions()) matchObj = re.search(r'android\.permission\.INTERNET', szPermissions, re.DOTALL | re.UNICODE | re.M | re.I) if matchObj: iNum += 1 szActivities = "".join(a.get_activities()) matchObj = re.search(r'client\.Main', szActivities, re.DOTALL | re.UNICODE | re.M | re.I) if matchObj: iNum += 1 szReceivers = "".join(a.get_receivers()) matchObj = re.search(r'receiver\.SmsReceiver', szReceivers, re.DOTALL | re.UNICODE | re.M | re.I) if matchObj: iNum += 1 szServices = "".join(a.get_services()) matchObj = re.search(r'client\.Client', szServices, re.DOTALL | re.UNICODE | re.M | re.I) if matchObj: iNum += 1 if iNum == 4: bRes = self.extract_config(self.apkfile) return bRes else: _log("[-] This is not MuddyWater")
def extract_config2(self, apkfile): self.apkfile = apkfile string = "" a = apk.APK(self.apkfile) d = dvm.DalvikVMFormat(a.get_dex()) encIP = "" encKey = "" for cls in d.get_classes(): if 'Lru/ok/android/b/a;'.lower() in cls.get_name().lower(): string = None for method in cls.get_methods(): if '/a;->a(Landroid/content/Context;)'.lower() in str(method).lower(): for inst in method.get_instructions(): if inst.get_name() == 'const-string': string = inst.get_output().split(',')[-1].strip(" '") if "=" in string: encIP = string _log("[+] Found encrypted C2 : %s" %encIP) if 'Lru/ok/android/b/b;'.lower() in cls.get_name().lower(): string = None for method in cls.get_methods(): if '<clinit>'.lower() in str(method).lower(): for inst in method.get_instructions(): if inst.get_name() == 'const-string': string = inst.get_output().split(',')[-1].strip(" '") if "=" in string and "=UTF-8" not in string: encKey = string _log("[+] Found MD5 hashed & Base64 encoded key : %s" %encKey) if encIP and encKey: bRes = self.AESdecrypt(encIP, encKey) if bRes: return True
def verifyEventBot(self, apkfile): self.apkfile = apkfile a = apk.APK(self.apkfile) szPackageName = a.get_package() if "example.eventbot" in szPackageName: bRes = self.extract_config(self.apkfile) return bRes else: _log("[-] This is not EventBot")
def verifyTeleRat(self, apkfile): self.apkfile = apkfile a = apk.APK(self.apkfile) szPackageName = a.get_package() if szPackageName == "b4a.example": bRes = self.extract_config(self.apkfile) return bRes else: _log("[-] This is not TeleRat")
def AESdecrypt(self, szData, key): key = md5(key.encode('utf-8')).hexdigest() szData = base64.b64decode(szData) cipher = AES.new(key, AES.MODE_ECB) plaintext = cipher.decrypt(szData) c2 = str(plaintext.decode("utf-8")) c2 = c2[:c2.find('\x08')] _log("[+] AES decrypted data --> C&C : %s" % c2) return True
def verifyFlexBotnet(self, apkfile): self.apkfile = apkfile a = apk.APK(self.apkfile) szPackageName = a.get_package() if "app.six" in szPackageName: bRes = self.extract_config(apkfile) if bRes == True: return True else: _log("[-] This is not FlexBotnet")
def verifyVamp(self, apkfile): self.apkfile = apkfile a = apk.APK(self.apkfile) szPackageName = a.get_package() if szPackageName=="ru.ok.android": bRes = self.extract_config2(apkfile) if bRes == True: return True else: _log("[-] This is not Vamp")
def verifySaefko(self, apkfile): self.apkfile = apkfile a = apk.APK(self.apkfile) szPackageName = a.get_package() if "com.sas.seafkoagent.seafkoagent" in szPackageName: bRes = self.extract_config(apkfile) if bRes == True: return True else: _log("[-] This is not Saefko")
def verifyTriout(self, apkfile): self.apkfile = apkfile a = apk.APK(self.apkfile) szPackageName = a.get_package() if "com.xapps.SexGameForAdults" in szPackageName: bRes = self.extract_config(apkfile) if bRes == True: return True else: _log("[-] This is not Triout")
def verifySandroRat(self, apkfile): self.apkfile = apkfile a = apk.APK(self.apkfile) szActivities = "".join(a.get_activities()) matchObj = re.search(r'net\.droidjack\.server', szActivities, re.DOTALL | re.UNICODE | re.M | re.I) bRes = self.extract_config(apkfile) if bRes == True: return True else: _log("[-] This is not SandroRat")
def verifyBankBot(self, apkfile): self.apkfile = apkfile a = apk.APK(self.apkfile) szPackageName = a.get_package() if szPackageName == "com.example.livemusay.myapplication": _log("[+] This is BankBot") bRes = self.extract_config(apkfile) if bRes == True: return True else: _log("[-] This is not BankBot")
def extract_config(self, apkfile): self.apkfile = apkfile string = "" a = apk.APK(self.apkfile) d = dvm.DalvikVMFormat(a.get_dex()) for cls in d.get_classes(): if 'Lcom/sas/seafkoagent/seafkoagent/GLOBALS;'.lower() in cls.get_name().lower(): c2 = "" serverpass = "" string = None for field in cls.get_fields(): if "SERVER_PASS" in field.get_name(): string = field.get_init_value().get_value() serverpass = string elif "SERVER_URL" in field.get_name(): string = field.get_init_value().get_value() c2 = string if self.isNotEmpty(c2): parsed_uri = urlparse(c2) result = '{uri.scheme}://{uri.netloc}/'.format(uri=parsed_uri) _log('[+] Extracting from %s' % self.apkfile) _log('[+] C&C: [ %s ]' % c2) _log('[+] Server password: [ %s ]' % serverpass) _log('[+] The DB file is most likely at [ %s ]' % (result + "seafko_db.db")) return True
def verifyAndroRat(self, apkfile): self.apkfile = apkfile a = apk.APK(self.apkfile) szPackageName = a.get_package() if "my.app.client" in szPackageName: bRes = self.extract_config(apkfile) if bRes == True: return True else: _log("[-] This is not AndroRat") return False else: _log("[-] This is not AndroRat") return False
def extract_config(self, apkfile): bRes = False self.apkfile = apkfile a = apk.APK(self.apkfile) d = dvm.DalvikVMFormat(a.get_dex()) for cls in d.get_classes(): if '/titan/appUtil/utils/AppField;'.lower() in cls.get_name( ).lower(): _log("[+] It's MuddyWater") _log("[+] Extracting from %s" % self.apkfile) c2 = [] string = None for field in cls.get_fields(): if "SERVER_IP" in field.get_name(): string = field.get_init_value().get_value() c2.append(string) if self.isNotEmpty(c2[0]): for CC in c2: _log("[+] Extracted C2: %s" % CC) bRes = True for field in cls.get_fields(): if "SERVER_PORT" in field.get_name(): string = field.get_init_value().get_value() _log("[+] Port: %s" % string) return bRes
def verifyDendroid(self, apkfile): self.apkfile = apkfile a = apk.APK(self.apkfile) szServices = "".join(a.get_services()) matchObj = re.search(r'com\.connect\.MyService', szServices, re.DOTALL | re.UNICODE | re.M | re.I) if matchObj == None: _log("[-] This is not Dendroid") return False else: if matchObj.group(0) == "com.connect.MyService": bRes = self.extract_config(apkfile) if bRes == True: return True
def extract_config2(self, apkfile): bRes = False self.apkfile = apkfile a = apk.APK(self.apkfile) szFilename = "" with zipfile.ZipFile(apkfile, 'r') as f: names = f.namelist() for filename in names: if "libhelper.so" in filename or "libma1sker.so" in filename or "libma2sker.so" in filename or "libma3sker.so" in filename: _log("[+] Found %s" % os.path.basename(filename)) f.extract(filename, "C:\\tmp") szFilename = "C:\\tmp\\" + filename.replace('/', '\\') self.ExtractC2(szFilename) return True f.close()
def extract_config(self, apkfile): self.apkfile = apkfile a = apk.APK(self.apkfile) d = dvm.DalvikVMFormat(a.get_dex()) bLegit = False for cls in d.get_classes(): c2 = "" szVersion = "" szPrefix = "" szNum = "" string = None bFound = False if 'Constants;'.lower() in cls.get_name().lower(): for method in cls.get_methods(): if '<clinit>'.lower() in str( method).lower() and bFound == False: for inst in method.get_instructions(): if inst.get_name() == 'const-string': string = inst.get_output().split( ',')[-1].strip(" '") szTemp = string if inst.get_name() == 'const/4': string = inst.get_output().split( ',')[-1].strip(" '") szNum = string if inst.get_name() == 'sput-object': if "SERVER" in inst.get_output(): c2 = szTemp if "VERSION" in inst.get_output(): szVersion = szTemp if inst.get_name() == 'sput': if 'PREFIX_ID' in inst.get_output(): szPrefix = szNum bFound = True if self.isNotEmpty(c2): _log('[+] Extracting from %s' % self.apkfile) _log('[+] C&C: [ %s ]' % c2) _log('[+] Version : [ %s ]' % szVersion) _log('[+] Prefix ID : [ %s ]' % szPrefix) return True if bFound == False: _log('[-] This is probably not Flex Botnet or a variant : %s' % self.apkfile) return False
def verifyWhiteBroad(self, apkfile): self.apkfile = apkfile iNum = 0 a = apk.APK(apkfile) szPackageName = a.get_package() if szPackageName == "com.red.rainbow": bRes = self.extract_config(self.apkfile) return bRes elif "com.android.hellon" in szPackageName: bRes = self.extract_config2(self.apkfile) return bRes elif "cn.close.vcl.play" in szPackageName: bRes = self.extract_config(self.apkfile) return bRes else: szPermissions = " ".join(a.get_permissions()) matchObj = re.search(r'android\.permission\.INTERNET', szPermissions, re.DOTALL | re.UNICODE | re.M | re.I) if matchObj: iNum += 1 szActivities = "".join(a.get_activities()) matchObj = re.search(r'activity\.MainActivity', szActivities, re.DOTALL | re.UNICODE | re.M | re.I) if matchObj: iNum += 1 szReceivers = "".join(a.get_receivers()) matchObj = re.search(r'receiver\.ShowReceiver', szReceivers, re.DOTALL | re.UNICODE | re.M | re.I) if matchObj: iNum += 1 szServices = "".join(a.get_services()) matchObj = re.search(r'call\.service\.New1Services', szServices, re.DOTALL | re.UNICODE | re.M | re.I) if matchObj: iNum += 1 if iNum == 4: bRes = self.extract_config(self.apkfile) return bRes else: _log("[-] This is not WhiteBroad")
def extract_config(self, apkfile): a = apk.APK(apkfile) d = dvm.DalvikVMFormat(a.get_dex()) for cls in d.get_classes(): if 'com/phone/stop/db/a;'.lower() in cls.get_name().lower(): c2 = "" tmp = [] string = None for method in cls.get_methods(): if 'Lcom/phone/stop/db/a;->i()Ljava/lang/String;'.lower() in str(method).lower(): for inst in method.get_instructions(): if inst.get_name() == 'const-string': string = inst.get_output() if "@" in string: c2 = string.split(',')[-1].strip(" '") #print c2 elif 'Lcom/phone/stop/db/a;->j()Ljava/lang/String;'.lower() in str(method).lower(): for inst in method.get_instructions(): if inst.get_name() == 'const-string': tmp.append(inst.get_output().split(',')[-1].strip(" '")) if self.isNotEmpty(c2): _log('[+] Extracting from %s' % apkfile) _log('[+] Email: [ %s ]' % c2[2:]) _log('[+] Password: [ %s ]' % tmp[1][2:]) return True
def extract_config(self, apkfile): self.apkfile = apkfile string = "" a = apk.APK(self.apkfile) d = dvm.DalvikVMFormat(a.get_dex()) for cls in d.get_classes(): if 'Lmy/app/client/ProcessCommand;'.lower() in cls.get_name().lower(): c2Found = False portFound = False c2 = "" port = "" string = None for method in cls.get_methods(): if 'loadPreferences'.lower() in str(method).lower(): for inst in method.get_instructions(): if inst.get_name() == 'const-string': string = inst.get_output().split(',')[-1].strip(" '") if c2Found == True: c2 = string c2Found = False if string == 'ip': c2Found = True if string == 'port': portFound = True if inst.get_name() == 'const/16': if portFound == True: string = inst.get_output().split(',')[-1].strip(" '") port = string if c2 and port: break server = "" if port: server = "{0}:{1}".format(c2, str(port)) else: server = c2 _log('[+] Extracting from %s' % apkfile) _log('[+] C&C: [ %s ]\n' % server) return True
def extract_config(self, apkfile): self.apkfile = apkfile string = "" a = apk.APK(self.apkfile) d = dvm.DalvikVMFormat(a.get_dex()) for cls in d.get_classes(): if 'psp/jsp/datamd/v;'.lower() in cls.get_name().lower(): c2 = "" string = None for method in cls.get_methods(): if '/v;-><clinit>()V'.lower() in str(method).lower(): for inst in method.get_instructions(): if inst.get_name() == 'const-string': string = inst.get_output().split( ',')[-1].strip(" '") if "." in string: c2 = string elif "/" in string: c2 = self.caesar(string, -1) if self.isNotEmpty(c2): _log('[+] Extracting from %s' % self.apkfile) _log('[+] C&C: [ %s ]' % c2) return True
def verifySyrianMT(self, apkfile): self.apkfile = apkfile a = apk.APK(self.apkfile) szPackageName = a.get_package() if szPackageName == "com.Google.Gmail" or szPackageName == "GOOD.BYE.GOOGLE" or szPackageName == "com.android.tester" or szPackageName == "com.syria.tel" or szPackageName == "syria.tel.ctu" or szPackageName == "com.syriatel.ctu": _log(" [+] Package Name : %s" % (szPackageName)) _log(" [+] This is likely a Syrian Mobile Trojan") bRes = self.extract_config(apkfile) if bRes == True: return True else: _log("[-] This is not Syrian Mobile Trojan")
def verifySpyNote(self, apkfile): try: self.apkfile = apkfile iNum = 0 a = apk.APK(self.apkfile) szPackageName = a.get_package() if szPackageName == "yps.eton.application": _log("[+] This is SpyNote") d = dvm.DalvikVMFormat(a.get_dex()) r = a.get_android_resources() app_name = '' app_name = r.get_string(szPackageName, "host", "\x00\x00") if app_name is not None: if self.isNotEmpty(app_name[1]): dat = app_name[1].split(",") _log('[+] Extracting from %s' % (self.apkfile)) _log('[+] C&C: [ %s:%s ]' % (dat[0], dat[1])) return True else: _log("[-] This is not SpyNote v2") except: pass