├── .gitignore ├── README.md ├── apkinfo.py └── config ├── keys.json └── shell.json /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .idea 3 | .DS_Store 4 | result/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## apkinfo 2 | 3 | **一键解析app信息+检查敏感信息** 4 | 5 | 用法: 6 | ``` 7 | python3 -m pip install apkutils 8 | 9 | python3 apkinfo.py -a path/to/app 10 | python3 apkinfo.py -f dir/to/app 11 | ``` 12 | 13 | 功能: 14 | 15 | - 解压app 16 | - 查壳 17 | - manifest解析 18 | - 签名查询 19 | - 敏感信息查询 20 | - url、ips 21 | - 手机号、身份证、银行卡等 22 | - 其他敏感信息,比如oss key、数据库链接地址等 23 | - 如果想自定义关键词,直接编辑`config/keys.json`即可 24 | -------------------------------------------------------------------------------- /apkinfo.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import os 3 | import sys 4 | import zipfile 5 | import subprocess 6 | from apkutils import APK 7 | import platform 8 | import re 9 | import json 10 | 11 | 12 | class APKInfo(): 13 | def __init__(self, apk_path): 14 | self.apk_path = os.path.abspath(apk_path) 15 | self.base_path = os.path.abspath(os.path.dirname(__file__)) 16 | self.apk = None 17 | self.result_path = None 18 | self.apk_name = None 19 | self.shell_type = None 20 | self.patterns = None 21 | self.pattern_file = None 22 | self.shellfeatures = None 23 | self.check() 24 | 25 | def shell_detect(self): 26 | try: 27 | zipfiles = zipfile.ZipFile(self.apk_path) 28 | namelist = zipfiles.namelist() # 得到压缩包里所有文件 29 | # zipfiles.extractall(path=os.path.join( 30 | # self.result_path, "files")) # 解压zip到result目录下 31 | 32 | for filename in namelist: 33 | for k, v in self.shellfeatures.items(): 34 | for shell in v: 35 | if shell in filename: 36 | shell_type = k 37 | return True, shell_type 38 | except: 39 | pass 40 | return False, "未加壳" 41 | 42 | def dex2jar(apk_path, savePath): 43 | try: 44 | subprocess.run( 45 | f"{dex2jar_path} --force {apk_path} --output {os.path.join(savePath, 'classed-dex2jar.jar')}", 46 | shell=True) 47 | return True 48 | except: 49 | pass 50 | return False 51 | 52 | def manifest(self): 53 | with open(os.path.join(self.result_path, "AndroidManifest.xml"), 54 | "w", 55 | encoding='utf-8') as f: 56 | f.write(self.apk.get_manifest()) 57 | 58 | print( 59 | f"{self.apkname}基础信息:package: {self.apk.package_name} Version: {self.apk._version_name} MainActivity: {self.apk.get_manifest_main_activities()}" 60 | ) 61 | 62 | def signinfo(self): 63 | try: 64 | # 获取签名信息 65 | for k, _ in self.apk.get_certs(): 66 | print(f"{self.apkname}签名信息:Signer:{k}") 67 | except: 68 | pass 69 | 70 | def finder(self, name, pattern, strings): 71 | matcher = re.compile(pattern) 72 | found = [] 73 | for string in strings: 74 | mo = matcher.search(string) 75 | if mo: 76 | found.append(mo.group()) 77 | return sorted(list(set(found))) 78 | 79 | def save(self, name, found): 80 | if not found: 81 | return 82 | with open(os.path.join(self.result_path, name), "a", 83 | encoding='utf-8') as f: 84 | f.write("\n".join(found)) 85 | 86 | def detect_strings(self): 87 | strings = set() 88 | for string in self.apk.get_dex_strings(): 89 | try: 90 | strings.add(string.decode(encoding="UTF-8")) 91 | except: 92 | pass 93 | with open(os.path.join(self.result_path, "strings.txt"), 94 | "w", 95 | encoding='utf-8') as f: 96 | for string in strings: 97 | f.write(f"{string}\n") 98 | 99 | for name, pattern in self.patterns.items(): 100 | if isinstance(pattern, list): 101 | for p in pattern: 102 | found = self.finder(name, p, strings) 103 | self.save(name, found) 104 | else: 105 | found = self.finder(name, pattern, strings) 106 | self.save(name, found) 107 | 108 | def check(self): 109 | print(f"下面开始分析:{self.apk_path}") 110 | if not os.path.exists(self.apk_path): 111 | raise (f"当前文件不存在") 112 | 113 | _, self.apkname = os.path.split(apk_path) 114 | self.result_path = os.path.join(self.base_path, "result", self.apkname) 115 | if not os.path.exists(self.result_path): 116 | os.makedirs(self.result_path) 117 | else: 118 | print(f"{self.apkname}: 检测到文件已经分析过,将会覆盖") 119 | self.pattern_file = os.path.join(self.base_path, "config", "keys.json") 120 | with open(self.pattern_file, encoding='utf-8') as f: 121 | self.patterns = json.load(f) 122 | shell_path = os.path.join(self.base_path, "config", "shell.json") 123 | with open(shell_path, encoding='utf-8') as f: 124 | self.shellfeatures = json.load(f) 125 | 126 | def analyse(self): 127 | # 先解压 + 查壳 128 | print(f"{self.apkname}: 开始查壳...") 129 | flag, self.shell_type = self.shell_detect() 130 | if flag: 131 | print(f"{self.apkname}: 经检测,该apk使用了{self.shell_type}进行加固") 132 | return 133 | else: 134 | print(f"{self.apkname}: 未检测到壳") 135 | 136 | self.apk = APK.from_file(self.apk_path) 137 | print(f"{self.apkname}: 下面开始解析apk...") 138 | # 解析manifest获取apk信息 139 | self.manifest() 140 | 141 | # 查看签名 142 | self.signinfo() 143 | 144 | # 字符串解析,查找敏感字符串 145 | self.detect_strings() 146 | print(f"{self.apkname}: 分析结束,结果保存在{self.result_path}") 147 | 148 | 149 | if __name__ == '__main__': 150 | parser = argparse.ArgumentParser(description='apk信息提取') 151 | parser.add_argument('-a', '--apk', help='指定apk路径') 152 | parser.add_argument('-d', '--dir', help='指定apk路径') 153 | args = parser.parse_args() 154 | apks = [] 155 | if args.apk: 156 | apks.append(args.apk) 157 | if args.dir: 158 | for filename in os.listdir(args.dir): 159 | if filename.endswith(".apk"): 160 | apks.append(os.path.join(args.dir, filename)) 161 | if not apks: 162 | print(f"请使用-a或者-f指定apk") 163 | sys.exit() 164 | 165 | for apk_path in apks: 166 | try: 167 | apk = APKInfo(apk_path) 168 | apk.analyse() 169 | except Exception as e: 170 | print(f"{apk_path}出错: {e}") 171 | import traceback 172 | traceback.print_exc() 173 | -------------------------------------------------------------------------------- /config/keys.json: -------------------------------------------------------------------------------- 1 | { 2 | "Amazon_AWS_Access_Key_ID": "([^A-Z0-9]|^)(AKIA|A3T|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{12,}", 3 | "Amazon_AWS_S3_Bucket": [ 4 | "//s3-[a-z0-9-]+\\.amazonaws\\.com/[a-z0-9._-]+", 5 | "//s3\\.amazonaws\\.com/[a-z0-9._-]+", 6 | "[a-z0-9.-]+\\.s3-[a-z0-9-]\\.amazonaws\\.com", 7 | "[a-z0-9.-]+\\.s3-website[.-](eu|ap|us|ca|sa|cn)", 8 | "[a-z0-9.-]+\\.s3\\.amazonaws\\.com", 9 | "amzn\\.mws\\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" 10 | ], 11 | "Artifactory_API_Token": "(?:\\s|=|:|\"|^)AKC[a-zA-Z0-9]{10,}", 12 | "Artifactory_Password": "(?:\\s|=|:|\"|^)AP[\\dABCDEF][a-zA-Z0-9]{8,}", 13 | "Authorization_Basic": "basic\\s[a-zA-Z0-9_\\-:\\.=]+", 14 | "Authorization_Bearer": "bearer\\s[a-zA-Z0-9_\\-:\\.=]+", 15 | "AWS_API_Key": "AKIA[0-9A-Z]{16}", 16 | "Basic_Auth_Credentials": "(?<=:\/\/)[a-zA-Z0-9]+:[a-zA-Z0-9]+@[a-zA-Z0-9]+\\.[a-zA-Z]+", 17 | "Cloudinary_Basic_Auth": "cloudinary:\/\/[0-9]{15}:[0-9A-Za-z]+@[a-z]+", 18 | "DEFCON_CTF_Flag": "O{3}\\{.*\\}", 19 | "Discord_BOT_Token": "((?:N|M|O)[a-zA-Z0-9]{23}\\.[a-zA-Z0-9-_]{6}\\.[a-zA-Z0-9-_]{27})$", 20 | "Facebook_Access_Token": "EAACEdEose0cBA[0-9A-Za-z]+", 21 | "Facebook_ClientID": "[f|F][a|A][c|C][e|E][b|B][o|O][o|O][k|K](.{0,20})?['\"][0-9]{13,17}", 22 | "Facebook_OAuth": "[f|F][a|A][c|C][e|E][b|B][o|O][o|O][k|K].*['|\"][0-9a-f]{32}['|\"]", 23 | "Facebook_Secret_Key": "([f|F][a|A][c|C][e|E][b|B][o|O][o|O][k|K]|[f|F][b|B])(.{0,20})?['\"][0-9a-f]{32}", 24 | "Firebase": "[a-z0-9.-]+\\.firebaseio\\.com", 25 | "Generic_API_Key": "[a|A][p|P][i|I][_]?[k|K][e|E][y|Y].*['|\"][0-9a-zA-Z]{32,45}['|\"]", 26 | "Generic_Secret": "[s|S][e|E][c|C][r|R][e|E][t|T].*['|\"][0-9a-zA-Z]{32,45}['|\"]", 27 | "GitHub": "[g|G][i|I][t|T][h|H][u|U][b|B].*['|\"][0-9a-zA-Z]{35,40}['|\"]", 28 | "GitHub_Access_Token": "([a-zA-Z0-9_-]*:[a-zA-Z0-9_-]+@github.com*)$", 29 | "Google_API_Key": "AIza[0-9A-Za-z\\-_]{35}", 30 | "Google_Cloud_Platform_OAuth": "[0-9]+-[0-9A-Za-z_]{32}\\.apps\\.googleusercontent\\.com", 31 | "Google_Cloud_Platform_Service_Account": "\"type\": \"service_account\"", 32 | "Google_OAuth_Access_Token": "ya29\\.[0-9A-Za-z\\-_]+", 33 | "HackerOne_CTF_Flag": "[h|H]1(?:[c|C][t|T][f|F])?\\{.*\\}", 34 | "HackTheBox_CTF_Flag": "[h|H](?:[a|A][c|C][k|K][t|T][h|H][e|E][b|B][o|O][x|X]|[t|T][b|B])\\{.*\\}$", 35 | "Heroku_API_Key": "[h|H][e|E][r|R][o|O][k|K][u|U].*[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}", 36 | "IP_Address": "(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])", 37 | "JSON_Web_Token": "(?i)^((?=.*[a-z])(?=.*[0-9])(?:[a-z0-9_=]+\\.){2}(?:[a-z0-9_\\-\\+\/=]*))$", 38 | "LinkFinder": "(?:\"|')(((?:[a-zA-Z]{1,10}:\/\/|\/\/)[^\"'\/]{1,}\\.[a-zA-Z]{2,}[^\"']{0,})|((?:\/|\\.\\.\/|\\.\/)[^\"'><,;| *()(%%$^\/\\\\\\[\\]][^\"'><,;|()]{1,})|([a-zA-Z0-9_\\-\/]{1,}\/[a-zA-Z0-9_\\-\/]{1,}\\.(?:[a-zA-Z]{1,4}|action)(?:[\\?|#][^\"|']{0,}|))|([a-zA-Z0-9_\\-\/]{1,}\/[a-zA-Z0-9_\\-\/]{3,}(?:[\\?|#][^\"|']{0,}|))|([a-zA-Z0-9_\\-]{1,}\\.(?:php|asp|aspx|jsp|json|action|html|js|txt|xml)(?:[\\?|#][^\"|']{0,}|)))(?:\"|')", 39 | "Mac_Address": "(([0-9A-Fa-f]{2}[:]){5}[0-9A-Fa-f]{2}|([0-9A-Fa-f]{2}[-]){5}[0-9A-Fa-f]{2}|([0-9A-Fa-f]{4}[\\.]){2}[0-9A-Fa-f]{4})$", 40 | "MailChimp_API_Key": "[0-9a-f]{32}-us[0-9]{1,2}", 41 | "Mailgun_API_Key": "key-[0-9a-zA-Z]{32}", 42 | "Mailto": "(?<=mailto:)[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9.-]+", 43 | "Password_in_URL": "[a-zA-Z]{3,10}://[^/\\s:@]{3,20}:[^/\\s:@]{3,20}@.{1,100}[\"'\\s]", 44 | "PayPal_Braintree_Access_Token": "access_token\\$production\\$[0-9a-z]{16}\\$[0-9a-f]{32}", 45 | "PGP_private_key_block": "-----BEGIN PGP PRIVATE KEY BLOCK-----", 46 | "Picatic_API_Key": "sk_live_[0-9a-z]{32}", 47 | "RSA_Private_Key": "-----BEGIN RSA PRIVATE KEY-----", 48 | "Slack_Token": "(xox[p|b|o|a]-[0-9]{12}-[0-9]{12}-[0-9]{12}-[a-z0-9]{32})", 49 | "Slack_Webhook": "https://hooks.slack.com/services/T[a-zA-Z0-9_]{8}/B[a-zA-Z0-9_]{8}/[a-zA-Z0-9_]{24}", 50 | "Square_Access_Token": "sq0atp-[0-9A-Za-z\\-_]{22}", 51 | "Square_OAuth_Secret": "sq0csp-[0-9A-Za-z\\-_]{43}", 52 | "SSH_DSA_Private_Key": "-----BEGIN DSA PRIVATE KEY-----", 53 | "SSH_EC_Private_Key": "-----BEGIN EC PRIVATE KEY-----", 54 | "Stripe_API_Key": "sk_live_[0-9a-zA-Z]{24}", 55 | "Stripe_Restricted_API_Key": "rk_live_[0-9a-zA-Z]{24}", 56 | "TryHackMe_CTF_Flag": "[t|T](?:[r|R][y|Y][h|H][a|A][c|C][k|K][m|M][e|E]|[h|H][m|M])\\{.*\\}$", 57 | "Twilio_API_Key": "SK[0-9a-fA-F]{32}", 58 | "Twitter_Access_Token": "[t|T][w|W][i|I][t|T][t|T][e|E][r|R].*[1-9][0-9]+-[0-9a-zA-Z]{40}", 59 | "Twitter_ClientID": "[t|T][w|W][i|I][t|T][t|T][e|E][r|R](.{0,20})?['\"][0-9a-z]{18,25}", 60 | "Twitter_OAuth": "[t|T][w|W][i|I][t|T][t|T][e|E][r|R].*['|\"][0-9a-zA-Z]{35,44}['|\"]", 61 | "Twitter_Secret_Key": "[t|T][w|W][i|I][t|T][t|T][e|E][r|R](.{0,20})?['\"][0-9a-z]{35,44}", 62 | "OSS":"([A|a]ccess[K|k]ey[I|i][d|D]|[A|a]ccess[K|k]ey[S|s]ecret)", 63 | "sensitives_list":["accessKey", "database", "ssh", "rdp", "smb", "mysql", "sqlserver", "oracle", 64 | "ftp", "mongodb", "memcached", "postgresql", "telnet", "smtp", "pop3", "imap", 65 | "vnc", "redis", "admin", "root", "config", "jdbc", ".properties", "aliyuncs", 66 | "oss"], 67 | "domain":["http://","https://"], 68 | "Chinese_Bank_Card_ID":"[^0-9]([1-9]\\d{12,18})[^0-9]", 69 | "MAC_Address" :"(^([a-fA-F0-9]{2}(:[a-fA-F0-9]{2}){5})|[^a-zA-Z0-9]([a-fA-F0-9]{2}(:[a-fA-F0-9]{2}){5}))", 70 | "Phone_Number":"[^\\w]((?:(?:\\+|00)86)?1(?:(?:3[\\d])|(?:4[5-79])|(?:5[0-35-9])|(?:6[5-7])|(?:7[0-8])|(?:8[\\d])|(?:9[189]))\\d{8})[^\\w]", 71 | "IDcard":"'[^0-9]((\\d{8}(0\\d|10|11|12)([0-2]\\d|30|31)\\d{3}$)|(\\d{6}(18|19|20)\\d{2}(0[1-9]|10|11|12)([0-2]\\d|30|31)\\d{3}(\\d|X|x)))[^0-9]'", 72 | "Email":"(([a-zA-Z0-9][_|\\.])*[a-zA-Z0-9]+@([a-zA-Z0-9][-|_|\\.])*[a-zA-Z0-9]+\\.((?!js|css|jpg|jpeg|png|ico)[a-zA-Z]{2,}))" 73 | } -------------------------------------------------------------------------------- /config/shell.json: -------------------------------------------------------------------------------- 1 | { 2 | "360":[ 3 | "1ibjgdtc.so", 4 | "libjgdtc_a64.so", 5 | "libjgdtc_x64.so", 6 | "libjiagu_x64.so", 7 | "libjiagu_art.so", 8 | "libjiagu_ls.so", 9 | "libjiagu.so", 10 | "libjgdtc_x86.so", 11 | ".appkey", 12 | "libjgdtc_art.so", 13 | "libjiagu_x86.so", 14 | "libjiagu_a64.so", 15 | "libprotectClass.so" 16 | ], 17 | "APKProtect":[ 18 | "libAPKProtect.so" 19 | ], 20 | "UU安全":[ 21 | "libuusafe.so", 22 | "libuusafeempty.so", 23 | "libuusafe.jar.so" 24 | ], 25 | "apktoolplus":[ 26 | "jiagu_data.bin", 27 | "libapktoolplus_jiagu.so", 28 | "sign.bin" 29 | ], 30 | "中国移动加固":[ 31 | "libcmvmp.so", 32 | "mogosec_classes", 33 | "libmogosec_dex.so", 34 | "mogosec_march", 35 | "libmogosec_sodecrypt.so", 36 | "mogosec_data", 37 | "ibmogosecurity.so", 38 | "mogosec_dexinfo" 39 | ], 40 | "几维安全":[ 41 | "libkwslinker.so", 42 | "libkwscmm.so", 43 | "libkwscr.so" 44 | ], 45 | "启明星辰":[ 46 | "libvenustech.so", 47 | "libvenSec.so" 48 | ], 49 | "国信灵通":[ 50 | "libnqshield.so" 51 | ], 52 | "娜迦":[ 53 | "libchaosvmp.so", 54 | "libddog.so", 55 | "libfdog.so" 56 | ], 57 | "娜迦企业版":[ 58 | "libedog.so" 59 | ], 60 | "梆梆":[ 61 | "libsecexe.so", 62 | "libsecmain.so", 63 | "libSecShell.so" 64 | ], 65 | "梆梆企业版":[ 66 | "libDexHelper-x86.so", 67 | "libDexHelper.so" 68 | ], 69 | "海云安加固":[ 70 | "libitsec.so" 71 | ], 72 | "爱加密":[ 73 | "libexec.so", 74 | "ijiami.dat", 75 | "ijiami.ajm", 76 | "libexecmain.so" 77 | ], 78 | "爱加密企业版":[ 79 | "ijiami.ajm" 80 | ], 81 | "珊瑚灵御":[ 82 | "libreincp_x86.so", 83 | "libreincp.so" 84 | ], 85 | "瑞星加固":[ 86 | "librsprotect.so" 87 | ], 88 | "百度加固":[ 89 | "libbaiduprotect.so", 90 | "libbaiduprotect_x86.so", 91 | "libbaiduprotect_art.so", 92 | "baiduprotect1.jar" 93 | ], 94 | "盛大加固":[ 95 | "libapssec.so" 96 | ], 97 | "网易易盾":[ 98 | "libnesec.so" 99 | ], 100 | "网秦加固":[ 101 | "libnqshield.so" 102 | ], 103 | "腾讯乐固(日版)":[ 104 | "libshel1x" 105 | ], 106 | "腾讯乐固(旧版)":[ 107 | "libshell.so", 108 | "libshella", 109 | "liblegudb.so", 110 | "mix.dex", 111 | "mixz.dex", 112 | "libtup.so", 113 | "libexec.so" 114 | ], 115 | "腾讯云移动应用安全(腾讯御安全)":[ 116 | "libtosprotection.armeabi-v7a.so", 117 | "libtosprotection.armeabi.so", 118 | "libBugly-yaq.so", 119 | "000001111111", 120 | "00000o11111.dex", 121 | "000000011111.dex", 122 | "tosversion", 123 | "libshellx-super.2019.so", 124 | "t86", 125 | "tosprotection", 126 | "libtosprotection.x86.so", 127 | "libshell-super.2019.so", 128 | "o0ooo000oo0o.dat", 129 | "000000111111.dex", 130 | "libzBugly-yaq.so" 131 | ], 132 | "腾讯御安全":[ 133 | "libtosprotection.armeabi-v7a.so", 134 | "libtosprotection.armeabi.so", 135 | "libtosprotection.x86.so" 136 | ], 137 | "通付盾":[ 138 | "libegis.so", 139 | "libNSaferOnly.so" 140 | ], 141 | "阿里聚安全":[ 142 | "libzumadata.so", 143 | "libdemolish.so", 144 | "libpreverify1.so", 145 | "libzuma.so", 146 | "libdemolishdata.so", 147 | "libsgsecuritybody.so", 148 | "libfakejni.so", 149 | "libsgmain.so", 150 | "aliprotect.dat", 151 | "libmobisec.so" 152 | ], 153 | "顶像科技":[ 154 | "libx3g.so" 155 | ] 156 | } 157 | --------------------------------------------------------------------------------