├── AnalysisCSN ├── CSN.py └── __init__.py ├── AnalysisDEX ├── InitDEX.py └── __init__.py ├── AnalysisXML ├── AXML.py ├── AXMLParser.py ├── AXMLPrinter.py └── __init__.py ├── ApkDetecter.py ├── ApkDetecter.pyw ├── ApkInfo.py ├── CheckProtect.py ├── DexInfo.py ├── GUI ├── __init__.py ├── apkdetecter_ui.py ├── apkdetecter_ui.ui ├── apkinfo_ui.py ├── apkinfo_ui.ui ├── dexinfor_ui.py └── dexinfor_ui.ui ├── README.md ├── TestCSN.py ├── UnzipAPK.py ├── __init__.py ├── androguard ├── __init__.py └── core │ ├── __init__.py │ ├── __init__.pyc │ ├── analysis │ ├── __init__.py │ ├── analysis.py │ ├── ganalysis.py │ ├── risk.py │ └── sign.py │ ├── androconf.py │ ├── androconf.pyc │ ├── androgen.py │ ├── bytecode.py │ ├── bytecode.pyc │ ├── bytecodes │ ├── __init__.py │ ├── api_permissions.py │ ├── apk 2.py │ ├── apk.py │ ├── arm.py │ ├── dvm.py │ ├── dvm_permissions.py │ ├── jvm.py │ ├── jvm_generate.py │ └── libdvm │ │ ├── Makefile │ │ ├── __init__.py │ │ ├── buff.cc │ │ ├── buff.h │ │ ├── dvm.cc │ │ ├── dvm.h │ │ └── test_dvm.py │ └── data │ ├── __init__.py │ └── data.py ├── core ├── __init__.py ├── __init__.pyc ├── chilkatCert │ ├── __init__.py │ ├── __init__.pyc │ ├── mac │ │ ├── __init__.py │ │ ├── _chilkat.so │ │ └── chilkat.py │ ├── win32 │ │ ├── __init__.py │ │ ├── __init__.pyc │ │ ├── _chilkat.pyd │ │ ├── chilkat.py │ │ └── chilkat.pyc │ └── win64 │ │ ├── __init__.py │ │ ├── _chilkat.pyd │ │ └── chilkat.py ├── extraTools.py └── kernel.py └── tool ├── 7z.dll ├── 7z.exe ├── AXMLPrinter2.jar ├── baksmali.jar ├── dexdump ├── dexdump.exe ├── libeay32.dll ├── openssl.exe ├── smaliParserX.jar ├── ssleay32.dll └── wget.exe /AnalysisCSN/CSN.py: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8-*- 2 | __author__ = 'Andy' 3 | import os 4 | from hashlib import md5, sha1, sha256 5 | from base64 import b64encode 6 | from core.chilkatCert.win32 import chilkat 7 | 8 | BLACK_LIST_CSN = [ 9 | ('936eacbe07f201df', 'Google测试证书(打包党)'), 10 | ('4f33fcd6', 'a.risk.zhigao')] 11 | 12 | class CSN: 13 | def __init__(self, filename): 14 | self.filename = filename 15 | self.raw = open(filename, 'rb').read() 16 | self.success, self.cert = self.get_obj_certificate() 17 | 18 | def get_filename(self): 19 | return self.filename 20 | 21 | def get_filename_abs(self): 22 | filePath, filename = os.path.split(self.filename) 23 | # return filename[:-4].strip(" ") 24 | return filename[:-4] 25 | 26 | def get_filename_rel(self): 27 | s, f = os.path.splitext(self.filename) 28 | return s 29 | 30 | def get_file_path(self): 31 | filePath, filename = os.path.split(self.filename) 32 | return filePath 33 | 34 | def getLogPath(self): 35 | savePath, fileType = os.path.splitext(self.filename) 36 | return savePath.strip(" ") + ".txt" 37 | 38 | def get_md5(self): 39 | return md5(open(self.filename, "rb").read()).hexdigest() 40 | 41 | def get_sha1(self): 42 | return sha1(open(self.filename, "rb").read()).hexdigest() 43 | 44 | def get_digest(self): 45 | return b64encode(sha1(open(self.filename, "rb").read()).digest()) 46 | 47 | def get_sha256(self): 48 | return sha256(open(self.filename, "rb").read()).hexdigest() 49 | 50 | def get_size(self): 51 | return str(os.path.getsize(self.filename)) 52 | 53 | def get_obj_certificate(self): 54 | cert = chilkat.CkCert() 55 | f = self.raw 56 | bytedata = chilkat.CkByteData() 57 | bytedata.append2(f, len(f)) 58 | success = cert.LoadFromBinary(bytedata) 59 | 60 | return success, cert 61 | 62 | def getCertificateSN(self): 63 | success, cert = self.get_obj_certificate() 64 | 65 | if self.success: 66 | x = [] 67 | c = self.cert.serialNumber() 68 | for i in c: 69 | x.append(i) 70 | 71 | if x[0] == x[1] == '0': 72 | x = x[2:] 73 | return ''.join(x).lower() 74 | else: 75 | return ''.join(x).lower() 76 | 77 | # def getCertificateIDN(self): 78 | # if self.success: 79 | # return 'C=' + self.cert.issuerC() + ', CN=' + self.cert.issuerCN() + ', DN=' + self.cert.issuerDN() + \ 80 | # ', E=' + self.cert.issuerE() + ', L=' + self.cert.issuerL() + ', O=' + self.cert.issuerO() + \ 81 | # ', OU=' + self.cert.issuerOU() + ', S=' + self.cert.issuerS() 82 | # else: 83 | # return None 84 | 85 | def getCertificateIDN(self): 86 | if self.success: 87 | return 'C=' + str(self.cert.issuerC()) + ', CN=' + str(self.cert.issuerCN() + ', DN=' + str(self.cert.issuerDN()) + \ 88 | ', E=' + str(self.cert.issuerE()) + ', L=' + str(self.cert.issuerL()) + ', O=') + str(self.cert.issuerO()) + \ 89 | ', OU=' + str(self.cert.issuerOU()) + ', S=' + str(self.cert.issuerS()) 90 | else: 91 | return None 92 | 93 | def getCertificateSDN(self): 94 | if self.success: 95 | return 'C=' + self.cert.subjectC() + ', CN=' + self.cert.subjectCN() + ', DN=' + self.cert.subjectDN() + \ 96 | ', E=' + self.cert.subjectE() + ', L=' + self.cert.subjectL() + ', O=' + self.cert.subjectO() + \ 97 | ', OU=' + self.cert.subjectOU() + ', S=' + self.cert.subjectS() 98 | else: 99 | return None 100 | 101 | def check_black_csn(self, csn, black_list_csn=BLACK_LIST_CSN): 102 | for k, v in black_list_csn: 103 | if k == csn: 104 | return v 105 | 106 | -------------------------------------------------------------------------------- /AnalysisCSN/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'Andy' 2 | -------------------------------------------------------------------------------- /AnalysisDEX/InitDEX.py: -------------------------------------------------------------------------------- 1 | __author__ = 'Andy' 2 | 3 | class InitDEX(): 4 | 5 | def __init__(self): 6 | self.dexheader = { 7 | "header_magic": u"", 8 | "header_checksum": u"", 9 | "header_signature": u"", 10 | "header_fileSize": u"", 11 | "header_headerSize": u"", 12 | "header_endianTag": u"", 13 | "header_linkSize": u"", 14 | "header_linkOff": u"", 15 | "header_mapOff": u"", 16 | "header_stringIdsSize": u"", 17 | "header_stringIdsOff": u"", 18 | "header_typeIdsSize": u"", 19 | "header_typeIdsOff": u"", 20 | "header_protoIdsSize": u"", 21 | "header_protoIdsOff": u"", 22 | "header_fieldIdsSize": u"", 23 | "header_fieldIdsOff": u"", 24 | "header_methodIdsSize": u"", 25 | "header_methodIdsOff": u"", 26 | "header_classDefsSize": u"", 27 | "header_classDefsOff": u"", 28 | "header_dataSize": u"", 29 | "header_dataOff": u""} 30 | 31 | def getDexInfo(self, path): 32 | 33 | self.dexheader.clear() 34 | infile = file(path, "rb") 35 | 36 | infile.seek(0, 1) 37 | byte = infile.read(8) 38 | hexstr = "%s" % byte.encode('hex') 39 | self.dexheader["header_magic"] = hexstr.upper() 40 | 41 | byte = infile.read(4) 42 | hexstr = "%s" % byte.encode('hex') 43 | self.dexheader["header_checksum"] = hexstr.upper() 44 | 45 | byte = infile.read(20) 46 | hexstr = "%s" % byte.encode('hex') 47 | self.dexheader["header_signature"] = hexstr.upper() 48 | 49 | byte = infile.read(4) 50 | hexstr = "%s" % byte.encode('hex') 51 | self.dexheader["header_fileSize"] = hexstr.upper() 52 | 53 | byte = infile.read(4) 54 | hexstr = "%s" % byte.encode('hex') 55 | self.dexheader["header_headerSize"] = hexstr.upper() 56 | 57 | byte = infile.read(4) 58 | hexstr = "%s" % byte.encode('hex') 59 | self.dexheader["header_endianTag"] = hexstr.upper() 60 | 61 | byte = infile.read(4) 62 | hexstr = "%s" % byte.encode('hex') 63 | self.dexheader["header_linkSize"] = hexstr.upper() 64 | 65 | byte = infile.read(4) 66 | hexstr = "%s" % byte.encode('hex') 67 | self.dexheader["header_linkOff"] = hexstr.upper() 68 | 69 | byte = infile.read(4) 70 | hexstr = "%s" % byte.encode('hex') 71 | self.dexheader["header_mapOff"] = hexstr.upper() 72 | 73 | byte = infile.read(4) 74 | hexstr = "%s" % byte.encode('hex') 75 | self.dexheader["header_stringIdsSize"] = hexstr.upper() 76 | 77 | byte = infile.read(4) 78 | hexstr = "%s" % byte.encode('hex') 79 | self.dexheader["header_stringIdsOff"] = hexstr.upper() 80 | 81 | byte = infile.read(4) 82 | hexstr = "%s" % byte.encode('hex') 83 | self.dexheader["header_typeIdsSize"] = hexstr.upper() 84 | 85 | byte = infile.read(4) 86 | hexstr = "%s" % byte.encode('hex') 87 | self.dexheader["header_typeIdsOff"] = hexstr.upper() 88 | 89 | byte = infile.read(4) 90 | hexstr = "%s" % byte.encode('hex') 91 | self.dexheader["header_protoIdsSize"] = hexstr.upper() 92 | 93 | byte = infile.read(4) 94 | hexstr = "%s" % byte.encode('hex') 95 | self.dexheader["header_protoIdsOff"] = hexstr.upper() 96 | 97 | byte = infile.read(4) 98 | hexstr = "%s" % byte.encode('hex') 99 | self.dexheader["header_fieldIdsSize"] = hexstr.upper() 100 | 101 | byte = infile.read(4) 102 | hexstr = "%s" % byte.encode('hex') 103 | self.dexheader["header_fieldIdsOff"] = hexstr.upper() 104 | 105 | byte = infile.read(4) 106 | hexstr = "%s" % byte.encode('hex') 107 | self.dexheader["header_methodIdsSize"] = hexstr.upper() 108 | 109 | byte = infile.read(4) 110 | hexstr = "%s" % byte.encode('hex') 111 | self.dexheader["header_methodIdsOff"] = hexstr.upper() 112 | 113 | byte = infile.read(4) 114 | hexstr = "%s" % byte.encode('hex') 115 | self.dexheader["header_classDefsSize"] = hexstr.upper() 116 | 117 | byte = infile.read(4) 118 | hexstr = "%s" % byte.encode('hex') 119 | self.dexheader["header_classDefsOff"] = hexstr.upper() 120 | 121 | byte = infile.read(4) 122 | hexstr = "%s" % byte.encode('hex') 123 | self.dexheader["header_dataSize"] = hexstr.upper() 124 | 125 | byte = infile.read(4) 126 | hexstr = "%s" % byte.encode('hex') 127 | self.dexheader["header_dataOff"] = hexstr.upper() 128 | 129 | infile.close() 130 | return self.dexheader 131 | 132 | 133 | 134 | 135 | if __name__ == "__main__": 136 | obj = InitDEX() 137 | obj.getDexInfo() 138 | -------------------------------------------------------------------------------- /AnalysisDEX/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'Andy' 2 | -------------------------------------------------------------------------------- /AnalysisXML/AXML.py: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8-*- 2 | __author__ = 'Andy' 3 | import os 4 | from hashlib import md5, sha1, sha256 5 | from base64 import b64encode 6 | from xml.dom import minidom 7 | from AXMLPrinter import AXMLPrinter 8 | 9 | MIN_SDK_VERSION = { 10 | "1": "Android 1.0", 11 | "2": "Android 1.1", 12 | "3": "Android 1.5", 13 | "4": "Android 1.6", 14 | "5": "Android 2.0", 15 | "6": "Android 2.0.1", 16 | "7": "Android 2.1-update1", 17 | "8": "Android 2.2", 18 | "9": "Android 2.3 - 2.3.2", 19 | "10": "Android 2.3.3 - 2.3.4", 20 | "11": "Android 3.0", 21 | "12": "Android 3.1", 22 | "13": "Android 3.2", 23 | "14": "Android 4.0.0 - 4.0.2", 24 | "15": "Android 4.0.3 - 4.0.4", 25 | "16": "Android 4.1 - 4.1.1", 26 | "17": "Android 4.2 - 4.2.2", 27 | } 28 | 29 | RISK_PERMISSION = { 30 | "android.permission.SEND_SMS": "可无提示直接发送短信", 31 | "android.permission.RECEIVE_SMS": "可监控短信接收", 32 | "android.permission.CALL_PRIVILEGED": "可无提示直接拨打电话", 33 | "android.permission.INTERNET": "具有完全的互联网访问权限", 34 | "android.permission.READ_CONTACTS": "可读取联系人信息", 35 | "android.permission.WRITE_CONTACTS": "可修改联系人信息", 36 | "android.permission.CHANGE_WIFI_STATE": "可修改手机当前WIFI设置", 37 | "android.permission.WRITE_EXTERNAL_STORAGE": "可对存储卡进行读写操作", 38 | "com.android.launcher.permission.INSTALL_SHORTCUT": "可创建程序快捷方式", 39 | "android.permission.READ_PHONE_STATE": "可读取手机状态和身份", 40 | "android.permission.INSTALL_PACKAGES": "可安装其它程序", 41 | "android.permission.READ_SMS": "读取短信或彩信", 42 | "android.permission.WRITE_SMS": "编辑短信或彩信", 43 | "android.permission.RESTART_PACKAGES": "重启应用程序", 44 | "android.permission.CALL_PHONE": "直接拨打电话", 45 | "android.permission.ACCESS_COARSE_LOCATION": "可获取当前粗略位置信息", 46 | "android.permission.ACCESS_FINE_LOCATION": "可获取当前精确位置信息", 47 | } 48 | 49 | class AXML: 50 | def __init__(self, filename): 51 | self.filename = filename 52 | self.raw = open(filename, 'rb').read() 53 | self.xml = {} 54 | self.package = "" 55 | self.androidversion = {} 56 | self.permissions = [] 57 | 58 | self.xml[filename] = minidom.parseString(AXMLPrinter(self.raw).getBuff()) 59 | self.package = self.xml[filename].documentElement.getAttribute("package") 60 | self.androidversion["Code"] = self.xml[filename].documentElement.getAttribute("android:versionCode") 61 | self.androidversion["Name"] = self.xml[filename].documentElement.getAttribute("android:versionName") 62 | 63 | for item in self.xml[filename].getElementsByTagName('uses-permission'): 64 | self.permissions.append(str(item.getAttribute("android:name"))) 65 | 66 | def get_filename(self): 67 | return self.filename 68 | 69 | def get_filename_abs(self): 70 | filePath, filename = os.path.split(self.filename) 71 | # return filename[:-4].strip(" ") 72 | return filename[:-4] 73 | 74 | def get_filename_rel(self): 75 | s, f = os.path.splitext(self.filename) 76 | return s 77 | 78 | def get_file_path(self): 79 | filePath, filename = os.path.split(self.filename) 80 | return filePath 81 | 82 | def getLogPath(self): 83 | savePath, fileType = os.path.splitext(self.filename) 84 | return savePath.strip(" ") + ".txt" 85 | 86 | def get_md5(self): 87 | return md5(open(self.filename, "rb").read()).hexdigest() 88 | 89 | def get_sha1(self): 90 | return sha1(open(self.filename, "rb").read()).hexdigest() 91 | 92 | def get_digest(self): 93 | return b64encode(sha1(open(self.filename, "rb").read()).digest()) 94 | 95 | def get_sha256(self): 96 | return sha256(open(self.filename, "rb").read()).hexdigest() 97 | 98 | def get_size(self): 99 | return str(os.path.getsize(self.filename)) 100 | 101 | def get_package(self): 102 | return self.package 103 | 104 | def get_androidversion_name(self): 105 | return self.androidversion["Name"] 106 | 107 | def get_androidversion_code(self): 108 | return self.androidversion["Code"] 109 | 110 | def get_element(self, tag_name, attribute): 111 | """ 112 | Return element in xml files which match with the tag name and the specific attribute 113 | 114 | @param tag_name : a string which specify the tag name 115 | @param attribute : a string which specify the attribute 116 | """ 117 | for i in self.xml: 118 | for item in self.xml[i].getElementsByTagName(tag_name): 119 | value = item.getAttribute(attribute) 120 | 121 | if len(value) > 0: 122 | return value 123 | return None 124 | 125 | def getMinSdkVersion(self): 126 | minSdk = self.get_element("uses-sdk", "android:minSdkVersion") 127 | if minSdk: 128 | try: 129 | return MIN_SDK_VERSION[minSdk] 130 | except KeyError: 131 | return minSdk 132 | else: 133 | return "None" 134 | 135 | def getPermission(self): 136 | for i in self.xml: 137 | x = [] 138 | if not self.xml[i].getElementsByTagName('uses-permission'): 139 | return [] 140 | else: 141 | for item in self.xml[i].getElementsByTagName('uses-permission'): 142 | x.append(item.getAttribute("android:name")) 143 | 144 | if len(x) > 0: 145 | return x 146 | 147 | def getRiskPermission(self): 148 | x = [] 149 | permission = self.getPermission() 150 | 151 | if len(permission) == 0: 152 | return ["该程序未发现含有权限"] 153 | else: 154 | for i in permission: 155 | try: 156 | if RISK_PERMISSION[i] not in x: 157 | x.append(RISK_PERMISSION[i]) 158 | except KeyError: 159 | pass 160 | 161 | if len(x) > 0: 162 | return x 163 | else: 164 | return ["该程序未发现含有风险权限"] 165 | 166 | def format_value(self, value): 167 | if len(value) > 0: 168 | if value[0] == ".": 169 | value = self.package + value 170 | else: 171 | v_dot = value.find(".") 172 | if v_dot == 0: 173 | value = self.package + "." + value 174 | elif v_dot == -1: 175 | value = self.package + "." + value 176 | return value 177 | 178 | def checkManifest(self): 179 | """ 180 | 1 有activity,但是程序没有入口 181 | 2 有入口 182 | 3 无图标 183 | """ 184 | self.result = [self.filename] # + 185 | self.result.append("1") 186 | # self.result = ["1"] 187 | 188 | for i in self.xml: 189 | if self.xml[i].getElementsByTagName("activity"): 190 | x = set() 191 | y = set() 192 | for item in self.xml[i].getElementsByTagName("activity"): 193 | for sitem in item.getElementsByTagName("action"): 194 | val = sitem.getAttribute("android:name") 195 | if val == "android.intent.action.MAIN": 196 | x.add(item.getAttribute("android:name")) 197 | 198 | for sitem in item.getElementsByTagName("category"): 199 | val = sitem.getAttribute("android:name") 200 | if val == "android.intent.category.LAUNCHER": 201 | y.add(item.getAttribute("android:name")) 202 | 203 | z = x.intersection(y) 204 | 205 | if len(z) > 0: 206 | self.result[1] = "2" 207 | # self.result[0] = "2" 208 | self.result.append(self.format_value(z.pop())) 209 | return self.result 210 | else: 211 | self.result.append("0") 212 | # self.result.append("0") 213 | return self.result 214 | else: 215 | self.result[1] = "3" 216 | # self.result[0] = "3" 217 | self.result.append("0") 218 | return self.result 219 | 220 | def getDetailServices(self): 221 | """ 222 | Return the detail of the services 223 | :rtype: dict 224 | {'name1': ['action1', 'action2', ...], 225 | 'name2': ['action1', 'action2', ...], ... 226 | } 227 | """ 228 | x = {} 229 | y = [] 230 | 231 | for i in self.xml: 232 | for item in self.xml[i].getElementsByTagName("service"): 233 | val = self.format_value(item.getAttribute("android:name")) 234 | if not item.getElementsByTagName("action"): 235 | y.append("None") 236 | x[val] = y 237 | y = [] 238 | else: 239 | for sitem in item.getElementsByTagName("action"): 240 | a = sitem.getAttribute("android:name") 241 | y.append(self.format_value(a)) 242 | x[val] = y 243 | y = [] 244 | 245 | if x: 246 | return x 247 | else: 248 | return "None" 249 | 250 | def getDetailReceivers(self): 251 | """ 252 | Return the detail of the receivers 253 | :rtype: dict 254 | {'name1': ['action1,Priority1', 'action2,Priority2', ...], 255 | 'name2': ['action1,Priority1', 'action2,Priority2', ...], ... 256 | } 257 | 258 | """ 259 | x = {} 260 | y = [] 261 | 262 | for i in self.xml: 263 | for item in self.xml[i].getElementsByTagName("receiver"): 264 | val = self.format_value(item.getAttribute("android:name")) 265 | if not item.getElementsByTagName("action"): 266 | # y.append("None,None") 267 | y.append(["None", "None"]) 268 | x[val] = y 269 | y = [] 270 | else: 271 | for sitem in item.getElementsByTagName("action"): 272 | a = sitem.getAttribute("android:name") 273 | p = sitem.parentNode.getAttribute("android:priority") 274 | if not p: 275 | p = "None" 276 | # y.append(self.format_value(a) + "," + p) 277 | y.append([self.format_value(a), p]) 278 | x[val] = y 279 | y = [] 280 | 281 | if x: 282 | return x 283 | else: 284 | return "None" 285 | 286 | def get_xml(self): 287 | #print AXMLPrinter(self.raw).get_xml() 288 | return AXMLPrinter(self.raw).get_xml() 289 | -------------------------------------------------------------------------------- /AnalysisXML/AXMLParser.py: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8-*- 2 | __author__ = 'Andy' 3 | 4 | from androguard.core import bytecode 5 | from androguard.core.bytecode import SV 6 | 7 | ATTRIBUTE_IX_NAMESPACE_URI = 0 8 | ATTRIBUTE_IX_NAME = 1 9 | ATTRIBUTE_IX_VALUE_STRING = 2 10 | ATTRIBUTE_IX_VALUE_TYPE = 3 11 | ATTRIBUTE_IX_VALUE_DATA = 4 12 | ATTRIBUTE_LENGHT = 5 13 | 14 | CHUNK_AXML_FILE = 0x00080003 15 | CHUNK_RESOURCEIDS = 0x00080180 16 | CHUNK_XML_FIRST = 0x00100100 17 | CHUNK_XML_START_NAMESPACE = 0x00100100 18 | CHUNK_XML_END_NAMESPACE = 0x00100101 19 | CHUNK_XML_START_TAG = 0x00100102 20 | CHUNK_XML_END_TAG = 0x00100103 21 | CHUNK_XML_TEXT = 0x00100104 22 | CHUNK_XML_LAST = 0x00100104 23 | 24 | TYPE_STRING = 3 25 | 26 | START_DOCUMENT = 0 27 | END_DOCUMENT = 1 28 | START_TAG = 2 29 | END_TAG = 3 30 | TEXT = 4 31 | 32 | 33 | 34 | class AXMLParser: 35 | def __init__(self, raw_buff): 36 | self.reset() 37 | 38 | self.buff = bytecode.BuffHandle(raw_buff) 39 | 40 | self.buff.read(4) 41 | self.buff.read(4) 42 | 43 | self.sb = StringBlock(self.buff) 44 | 45 | self.m_resourceIDs = [] 46 | self.m_prefixuri = {} 47 | self.m_uriprefix = {} 48 | self.m_prefixuriL = [] 49 | 50 | def reset(self): 51 | self.m_event = -1 52 | self.m_lineNumber = -1 53 | self.m_name = -1 54 | self.m_namespaceUri = -1 55 | self.m_attributes = [] 56 | self.m_idAttribute = -1 57 | self.m_classAttribute = -1 58 | self.m_styleAttribute = -1 59 | 60 | def next(self): 61 | self.doNext() 62 | return self.m_event 63 | 64 | def doNext(self): 65 | if self.m_event == END_DOCUMENT: 66 | return 67 | 68 | event = self.m_event 69 | 70 | self.reset() 71 | while 1: 72 | chunkType = -1 73 | 74 | # Fake END_DOCUMENT event. 75 | if event == END_TAG: 76 | pass 77 | 78 | # START_DOCUMENT 79 | if event == START_DOCUMENT: 80 | chunkType = CHUNK_XML_START_TAG 81 | else: 82 | if self.buff.end() == True: 83 | self.m_event = END_DOCUMENT 84 | break 85 | chunkType = SV(' CHUNK_XML_LAST: 100 | raise ("ooo") 101 | 102 | # Fake START_DOCUMENT event. 103 | if chunkType == CHUNK_XML_START_TAG and event == -1: 104 | self.m_event = START_DOCUMENT 105 | break 106 | 107 | self.buff.read(4) #/*chunkSize*/ 108 | lineNumber = SV('> 16) - 1 139 | attributeCount = attributeCount & 0xFFFF 140 | self.m_classAttribute = SV('> 16) - 1 142 | 143 | self.m_classAttribute = (self.m_classAttribute & 0xFFFF) - 1 144 | 145 | for i in range(0, attributeCount * ATTRIBUTE_LENGHT): 146 | self.m_attributes.append(SV('> 24) 150 | 151 | self.m_event = START_TAG 152 | break 153 | 154 | if chunkType == CHUNK_XML_END_TAG: 155 | self.m_namespaceUri = SV('= len(self.m_attributes): 227 | raise ("Invalid attribute index") 228 | 229 | return offset 230 | 231 | def getAttributeCount(self): 232 | if self.m_event != START_TAG: 233 | return -1 234 | 235 | return len(self.m_attributes) / ATTRIBUTE_LENGHT 236 | 237 | def getAttributePrefix(self, index): 238 | offset = self.getAttributeOffset(index) 239 | uri = self.m_attributes[offset + ATTRIBUTE_IX_NAMESPACE_URI] 240 | 241 | prefix = self.getPrefixByUri(uri) 242 | if prefix == -1: 243 | return "" 244 | 245 | return self.sb.getRaw(prefix) 246 | 247 | def getAttributeName(self, index): 248 | offset = self.getAttributeOffset(index) 249 | name = self.m_attributes[offset + ATTRIBUTE_IX_NAME] 250 | 251 | if name == -1: 252 | return "" 253 | 254 | return self.sb.getRaw(name) 255 | 256 | def getAttributeValueType(self, index): 257 | offset = self.getAttributeOffset(index) 258 | return self.m_attributes[offset + ATTRIBUTE_IX_VALUE_TYPE] 259 | 260 | def getAttributeValueData(self, index): 261 | offset = self.getAttributeOffset(index) 262 | return self.m_attributes[offset + ATTRIBUTE_IX_VALUE_DATA] 263 | 264 | def getAttributeValue(self, index): 265 | offset = self.getAttributeOffset(index) 266 | valueType = self.m_attributes[offset + ATTRIBUTE_IX_VALUE_TYPE] 267 | if valueType == TYPE_STRING: 268 | valueString = self.m_attributes[offset + ATTRIBUTE_IX_VALUE_STRING] 269 | return self.sb.getRaw(valueString) 270 | # WIP 271 | return "" 272 | #int valueData=m_attributes[offset+ATTRIBUTE_IX_VALUE_DATA]; 273 | #return TypedValue.coerceToString(valueType,valueData); 274 | 275 | ######################################################## AXML FORMAT ######################################################## 276 | # Translated from http://code.google.com/p/android4me/source/browse/src/android/content/res/AXmlResourceParser.java 277 | class StringBlock: 278 | def __init__(self, buff): 279 | buff.read(4) 280 | 281 | self.chunkSize = SV('= len(self.m_stringOffsets): 325 | return None 326 | 327 | offset = self.m_stringOffsets[idx].get_value() 328 | length = self.getShort(self.m_strings, offset) 329 | 330 | data = "" 331 | 332 | while length > 0: 333 | offset += 2 334 | # Unicode character 335 | data += unichr(self.getShort(self.m_strings, offset)) 336 | 337 | # FIXME 338 | if data[-1] == "&": 339 | data = data[:-1] 340 | 341 | length -= 1 342 | 343 | return data 344 | 345 | def getShort(self, array, offset): 346 | value = array[offset / 4].get_value() 347 | if ((offset % 4) / 2) == 0: 348 | return value & 0xFFFF 349 | else: 350 | return value >> 16 351 | -------------------------------------------------------------------------------- /AnalysisXML/AXMLPrinter.py: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8-*- 2 | __author__ = 'Andy' 3 | 4 | from struct import pack, unpack 5 | from xml.dom import minidom 6 | from xml.sax.saxutils import escape 7 | 8 | from AXMLParser import AXMLParser 9 | from androguard.core import androconf 10 | 11 | 12 | TYPE_ATTRIBUTE = 2 13 | TYPE_DIMENSION = 5 14 | TYPE_FIRST_COLOR_INT = 28 15 | TYPE_FIRST_INT = 16 16 | TYPE_FLOAT = 4 17 | TYPE_FRACTION = 6 18 | TYPE_INT_BOOLEAN = 18 19 | TYPE_INT_COLOR_ARGB4 = 30 20 | TYPE_INT_COLOR_ARGB8 = 28 21 | TYPE_INT_COLOR_RGB4 = 31 22 | TYPE_INT_COLOR_RGB8 = 29 23 | TYPE_INT_DEC = 16 24 | TYPE_INT_HEX = 17 25 | TYPE_LAST_COLOR_INT = 31 26 | TYPE_LAST_INT = 31 27 | TYPE_NULL = 0 28 | TYPE_REFERENCE = 1 29 | TYPE_STRING = 3 30 | 31 | START_DOCUMENT = 0 32 | END_DOCUMENT = 1 33 | START_TAG = 2 34 | END_TAG = 3 35 | TEXT = 4 36 | 37 | RADIX_MULTS = [0.00390625, 3.051758E-005, 1.192093E-007, 4.656613E-010] 38 | DIMENSION_UNITS = ["px", "dip", "sp", "pt", "in", "mm", "", ""] 39 | FRACTION_UNITS = ["%", "%p", "", "", "", "", "", ""] 40 | 41 | COMPLEX_UNIT_MASK = 15 42 | class AXMLPrinter: 43 | def __init__(self, raw_buff): 44 | self.axml = AXMLParser(raw_buff) 45 | self.xmlns = False 46 | 47 | self.buff = "" 48 | 49 | while 1: 50 | _type = self.axml.next() 51 | # print "tagtype = ", _type 52 | 53 | if _type == START_DOCUMENT: 54 | self.buff += "\n" 55 | elif _type == START_TAG: 56 | self.buff += "<%s%s\n" % ( self.getPrefix(self.axml.getPrefix()), self.axml.getName() ) 57 | 58 | # FIXME : use namespace 59 | if self.xmlns == False: 60 | self.buff += self.axml.getXMLNS() 61 | self.xmlns = True 62 | 63 | for i in range(0, self.axml.getAttributeCount()): 64 | self.buff += "%s%s=\"%s\"\n" % ( self.getPrefix( 65 | self.axml.getAttributePrefix(i)), self.axml.getAttributeName(i), 66 | self._escape(self.getAttributeValue(i)) ) 67 | 68 | self.buff += ">\n" 69 | 70 | elif _type == END_TAG: 71 | self.buff += "\n" % ( self.getPrefix(self.axml.getPrefix()), self.axml.getName() ) 72 | 73 | elif _type == TEXT: 74 | self.buff += "%s\n" % self.axml.getText() 75 | 76 | elif _type == END_DOCUMENT: 77 | break 78 | 79 | # pleed patch 80 | def _escape(self, s): 81 | s = s.replace("&", "&") 82 | s = s.replace('"', """) 83 | s = s.replace("'", "'") 84 | s = s.replace("<", "<") 85 | s = s.replace(">", ">") 86 | 87 | return escape(s) 88 | 89 | 90 | def getBuff(self): 91 | return self.buff.encode("utf-8") 92 | 93 | def get_xml(self): 94 | # print self.getBuff()toprettyxml 95 | return minidom.parseString(self.getBuff()).toprettyxml(indent=" ", newl="", encoding = 'utf-8') 96 | # return minidom.parseString(self.getBuff()).toxml(encoding = 'utf-8') 97 | 98 | def getPrefix(self, prefix): 99 | if prefix == None or len(prefix) == 0: 100 | return "" 101 | 102 | return prefix + ":" 103 | 104 | def getAttributeValue(self, index): 105 | _type = self.axml.getAttributeValueType(index) 106 | _data = self.axml.getAttributeValueData(index) 107 | 108 | #print _type, _data 109 | if _type == TYPE_STRING: 110 | return self.axml.getAttributeValue(index) 111 | 112 | elif _type == TYPE_ATTRIBUTE: 113 | return "?%s%08X" % (self.getPackage(_data), _data) 114 | 115 | elif _type == TYPE_REFERENCE: 116 | return "@%s%08X" % (self.getPackage(_data), _data) 117 | 118 | # WIP 119 | elif _type == TYPE_FLOAT: 120 | return "%f" % unpack("=f", pack("=L", _data))[0] 121 | 122 | elif _type == TYPE_INT_HEX: 123 | return "0x%08X" % _data 124 | 125 | elif _type == TYPE_INT_BOOLEAN: 126 | if _data == 0: 127 | return "false" 128 | return "true" 129 | 130 | elif _type == TYPE_DIMENSION: 131 | return "%f%s" % (self.complexToFloat(_data), DIMENSION_UNITS[_data & COMPLEX_UNIT_MASK]) 132 | 133 | elif _type == TYPE_FRACTION: 134 | return "%f%s" % (self.complexToFloat(_data), FRACTION_UNITS[_data & COMPLEX_UNIT_MASK]) 135 | 136 | elif _type >= TYPE_FIRST_COLOR_INT and _type <= TYPE_LAST_COLOR_INT: 137 | return "#%08X" % _data 138 | 139 | elif _type >= TYPE_FIRST_INT and _type <= TYPE_LAST_INT: 140 | return "%d" % androconf.long2int(_data) 141 | 142 | return "<0x%X, type 0x%02X>" % (_data, _type) 143 | 144 | def complexToFloat(self, xcomplex): 145 | return (float)(xcomplex & 0xFFFFFF00) * RADIX_MULTS[(xcomplex >> 4) & 3]; 146 | 147 | def getPackage(self, id): 148 | if id >> 24 == 1: 149 | return "android:" 150 | return "" -------------------------------------------------------------------------------- /AnalysisXML/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'Andy' 2 | -------------------------------------------------------------------------------- /ApkDetecter.py: -------------------------------------------------------------------------------- 1 | #-*-encoding:utf-8-*- 2 | __author__ = 'Andy' 3 | import os 4 | import time 5 | import tempfile 6 | import io 7 | import sys 8 | import hashlib 9 | import thread 10 | import shutil 11 | from PyQt4 import QtCore, QtGui 12 | from AnalysisXML.AXML import AXML 13 | from DexInfo import DexInfoForm 14 | from ApkInfo import MyApkInfoForm 15 | from AnalysisDEX.InitDEX import InitDEX 16 | from CheckProtect import CheckProtect 17 | from AnalysisCSN.CSN import CSN 18 | from GUI.apkdetecter_ui import Ui_APKDetecter 19 | 20 | 21 | 22 | 23 | class ApkDetecterForm(QtGui.QMainWindow): 24 | def __init__(self, parent = None): 25 | QtGui.QWidget.__init__(self, parent) 26 | #super(ApkDetecterForm, self).__init__(parent) 27 | self._want_to_close = True 28 | self.dexheader = {} 29 | self.loadfile_path = "" 30 | #self.unpackDir = tempfile.mktemp() 31 | self.unpackDir = ur"c:\APK" 32 | isExists = os.path.exists(self.unpackDir) 33 | if not isExists: 34 | os.makedirs(ur"c:\APK") 35 | self.ui = Ui_APKDetecter() 36 | self.ui.setupUi(self) 37 | 38 | QtCore.QObject.connect(self.ui.file_open, QtCore.SIGNAL("clicked()"), self.file_dialog) 39 | self.ui.apk_info.clicked.connect(self.apkinfo_dialog) 40 | self.ui.extend_info.clicked.connect(self.extendinfo_dialog) 41 | 42 | def closeEvent(self, evnt): 43 | if self._want_to_close: 44 | super(ApkDetecterForm, self).closeEvent(evnt) 45 | self.clearfiles(self.unpackDir) 46 | print "Andy" 47 | 48 | 49 | def probar_thread(self, no, interval): 50 | 51 | for a in range(no, interval): 52 | time.sleep(0.1) 53 | self.ui.progressBar.setValue(a) 54 | thread.exit_thread() 55 | 56 | def unzip(self, apkpath): 57 | apkpath = unicode(apkpath, "utf8") 58 | cmd = "tool\\7z.exe x %s -y -o%s *.dex AndroidManifest.xml lib META-INF assets" 59 | print cmd % (apkpath, self.unpackDir) 60 | self.ui.progressBar.setMaximum(29) 61 | thread.start_new_thread(self.probar_thread, (3, 30)) 62 | os.system(cmd % (apkpath, self.unpackDir)) 63 | 64 | 65 | def Init_Main_text(self): 66 | self.ui.te_dex_flag.clear() 67 | self.ui.te_dexheader_size.clear() 68 | self.ui.te_endiantag.clear() 69 | self.ui.te_file_size.clear() 70 | self.ui.te_linkoff.clear() 71 | self.ui.te_linksize.clear() 72 | self.ui.te_protect.clear() 73 | 74 | def Init_Apkinfo_text(self): 75 | self.apkinfo.ui.edt_file.setText("") 76 | self.apkinfo.ui.edt_serial_num.setText("") 77 | self.apkinfo.ui.edt_publisher.setText("") 78 | self.apkinfo.ui.edt_issuer.setText("") 79 | self.apkinfo.ui.edt_dexmd5.setText("") 80 | self.apkinfo.ui.edt_apkmd5.setText("") 81 | self.apkinfo.ui.edt_package.setText("") 82 | self.apkinfo.ui.edt_version.setText("") 83 | self.apkinfo.ui.edt_version_num.setText("") 84 | self.apkinfo.ui.edt_version_need.setText("") 85 | 86 | def Init_DexInfo_text(self): 87 | self.dexinfo.ui.text_magic.setText("") 88 | self.dexinfo.ui.text_checksum.setText("") 89 | self.dexinfo.ui.text_file_size.setText("") 90 | self.dexinfo.ui.text_header_size.setText("") 91 | self.dexinfo.ui.text_endian_tag.setText("") 92 | self.dexinfo.ui.text_link_size.setText("") 93 | self.dexinfo.ui.text_link_off.setText("") 94 | self.dexinfo.ui.text_map_off.setText("") 95 | self.dexinfo.ui.text_string_ids_size.setText("") 96 | self.dexinfo.ui.text_string_ids_off.setText("") 97 | self.dexinfo.ui.text_type_ids_size.setText("") 98 | self.dexinfo.ui.text_type_ids_off.setText("") 99 | self.dexinfo.ui.text_proto_ids_size.setText("") 100 | self.dexinfo.ui.text_proto_ids_off.setText("") 101 | self.dexinfo.ui.text_field_ids_size.setText("") 102 | self.dexinfo.ui.text_field_ids_off.setText("") 103 | self.dexinfo.ui.text_method_ids_size.setText("") 104 | self.dexinfo.ui.text_method_ids_off.setText("") 105 | self.dexinfo.ui.text_class_defs_size.setText("") 106 | self.dexinfo.ui.text_class_defs_off.setText("") 107 | self.dexinfo.ui.text_data_size.setText("") 108 | self.dexinfo.ui.text_data_off.setText("") 109 | self.dexinfo.ui.text_sha.setText("") 110 | 111 | def clearfiles(self, delDir): 112 | delList = [] 113 | delList = os.listdir(delDir) 114 | 115 | for f in delList: 116 | filePath = os.path.join(delDir, f) 117 | if os.path.isfile(filePath): 118 | os.remove(filePath) 119 | elif os.path.isdir(filePath): 120 | shutil.rmtree(filePath, True) 121 | shutil.rmtree(delDir) 122 | 123 | 124 | 125 | 126 | 127 | def file_dialog(self): 128 | fd = QtGui.QFileDialog(self) 129 | 130 | self.Init_Main_text() 131 | self.loadfile_path = u"" 132 | self.loadfile_path = fd.getOpenFileName() 133 | 134 | #self.loadfile_path = unicode(self.loadfile_path, "utf8") 135 | self.loadfile_path = self.loadfile_path.replace("/", os.path.sep) 136 | 137 | 138 | if self.loadfile_path != u"": 139 | self.clearfiles(self.unpackDir) 140 | self.ui.te_path.setText(self.loadfile_path) 141 | self.unzip(self.loadfile_path) 142 | obj = CheckProtect(self.unpackDir) 143 | 144 | protect_flag = obj.check_protectflag() 145 | 146 | dexobj = InitDEX() 147 | self.dexheader ={} 148 | self.dexheader = dexobj.getDexInfo(self.unpackDir + os.path.sep + "classes.dex") 149 | 150 | self.ui.te_dex_flag.setText(self.dexheader["header_magic"]) 151 | self.ui.te_dexheader_size.setText(self.dexheader["header_headerSize"]) 152 | self.ui.te_endiantag.setText(self.dexheader["header_endianTag"]) 153 | self.ui.te_file_size.setText(self.dexheader["header_fileSize"]) 154 | self.ui.te_linkoff.setText(self.dexheader["header_linkOff"]) 155 | self.ui.te_linksize.setText(self.dexheader["header_linkSize"]) 156 | self.ui.te_protect.setText(protect_flag) 157 | 158 | else: 159 | return 160 | 161 | def GetFileMd5(self, path): 162 | try: 163 | file = open(path, 'rb') 164 | md5 = hashlib.md5() 165 | strRead = "" 166 | while True: 167 | strRead = file.read(8096) 168 | if not strRead: 169 | break 170 | md5.update(strRead) 171 | #read file finish 172 | strMd5 = md5.hexdigest() 173 | file.close() 174 | return strMd5 175 | except: 176 | return u"Sorry,计算出错!" 177 | 178 | 179 | 180 | 181 | 182 | def apkinfo_dialog(self): 183 | self.apkinfo = MyApkInfoForm() 184 | self.Init_Apkinfo_text() 185 | csn_path = self.unpackDir + os.path.sep + "META-INF" 186 | if os.path.isdir(csn_path): 187 | f_list = os.listdir(csn_path) 188 | 189 | for file_name in f_list: 190 | if os.path.splitext(file_name)[1] == '.RSA' or os.path.splitext(file_name)[1] == '.DSA': 191 | csn_path = csn_path + os.path.sep + file_name 192 | csn = CSN(csn_path) 193 | self.apkinfo.ui.edt_file.setText(str(csn.get_size())) 194 | self.apkinfo.ui.edt_serial_num.setText(str(csn.getCertificateSN()).upper()) 195 | self.apkinfo.ui.edt_publisher.setText(str(csn.getCertificateIDN())) 196 | self.apkinfo.ui.edt_issuer.setText(str(csn.getCertificateSDN())) 197 | break 198 | 199 | 200 | dex_path = self.unpackDir + os.path.sep + "classes.dex" 201 | if os.path.exists(dex_path): 202 | m = hashlib.md5() 203 | file = io.FileIO(dex_path, 'r') 204 | bytes = file.read(1024) 205 | while(bytes != b''): 206 | m.update(bytes) 207 | bytes = file.read(1024) 208 | file.close() 209 | dexmd5value = m.hexdigest() 210 | #print str(dexmd5value).upper() 211 | self.apkinfo.ui.edt_dexmd5.setText(str(dexmd5value).upper()) 212 | 213 | apkpath = unicode(self.loadfile_path, "utf8") 214 | if os.path.isfile(apkpath) and self.loadfile_path != "": 215 | pass 216 | if self.loadfile_path != "": 217 | #apkpath = unicode(self.loadfile_path, "utf8") 218 | 219 | apkmd5value = self.GetFileMd5(self.loadfile_path) 220 | 221 | # m = hashlib.md5() 222 | # file = io.FileIO(self.loadfile_path, 'r') 223 | # bytes = file.read(1024) 224 | # while(bytes != b''): 225 | # m.update(bytes) 226 | # bytes = file.read(1024) 227 | # file.close() 228 | # apkmd5value = m.hexdigest() 229 | self.apkinfo.ui.edt_apkmd5.setText(apkmd5value.upper()) 230 | 231 | 232 | path = self.unpackDir + os.path.sep +"AndroidManifest.xml" 233 | 234 | if os.path.exists(path): 235 | axml_analysis = AXML(self.unpackDir + os.path.sep +"AndroidManifest.xml") 236 | if axml_analysis.get_filename_abs() == 'AndroidManifest': 237 | self.apkinfo.ui.edt_package.setText(axml_analysis.get_package()) 238 | self.apkinfo.ui.edt_version.setText(axml_analysis.get_androidversion_name()) 239 | self.apkinfo.ui.edt_version_num.setText(axml_analysis.get_androidversion_code()) 240 | self.apkinfo.ui.edt_version_need.setText(axml_analysis.getMinSdkVersion()) 241 | 242 | 243 | 244 | self.apkinfo.show() 245 | 246 | def extendinfo_dialog(self): 247 | self.dexinfo = DexInfoForm() 248 | self.Init_DexInfo_text() 249 | if self.dexheader.has_key("header_magic"): 250 | self.dexinfo.ui.text_magic.setText(self.dexheader["header_magic"]) 251 | self.dexinfo.ui.text_checksum.setText(self.dexheader["header_checksum"]) 252 | self.dexinfo.ui.text_file_size.setText(self.dexheader["header_fileSize"]) 253 | self.dexinfo.ui.text_header_size.setText(self.dexheader["header_headerSize"]) 254 | self.dexinfo.ui.text_endian_tag.setText(self.dexheader["header_endianTag"]) 255 | self.dexinfo.ui.text_link_size.setText(self.dexheader["header_linkSize"]) 256 | self.dexinfo.ui.text_link_off.setText(self.dexheader["header_linkOff"]) 257 | self.dexinfo.ui.text_map_off.setText(self.dexheader["header_mapOff"]) 258 | self.dexinfo.ui.text_string_ids_size.setText(self.dexheader["header_stringIdsSize"]) 259 | self.dexinfo.ui.text_string_ids_off.setText(self.dexheader["header_stringIdsOff"]) 260 | self.dexinfo.ui.text_type_ids_size.setText(self.dexheader["header_typeIdsSize"]) 261 | self.dexinfo.ui.text_type_ids_off.setText(self.dexheader["header_typeIdsOff"]) 262 | self.dexinfo.ui.text_proto_ids_size.setText(self.dexheader["header_protoIdsSize"]) 263 | self.dexinfo.ui.text_proto_ids_off.setText(self.dexheader["header_protoIdsOff"]) 264 | self.dexinfo.ui.text_field_ids_size.setText(self.dexheader["header_fieldIdsSize"]) 265 | self.dexinfo.ui.text_field_ids_off.setText(self.dexheader["header_fieldIdsOff"]) 266 | self.dexinfo.ui.text_method_ids_size.setText(self.dexheader["header_methodIdsSize"]) 267 | self.dexinfo.ui.text_method_ids_off.setText(self.dexheader["header_methodIdsOff"]) 268 | self.dexinfo.ui.text_class_defs_size.setText(self.dexheader["header_classDefsSize"]) 269 | self.dexinfo.ui.text_class_defs_off.setText(self.dexheader["header_classDefsOff"]) 270 | self.dexinfo.ui.text_data_size.setText(self.dexheader["header_dataSize"]) 271 | self.dexinfo.ui.text_data_off.setText(self.dexheader["header_dataOff"]) 272 | self.dexinfo.ui.text_sha.setText(self.dexheader["header_signature"]) 273 | self.dexinfo.show() 274 | 275 | 276 | 277 | if __name__ == "__main__": 278 | 279 | app = QtGui.QApplication(sys.argv) 280 | myapp = ApkDetecterForm() 281 | myapp.show() 282 | sys.exit(app.exec_()) -------------------------------------------------------------------------------- /ApkDetecter.pyw: -------------------------------------------------------------------------------- 1 | #-*-encoding:utf-8-*- 2 | __author__ = 'Andy' 3 | import os 4 | import time 5 | import tempfile 6 | import io 7 | import sys 8 | import hashlib 9 | import thread 10 | import shutil 11 | from PyQt4 import QtCore, QtGui 12 | from AnalysisXML.AXML import AXML 13 | from DexInfo import DexInfoForm 14 | from ApkInfo import MyApkInfoForm 15 | from AnalysisDEX.InitDEX import InitDEX 16 | from CheckProtect import CheckProtect 17 | from AnalysisCSN.CSN import CSN 18 | from GUI.apkdetecter_ui import Ui_APKDetecter 19 | 20 | 21 | 22 | 23 | class ApkDetecterForm(QtGui.QMainWindow): 24 | def __init__(self, parent = None): 25 | QtGui.QWidget.__init__(self, parent) 26 | #super(ApkDetecterForm, self).__init__(parent) 27 | self._want_to_close = True 28 | self.dexheader = {} 29 | self.loadfile_path = "" 30 | #self.unpackDir = tempfile.mktemp() 31 | self.unpackDir = ur"c:\APK" 32 | isExists = os.path.exists(self.unpackDir) 33 | if not isExists: 34 | os.makedirs(ur"c:\APK") 35 | 36 | self.ui = Ui_APKDetecter() 37 | self.ui.setupUi(self) 38 | 39 | QtCore.QObject.connect(self.ui.file_open, QtCore.SIGNAL("clicked()"), self.file_dialog) 40 | self.ui.apk_info.clicked.connect(self.apkinfo_dialog) 41 | self.ui.extend_info.clicked.connect(self.extendinfo_dialog) 42 | 43 | def closeEvent(self, evnt): 44 | if self._want_to_close: 45 | super(ApkDetecterForm, self).closeEvent(evnt) 46 | self.clearfiles(self.unpackDir) 47 | print "Andy" 48 | 49 | 50 | def probar_thread(self, no, interval): 51 | 52 | for a in range(no, interval): 53 | time.sleep(0.1) 54 | self.ui.progressBar.setValue(a) 55 | thread.exit_thread() 56 | 57 | def unzip(self, apkpath): 58 | apkpath = unicode(apkpath, "utf8") 59 | cmd = "tool\\7z.exe x %s -y -o%s *.dex AndroidManifest.xml lib META-INF assets" 60 | print cmd % (apkpath, self.unpackDir) 61 | self.ui.progressBar.setMaximum(29) 62 | thread.start_new_thread(self.probar_thread, (3, 30)) 63 | os.system(cmd % (apkpath, self.unpackDir)) 64 | 65 | 66 | def Init_Main_text(self): 67 | self.ui.te_dex_flag.clear() 68 | self.ui.te_dexheader_size.clear() 69 | self.ui.te_endiantag.clear() 70 | self.ui.te_file_size.clear() 71 | self.ui.te_linkoff.clear() 72 | self.ui.te_linksize.clear() 73 | self.ui.te_protect.clear() 74 | 75 | def Init_Apkinfo_text(self): 76 | self.apkinfo.ui.edt_file.setText("") 77 | self.apkinfo.ui.edt_serial_num.setText("") 78 | self.apkinfo.ui.edt_publisher.setText("") 79 | self.apkinfo.ui.edt_issuer.setText("") 80 | self.apkinfo.ui.edt_dexmd5.setText("") 81 | self.apkinfo.ui.edt_apkmd5.setText("") 82 | self.apkinfo.ui.edt_package.setText("") 83 | self.apkinfo.ui.edt_version.setText("") 84 | self.apkinfo.ui.edt_version_num.setText("") 85 | self.apkinfo.ui.edt_version_need.setText("") 86 | 87 | def Init_DexInfo_text(self): 88 | self.dexinfo.ui.text_magic.setText("") 89 | self.dexinfo.ui.text_checksum.setText("") 90 | self.dexinfo.ui.text_file_size.setText("") 91 | self.dexinfo.ui.text_header_size.setText("") 92 | self.dexinfo.ui.text_endian_tag.setText("") 93 | self.dexinfo.ui.text_link_size.setText("") 94 | self.dexinfo.ui.text_link_off.setText("") 95 | self.dexinfo.ui.text_map_off.setText("") 96 | self.dexinfo.ui.text_string_ids_size.setText("") 97 | self.dexinfo.ui.text_string_ids_off.setText("") 98 | self.dexinfo.ui.text_type_ids_size.setText("") 99 | self.dexinfo.ui.text_type_ids_off.setText("") 100 | self.dexinfo.ui.text_proto_ids_size.setText("") 101 | self.dexinfo.ui.text_proto_ids_off.setText("") 102 | self.dexinfo.ui.text_field_ids_size.setText("") 103 | self.dexinfo.ui.text_field_ids_off.setText("") 104 | self.dexinfo.ui.text_method_ids_size.setText("") 105 | self.dexinfo.ui.text_method_ids_off.setText("") 106 | self.dexinfo.ui.text_class_defs_size.setText("") 107 | self.dexinfo.ui.text_class_defs_off.setText("") 108 | self.dexinfo.ui.text_data_size.setText("") 109 | self.dexinfo.ui.text_data_off.setText("") 110 | self.dexinfo.ui.text_sha.setText("") 111 | 112 | def clearfiles(self, delDir): 113 | delList = [] 114 | delList = os.listdir(delDir) 115 | 116 | for f in delList: 117 | filePath = os.path.join(delDir, f) 118 | if os.path.isfile(filePath): 119 | os.remove(filePath) 120 | elif os.path.isdir(filePath): 121 | shutil.rmtree(filePath, True) 122 | shutil.rmtree(delDir) 123 | 124 | 125 | 126 | def file_dialog(self): 127 | fd = QtGui.QFileDialog(self) 128 | 129 | self.Init_Main_text() 130 | self.loadfile_path = u"" 131 | self.loadfile_path = fd.getOpenFileName() 132 | #self.loadfile_path = unicode(self.loadfile_path, "utf8") 133 | self.loadfile_path = self.loadfile_path.replace("/", os.path.sep) 134 | 135 | if self.loadfile_path != u"": 136 | self.clearfiles(self.unpackDir) 137 | self.ui.te_path.setText(self.loadfile_path) 138 | self.unzip(self.loadfile_path) 139 | obj = CheckProtect(self.unpackDir) 140 | 141 | protect_flag = obj.check_protectflag() 142 | 143 | dexobj = InitDEX() 144 | self.dexheader ={} 145 | self.dexheader = dexobj.getDexInfo(self.unpackDir + os.path.sep + "classes.dex") 146 | 147 | self.ui.te_dex_flag.setText(self.dexheader["header_magic"]) 148 | self.ui.te_dexheader_size.setText(self.dexheader["header_headerSize"]) 149 | self.ui.te_endiantag.setText(self.dexheader["header_endianTag"]) 150 | self.ui.te_file_size.setText(self.dexheader["header_fileSize"]) 151 | self.ui.te_linkoff.setText(self.dexheader["header_linkOff"]) 152 | self.ui.te_linksize.setText(self.dexheader["header_linkSize"]) 153 | self.ui.te_protect.setText(protect_flag) 154 | 155 | else: 156 | return 157 | 158 | def GetFileMd5(self, path): 159 | try: 160 | file = open(path, 'rb') 161 | md5 = hashlib.md5() 162 | strRead = "" 163 | while True: 164 | strRead = file.read(8096) 165 | if not strRead: 166 | break 167 | md5.update(strRead) 168 | #read file finish 169 | strMd5 = md5.hexdigest() 170 | file.close() 171 | return strMd5 172 | except: 173 | return u"Sorry,计算出错!" 174 | 175 | 176 | 177 | 178 | 179 | def apkinfo_dialog(self): 180 | self.apkinfo = MyApkInfoForm() 181 | self.Init_Apkinfo_text() 182 | csn_path = self.unpackDir + os.path.sep + "META-INF" 183 | if os.path.isdir(csn_path): 184 | f_list = os.listdir(csn_path) 185 | 186 | for file_name in f_list: 187 | if os.path.splitext(file_name)[1] == '.RSA' or os.path.splitext(file_name)[1] == '.DSA': 188 | csn_path = csn_path + os.path.sep + file_name 189 | csn = CSN(csn_path) 190 | self.apkinfo.ui.edt_file.setText(str(csn.get_size())) 191 | self.apkinfo.ui.edt_serial_num.setText(str(csn.getCertificateSN()).upper()) 192 | self.apkinfo.ui.edt_publisher.setText(str(csn.getCertificateIDN())) 193 | self.apkinfo.ui.edt_issuer.setText(str(csn.getCertificateSDN())) 194 | break 195 | 196 | 197 | dex_path = self.unpackDir + os.path.sep + "classes.dex" 198 | if os.path.exists(dex_path): 199 | m = hashlib.md5() 200 | file = io.FileIO(dex_path, 'r') 201 | bytes = file.read(1024) 202 | while(bytes != b''): 203 | m.update(bytes) 204 | bytes = file.read(1024) 205 | file.close() 206 | dexmd5value = m.hexdigest() 207 | #print str(dexmd5value).upper() 208 | self.apkinfo.ui.edt_dexmd5.setText(str(dexmd5value).upper()) 209 | 210 | apkpath = unicode(self.loadfile_path, "utf8") 211 | if os.path.isfile(apkpath) and self.loadfile_path != "": 212 | pass 213 | if self.loadfile_path != "": 214 | #apkpath = unicode(self.loadfile_path, "utf8") 215 | 216 | apkmd5value = self.GetFileMd5(self.loadfile_path) 217 | 218 | # m = hashlib.md5() 219 | # file = io.FileIO(self.loadfile_path, 'r') 220 | # bytes = file.read(1024) 221 | # while(bytes != b''): 222 | # m.update(bytes) 223 | # bytes = file.read(1024) 224 | # file.close() 225 | # apkmd5value = m.hexdigest() 226 | self.apkinfo.ui.edt_apkmd5.setText(apkmd5value.upper()) 227 | 228 | 229 | path = self.unpackDir + os.path.sep +"AndroidManifest.xml" 230 | 231 | if os.path.exists(path): 232 | axml_analysis = AXML(self.unpackDir + os.path.sep +"AndroidManifest.xml") 233 | if axml_analysis.get_filename_abs() == 'AndroidManifest': 234 | self.apkinfo.ui.edt_package.setText(axml_analysis.get_package()) 235 | self.apkinfo.ui.edt_version.setText(axml_analysis.get_androidversion_name()) 236 | self.apkinfo.ui.edt_version_num.setText(axml_analysis.get_androidversion_code()) 237 | self.apkinfo.ui.edt_version_need.setText(axml_analysis.getMinSdkVersion()) 238 | 239 | 240 | 241 | self.apkinfo.show() 242 | 243 | def extendinfo_dialog(self): 244 | self.dexinfo = DexInfoForm() 245 | self.Init_DexInfo_text() 246 | if self.dexheader.has_key("header_magic"): 247 | self.dexinfo.ui.text_magic.setText(self.dexheader["header_magic"]) 248 | self.dexinfo.ui.text_checksum.setText(self.dexheader["header_checksum"]) 249 | self.dexinfo.ui.text_file_size.setText(self.dexheader["header_fileSize"]) 250 | self.dexinfo.ui.text_header_size.setText(self.dexheader["header_headerSize"]) 251 | self.dexinfo.ui.text_endian_tag.setText(self.dexheader["header_endianTag"]) 252 | self.dexinfo.ui.text_link_size.setText(self.dexheader["header_linkSize"]) 253 | self.dexinfo.ui.text_link_off.setText(self.dexheader["header_linkOff"]) 254 | self.dexinfo.ui.text_map_off.setText(self.dexheader["header_mapOff"]) 255 | self.dexinfo.ui.text_string_ids_size.setText(self.dexheader["header_stringIdsSize"]) 256 | self.dexinfo.ui.text_string_ids_off.setText(self.dexheader["header_stringIdsOff"]) 257 | self.dexinfo.ui.text_type_ids_size.setText(self.dexheader["header_typeIdsSize"]) 258 | self.dexinfo.ui.text_type_ids_off.setText(self.dexheader["header_typeIdsOff"]) 259 | self.dexinfo.ui.text_proto_ids_size.setText(self.dexheader["header_protoIdsSize"]) 260 | self.dexinfo.ui.text_proto_ids_off.setText(self.dexheader["header_protoIdsOff"]) 261 | self.dexinfo.ui.text_field_ids_size.setText(self.dexheader["header_fieldIdsSize"]) 262 | self.dexinfo.ui.text_field_ids_off.setText(self.dexheader["header_fieldIdsOff"]) 263 | self.dexinfo.ui.text_method_ids_size.setText(self.dexheader["header_methodIdsSize"]) 264 | self.dexinfo.ui.text_method_ids_off.setText(self.dexheader["header_methodIdsOff"]) 265 | self.dexinfo.ui.text_class_defs_size.setText(self.dexheader["header_classDefsSize"]) 266 | self.dexinfo.ui.text_class_defs_off.setText(self.dexheader["header_classDefsOff"]) 267 | self.dexinfo.ui.text_data_size.setText(self.dexheader["header_dataSize"]) 268 | self.dexinfo.ui.text_data_off.setText(self.dexheader["header_dataOff"]) 269 | self.dexinfo.ui.text_sha.setText(self.dexheader["header_signature"]) 270 | self.dexinfo.show() 271 | 272 | 273 | 274 | if __name__ == "__main__": 275 | 276 | app = QtGui.QApplication(sys.argv) 277 | myapp = ApkDetecterForm() 278 | myapp.show() 279 | sys.exit(app.exec_()) -------------------------------------------------------------------------------- /ApkInfo.py: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8-*- 2 | __author__ = 'Andy' 3 | import sys 4 | 5 | from PyQt4 import QtGui 6 | 7 | from GUI.apkinfo_ui import Ui_ApkInfo 8 | 9 | class MyApkInfoForm(QtGui.QMainWindow): 10 | def __init__(self, parent = None): 11 | QtGui.QWidget.__init__(self, parent) 12 | self.ui = Ui_ApkInfo() 13 | self.ui.setupUi(self) 14 | 15 | 16 | 17 | 18 | if __name__ == "__main__": 19 | app = QtGui.QApplication(sys.argv) 20 | myapp = MyApkInfoForm() 21 | myapp.show() 22 | sys.exit(app.exec_()) -------------------------------------------------------------------------------- /CheckProtect.py: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8-*- 2 | __author__ = 'Andy' 3 | 4 | import os 5 | from UnzipAPK import UnzipAPK 6 | from AnalysisXML.AXML import AXML 7 | class CheckProtect(): 8 | 9 | def __init__(self, apkPath): 10 | #self.apkPath = r"D:\original.apk" 11 | self.apkPath = apkPath 12 | self.protectflag = "" 13 | self.protectflag_dict = {"libsecexe.so": u"该APK已加固=>梆梆加固", "libAPKProtect.so": u"该APK已加固=>APKProtect加固", 14 | "libprotectClass.so": u"该APK已加固=>360加固", "libNSaferOnly.so": u"该APK已加固=>通付盾加固", 15 | "libnqshield.so": u"该APK已加固=>网秦加固", "libshell.so": u"该APK已加固=>腾讯加固", 16 | "ijiami.dat": u"该APK已加固=>爱加密加固", "libddog.so": u"该APK已加固=>娜迦加固", 17 | "libmobisec.so": u"该APK已加固=>阿里加固", "libbaiduprotect.so": u"该APK已加固=>百度加固"} 18 | 19 | def getactivity(self, path): 20 | axml_analysis = AXML(path + os.path.sep +"AndroidManifest.xml") 21 | mainfast = axml_analysis.get_xml() 22 | packagename = axml_analysis.get_package() 23 | xml_content = mainfast.split("" in tmp: 30 | tmp = tmp.split('>')[0] 31 | if tmp.startswith("."): 32 | activity[packagename + tmp] = "" 33 | elif tmp.startswith(packagename): 34 | activity[tmp] = "" 35 | else: 36 | activity[packagename + '.' + tmp] = "" 37 | return activity 38 | 39 | def check_protectflag(self): 40 | 41 | self.protectflag = "" 42 | 43 | obj = UnzipAPK(self.apkPath) 44 | dir_name = {} 45 | file_name = {} 46 | 47 | activites = self.getactivity(self.apkPath) 48 | class_names = obj.getclassname() 49 | 50 | all_file_name, all_dir_name = obj.getallname() 51 | 52 | for file in all_file_name: 53 | file_name[file] = "" 54 | 55 | for dir in all_dir_name: 56 | dir_name[dir] = "" 57 | 58 | 59 | for key in self.protectflag_dict.keys(): 60 | if file_name.has_key(key): 61 | self.protectflag = self.protectflag + self.protectflag_dict[key] 62 | 63 | if file_name.has_key("key.dat") and all_dir_name.has_key("apkprotect.com"): 64 | if self.protectflag == "" or (u"APKProtect加固" not in self.protectflag): 65 | self.protectflag = self.protectflag + u"APKProtect加固" 66 | 67 | if self.protectflag != "": 68 | return self.protectflag 69 | else: 70 | self.flag = 0 71 | for activity in activites.keys(): 72 | # self.flag = 0 73 | if class_names.has_key(activity): 74 | pass 75 | else: 76 | self.flag = 1 77 | 78 | if self.protectflag == "" and self.flag == 1: 79 | self.protectflag = u"疑似未知加密" 80 | 81 | if self.protectflag == "": 82 | self.protectflag = u"该APK未加密" 83 | 84 | return self.protectflag 85 | 86 | 87 | 88 | if __name__ == "__main__": 89 | obj = CheckProtect() 90 | obj.check_protectflag() -------------------------------------------------------------------------------- /DexInfo.py: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8-*- 2 | __author__ = 'Andy' 3 | import sys 4 | 5 | from PyQt4 import QtGui 6 | 7 | from GUI.dexinfor_ui import Ui_DexInfo 8 | 9 | 10 | class DexInfoForm(QtGui.QMainWindow): 11 | def __init__(self, parent = None): 12 | QtGui.QWidget.__init__(self, parent) 13 | self.ui = Ui_DexInfo() 14 | self.ui.setupUi(self) 15 | 16 | 17 | 18 | if __name__ == "__main__": 19 | app = QtGui.QApplication(sys.argv) 20 | myapp = DexInfoForm() 21 | myapp.show() 22 | sys.exit(app.exec_()) -------------------------------------------------------------------------------- /GUI/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'Andy' 2 | -------------------------------------------------------------------------------- /GUI/apkdetecter_ui.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'apkdetecter_ui.ui' 4 | # 5 | # Created: Sun Jan 18 22:26:54 2015 6 | # by: PyQt4 UI code generator 4.11.1 7 | # 8 | # WARNING! All changes made in this file will be lost! 9 | 10 | from PyQt4 import QtCore, QtGui 11 | 12 | try: 13 | _fromUtf8 = QtCore.QString.fromUtf8 14 | except AttributeError: 15 | def _fromUtf8(s): 16 | return s 17 | 18 | try: 19 | _encoding = QtGui.QApplication.UnicodeUTF8 20 | def _translate(context, text, disambig): 21 | return QtGui.QApplication.translate(context, text, disambig, _encoding) 22 | except AttributeError: 23 | def _translate(context, text, disambig): 24 | return QtGui.QApplication.translate(context, text, disambig) 25 | 26 | class Ui_APKDetecter(object): 27 | def setupUi(self, APKDetecter): 28 | APKDetecter.setObjectName(_fromUtf8("APKDetecter")) 29 | APKDetecter.setWindowModality(QtCore.Qt.WindowModal) 30 | APKDetecter.setEnabled(True) 31 | APKDetecter.resize(432, 237) 32 | APKDetecter.setMinimumSize(QtCore.QSize(432, 237)) 33 | APKDetecter.setMaximumSize(QtCore.QSize(432, 237)) 34 | icon = QtGui.QIcon() 35 | icon.addPixmap(QtGui.QPixmap(_fromUtf8("C:/Users/Andy/Desktop/20150117051304968_easyicon_net_512.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) 36 | APKDetecter.setWindowIcon(icon) 37 | self.lab_file = QtGui.QLabel(APKDetecter) 38 | self.lab_file.setGeometry(QtCore.QRect(10, 10, 41, 16)) 39 | font = QtGui.QFont() 40 | font.setFamily(_fromUtf8("Arial")) 41 | font.setPointSize(10) 42 | font.setBold(True) 43 | font.setWeight(75) 44 | self.lab_file.setFont(font) 45 | self.lab_file.setObjectName(_fromUtf8("lab_file")) 46 | self.te_path = QtGui.QTextBrowser(APKDetecter) 47 | self.te_path.setGeometry(QtCore.QRect(50, 5, 291, 24)) 48 | self.te_path.setObjectName(_fromUtf8("te_path")) 49 | self.file_open = QtGui.QPushButton(APKDetecter) 50 | self.file_open.setGeometry(QtCore.QRect(350, 5, 71, 23)) 51 | font = QtGui.QFont() 52 | font.setFamily(_fromUtf8("Arial")) 53 | font.setPointSize(10) 54 | font.setBold(True) 55 | font.setWeight(75) 56 | self.file_open.setFont(font) 57 | self.file_open.setObjectName(_fromUtf8("file_open")) 58 | self.groupBox = QtGui.QGroupBox(APKDetecter) 59 | self.groupBox.setGeometry(QtCore.QRect(10, 30, 411, 181)) 60 | font = QtGui.QFont() 61 | font.setFamily(_fromUtf8("Arabic Typesetting")) 62 | font.setPointSize(8) 63 | font.setBold(False) 64 | font.setItalic(True) 65 | font.setWeight(50) 66 | self.groupBox.setFont(font) 67 | self.groupBox.setObjectName(_fromUtf8("groupBox")) 68 | self.lab_linksize = QtGui.QLabel(self.groupBox) 69 | self.lab_linksize.setGeometry(QtCore.QRect(210, 70, 71, 16)) 70 | font = QtGui.QFont() 71 | font.setFamily(_fromUtf8("Arial Narrow")) 72 | font.setPointSize(10) 73 | font.setBold(True) 74 | font.setItalic(False) 75 | font.setWeight(75) 76 | self.lab_linksize.setFont(font) 77 | self.lab_linksize.setObjectName(_fromUtf8("lab_linksize")) 78 | self.lab_dex_flag = QtGui.QLabel(self.groupBox) 79 | self.lab_dex_flag.setGeometry(QtCore.QRect(10, 30, 61, 16)) 80 | font = QtGui.QFont() 81 | font.setFamily(_fromUtf8("Arial Narrow")) 82 | font.setPointSize(10) 83 | font.setBold(True) 84 | font.setItalic(False) 85 | font.setWeight(75) 86 | self.lab_dex_flag.setFont(font) 87 | self.lab_dex_flag.setObjectName(_fromUtf8("lab_dex_flag")) 88 | self.lab_dexheader_size = QtGui.QLabel(self.groupBox) 89 | self.lab_dexheader_size.setGeometry(QtCore.QRect(10, 70, 61, 16)) 90 | font = QtGui.QFont() 91 | font.setFamily(_fromUtf8("Arial Narrow")) 92 | font.setBold(True) 93 | font.setItalic(False) 94 | font.setWeight(75) 95 | self.lab_dexheader_size.setFont(font) 96 | self.lab_dexheader_size.setObjectName(_fromUtf8("lab_dexheader_size")) 97 | self.te_endiantag = QtGui.QTextBrowser(self.groupBox) 98 | self.te_endiantag.setEnabled(False) 99 | self.te_endiantag.setGeometry(QtCore.QRect(80, 104, 111, 27)) 100 | font = QtGui.QFont() 101 | font.setFamily(_fromUtf8("Arial Narrow")) 102 | font.setPointSize(10) 103 | font.setBold(True) 104 | font.setItalic(False) 105 | font.setWeight(75) 106 | self.te_endiantag.setFont(font) 107 | self.te_endiantag.setFrameShape(QtGui.QFrame.Panel) 108 | self.te_endiantag.setObjectName(_fromUtf8("te_endiantag")) 109 | self.lab_linkoff = QtGui.QLabel(self.groupBox) 110 | self.lab_linkoff.setGeometry(QtCore.QRect(210, 111, 71, 16)) 111 | font = QtGui.QFont() 112 | font.setFamily(_fromUtf8("Arial Narrow")) 113 | font.setPointSize(10) 114 | font.setBold(True) 115 | font.setItalic(False) 116 | font.setWeight(75) 117 | self.lab_linkoff.setFont(font) 118 | self.lab_linkoff.setObjectName(_fromUtf8("lab_linkoff")) 119 | self.te_linkoff = QtGui.QTextBrowser(self.groupBox) 120 | self.te_linkoff.setEnabled(False) 121 | self.te_linkoff.setGeometry(QtCore.QRect(292, 103, 111, 27)) 122 | font = QtGui.QFont() 123 | font.setFamily(_fromUtf8("Arial Narrow")) 124 | font.setPointSize(10) 125 | font.setBold(True) 126 | font.setItalic(False) 127 | font.setWeight(75) 128 | self.te_linkoff.setFont(font) 129 | self.te_linkoff.setFrameShape(QtGui.QFrame.Panel) 130 | self.te_linkoff.setObjectName(_fromUtf8("te_linkoff")) 131 | self.lab_file_size = QtGui.QLabel(self.groupBox) 132 | self.lab_file_size.setGeometry(QtCore.QRect(212, 32, 54, 12)) 133 | font = QtGui.QFont() 134 | font.setFamily(_fromUtf8("Arial Narrow")) 135 | font.setPointSize(10) 136 | font.setBold(True) 137 | font.setItalic(False) 138 | font.setWeight(75) 139 | self.lab_file_size.setFont(font) 140 | self.lab_file_size.setObjectName(_fromUtf8("lab_file_size")) 141 | self.te_linksize = QtGui.QTextBrowser(self.groupBox) 142 | self.te_linksize.setEnabled(False) 143 | self.te_linksize.setGeometry(QtCore.QRect(292, 63, 111, 27)) 144 | font = QtGui.QFont() 145 | font.setFamily(_fromUtf8("Arial Narrow")) 146 | font.setPointSize(10) 147 | font.setBold(True) 148 | font.setItalic(False) 149 | font.setWeight(75) 150 | self.te_linksize.setFont(font) 151 | self.te_linksize.setFrameShape(QtGui.QFrame.Panel) 152 | self.te_linksize.setObjectName(_fromUtf8("te_linksize")) 153 | self.te_dexheader_size = QtGui.QTextBrowser(self.groupBox) 154 | self.te_dexheader_size.setEnabled(False) 155 | self.te_dexheader_size.setGeometry(QtCore.QRect(80, 63, 111, 27)) 156 | font = QtGui.QFont() 157 | font.setFamily(_fromUtf8("Arial Narrow")) 158 | font.setPointSize(10) 159 | font.setBold(True) 160 | font.setItalic(False) 161 | font.setWeight(75) 162 | self.te_dexheader_size.setFont(font) 163 | self.te_dexheader_size.setFrameShape(QtGui.QFrame.Panel) 164 | self.te_dexheader_size.setObjectName(_fromUtf8("te_dexheader_size")) 165 | self.te_file_size = QtGui.QTextBrowser(self.groupBox) 166 | self.te_file_size.setEnabled(False) 167 | self.te_file_size.setGeometry(QtCore.QRect(292, 22, 111, 27)) 168 | font = QtGui.QFont() 169 | font.setFamily(_fromUtf8("Arial Narrow")) 170 | font.setPointSize(10) 171 | font.setBold(True) 172 | font.setItalic(False) 173 | font.setWeight(75) 174 | self.te_file_size.setFont(font) 175 | self.te_file_size.setFrameShape(QtGui.QFrame.Panel) 176 | self.te_file_size.setObjectName(_fromUtf8("te_file_size")) 177 | self.lab_endiantag = QtGui.QLabel(self.groupBox) 178 | self.lab_endiantag.setGeometry(QtCore.QRect(10, 113, 54, 12)) 179 | font = QtGui.QFont() 180 | font.setFamily(_fromUtf8("Arial Narrow")) 181 | font.setPointSize(10) 182 | font.setBold(True) 183 | font.setItalic(False) 184 | font.setWeight(75) 185 | self.lab_endiantag.setFont(font) 186 | self.lab_endiantag.setObjectName(_fromUtf8("lab_endiantag")) 187 | self.te_protect = QtGui.QTextBrowser(self.groupBox) 188 | self.te_protect.setEnabled(False) 189 | self.te_protect.setGeometry(QtCore.QRect(12, 140, 391, 27)) 190 | font = QtGui.QFont() 191 | font.setFamily(_fromUtf8("Arial Narrow")) 192 | font.setPointSize(10) 193 | font.setBold(True) 194 | font.setItalic(False) 195 | font.setWeight(75) 196 | self.te_protect.setFont(font) 197 | self.te_protect.setFrameShape(QtGui.QFrame.Panel) 198 | self.te_protect.setObjectName(_fromUtf8("te_protect")) 199 | self.te_dex_flag = QtGui.QTextEdit(self.groupBox) 200 | self.te_dex_flag.setEnabled(False) 201 | self.te_dex_flag.setGeometry(QtCore.QRect(80, 22, 111, 27)) 202 | font = QtGui.QFont() 203 | font.setFamily(_fromUtf8("Arial Narrow")) 204 | font.setPointSize(10) 205 | font.setBold(True) 206 | font.setItalic(False) 207 | font.setWeight(75) 208 | self.te_dex_flag.setFont(font) 209 | self.te_dex_flag.setFrameShape(QtGui.QFrame.Panel) 210 | self.te_dex_flag.setObjectName(_fromUtf8("te_dex_flag")) 211 | self.progressBar = QtGui.QProgressBar(APKDetecter) 212 | self.progressBar.setEnabled(True) 213 | self.progressBar.setGeometry(QtCore.QRect(10, 217, 191, 16)) 214 | self.progressBar.setProperty("value", 0) 215 | self.progressBar.setObjectName(_fromUtf8("progressBar")) 216 | self.extend_info = QtGui.QPushButton(APKDetecter) 217 | self.extend_info.setGeometry(QtCore.QRect(275, 214, 71, 20)) 218 | self.extend_info.setObjectName(_fromUtf8("extend_info")) 219 | self.about_info = QtGui.QPushButton(APKDetecter) 220 | self.about_info.setGeometry(QtCore.QRect(350, 214, 71, 20)) 221 | self.about_info.setObjectName(_fromUtf8("about_info")) 222 | self.apk_info = QtGui.QPushButton(APKDetecter) 223 | self.apk_info.setGeometry(QtCore.QRect(200, 214, 71, 20)) 224 | self.apk_info.setObjectName(_fromUtf8("apk_info")) 225 | 226 | self.retranslateUi(APKDetecter) 227 | QtCore.QMetaObject.connectSlotsByName(APKDetecter) 228 | 229 | def retranslateUi(self, APKDetecter): 230 | APKDetecter.setWindowTitle(_translate("APKDetecter", "APKDetecter", None)) 231 | self.lab_file.setText(_translate("APKDetecter", "文 件", None)) 232 | self.file_open.setText(_translate("APKDetecter", "打 开", None)) 233 | self.groupBox.setTitle(_translate("APKDetecter", "DEX信息", None)) 234 | self.lab_linksize.setText(_translate("APKDetecter", "连接段大小", None)) 235 | self.lab_dex_flag.setText(_translate("APKDetecter", "DEX 标 识", None)) 236 | self.lab_dexheader_size.setText(_translate("APKDetecter", "DEX头大小", None)) 237 | self.lab_linkoff.setText(_translate("APKDetecter", "连接段偏移", None)) 238 | self.lab_file_size.setText(_translate("APKDetecter", "文件大小", None)) 239 | self.lab_endiantag.setText(_translate("APKDetecter", "字节序列", None)) 240 | self.extend_info.setText(_translate("APKDetecter", "扩展信息", None)) 241 | self.about_info.setText(_translate("APKDetecter", "About", None)) 242 | self.apk_info.setText(_translate("APKDetecter", "ApkInfo", None)) 243 | 244 | -------------------------------------------------------------------------------- /GUI/apkdetecter_ui.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | APKDetecter 4 | 5 | 6 | Qt::WindowModal 7 | 8 | 9 | true 10 | 11 | 12 | 13 | 0 14 | 0 15 | 432 16 | 237 17 | 18 | 19 | 20 | 21 | 432 22 | 237 23 | 24 | 25 | 26 | 27 | 432 28 | 237 29 | 30 | 31 | 32 | APKDetecter 33 | 34 | 35 | 36 | C:/Users/Andy/Desktop/20150117051304968_easyicon_net_512.pngC:/Users/Andy/Desktop/20150117051304968_easyicon_net_512.png 37 | 38 | 39 | 40 | 41 | 10 42 | 10 43 | 41 44 | 16 45 | 46 | 47 | 48 | 49 | Arial 50 | 10 51 | 75 52 | true 53 | 54 | 55 | 56 | 文 件 57 | 58 | 59 | 60 | 61 | 62 | 50 63 | 5 64 | 291 65 | 24 66 | 67 | 68 | 69 | 70 | 71 | 72 | 350 73 | 5 74 | 71 75 | 23 76 | 77 | 78 | 79 | 80 | Arial 81 | 10 82 | 75 83 | true 84 | 85 | 86 | 87 | 打 开 88 | 89 | 90 | 91 | 92 | 93 | 10 94 | 30 95 | 411 96 | 181 97 | 98 | 99 | 100 | 101 | Arabic Typesetting 102 | 8 103 | 50 104 | true 105 | false 106 | 107 | 108 | 109 | DEX信息 110 | 111 | 112 | 113 | 114 | 210 115 | 70 116 | 71 117 | 16 118 | 119 | 120 | 121 | 122 | Arial Narrow 123 | 10 124 | 75 125 | false 126 | true 127 | 128 | 129 | 130 | 连接段大小 131 | 132 | 133 | 134 | 135 | 136 | 10 137 | 30 138 | 61 139 | 16 140 | 141 | 142 | 143 | 144 | Arial Narrow 145 | 10 146 | 75 147 | false 148 | true 149 | 150 | 151 | 152 | DEX 标 识 153 | 154 | 155 | 156 | 157 | 158 | 10 159 | 70 160 | 61 161 | 16 162 | 163 | 164 | 165 | 166 | Arial Narrow 167 | 75 168 | false 169 | true 170 | 171 | 172 | 173 | DEX头大小 174 | 175 | 176 | 177 | 178 | false 179 | 180 | 181 | 182 | 80 183 | 104 184 | 111 185 | 27 186 | 187 | 188 | 189 | 190 | Arial Narrow 191 | 10 192 | 75 193 | false 194 | true 195 | 196 | 197 | 198 | QFrame::Panel 199 | 200 | 201 | 202 | 203 | 204 | 210 205 | 111 206 | 71 207 | 16 208 | 209 | 210 | 211 | 212 | Arial Narrow 213 | 10 214 | 75 215 | false 216 | true 217 | 218 | 219 | 220 | 连接段偏移 221 | 222 | 223 | 224 | 225 | false 226 | 227 | 228 | 229 | 292 230 | 103 231 | 111 232 | 27 233 | 234 | 235 | 236 | 237 | Arial Narrow 238 | 10 239 | 75 240 | false 241 | true 242 | 243 | 244 | 245 | QFrame::Panel 246 | 247 | 248 | 249 | 250 | 251 | 212 252 | 32 253 | 54 254 | 12 255 | 256 | 257 | 258 | 259 | Arial Narrow 260 | 10 261 | 75 262 | false 263 | true 264 | 265 | 266 | 267 | 文件大小 268 | 269 | 270 | 271 | 272 | false 273 | 274 | 275 | 276 | 292 277 | 63 278 | 111 279 | 27 280 | 281 | 282 | 283 | 284 | Arial Narrow 285 | 10 286 | 75 287 | false 288 | true 289 | 290 | 291 | 292 | QFrame::Panel 293 | 294 | 295 | 296 | 297 | false 298 | 299 | 300 | 301 | 80 302 | 63 303 | 111 304 | 27 305 | 306 | 307 | 308 | 309 | Arial Narrow 310 | 10 311 | 75 312 | false 313 | true 314 | 315 | 316 | 317 | QFrame::Panel 318 | 319 | 320 | 321 | 322 | false 323 | 324 | 325 | 326 | 292 327 | 22 328 | 111 329 | 27 330 | 331 | 332 | 333 | 334 | Arial Narrow 335 | 10 336 | 75 337 | false 338 | true 339 | 340 | 341 | 342 | QFrame::Panel 343 | 344 | 345 | 346 | 347 | 348 | 10 349 | 113 350 | 54 351 | 12 352 | 353 | 354 | 355 | 356 | Arial Narrow 357 | 10 358 | 75 359 | false 360 | true 361 | 362 | 363 | 364 | 字节序列 365 | 366 | 367 | 368 | 369 | false 370 | 371 | 372 | 373 | 12 374 | 140 375 | 391 376 | 27 377 | 378 | 379 | 380 | 381 | Arial Narrow 382 | 10 383 | 75 384 | false 385 | true 386 | 387 | 388 | 389 | QFrame::Panel 390 | 391 | 392 | 393 | 394 | false 395 | 396 | 397 | 398 | 80 399 | 22 400 | 111 401 | 27 402 | 403 | 404 | 405 | 406 | Arial Narrow 407 | 10 408 | 75 409 | false 410 | true 411 | 412 | 413 | 414 | QFrame::Panel 415 | 416 | 417 | 418 | 419 | 420 | true 421 | 422 | 423 | 424 | 10 425 | 217 426 | 191 427 | 16 428 | 429 | 430 | 431 | 0 432 | 433 | 434 | 435 | 436 | 437 | 275 438 | 214 439 | 71 440 | 20 441 | 442 | 443 | 444 | 扩展信息 445 | 446 | 447 | 448 | 449 | 450 | 350 451 | 214 452 | 71 453 | 20 454 | 455 | 456 | 457 | About 458 | 459 | 460 | 461 | 462 | 463 | 200 464 | 214 465 | 71 466 | 20 467 | 468 | 469 | 470 | ApkInfo 471 | 472 | 473 | 474 | 475 | 476 | 477 | -------------------------------------------------------------------------------- /GUI/apkinfo_ui.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'apkinfo_ui.ui' 4 | # 5 | # Created: Tue Jan 20 11:25:39 2015 6 | # by: PyQt4 UI code generator 4.11.3 7 | # 8 | # WARNING! All changes made in this file will be lost! 9 | 10 | from PyQt4 import QtCore, QtGui 11 | 12 | try: 13 | _fromUtf8 = QtCore.QString.fromUtf8 14 | except AttributeError: 15 | def _fromUtf8(s): 16 | return s 17 | 18 | try: 19 | _encoding = QtGui.QApplication.UnicodeUTF8 20 | def _translate(context, text, disambig): 21 | return QtGui.QApplication.translate(context, text, disambig, _encoding) 22 | except AttributeError: 23 | def _translate(context, text, disambig): 24 | return QtGui.QApplication.translate(context, text, disambig) 25 | 26 | class Ui_ApkInfo(object): 27 | def setupUi(self, ApkInfo): 28 | ApkInfo.setObjectName(_fromUtf8("ApkInfo")) 29 | ApkInfo.setWindowModality(QtCore.Qt.WindowModal) 30 | ApkInfo.setEnabled(True) 31 | ApkInfo.resize(621, 330) 32 | ApkInfo.setMinimumSize(QtCore.QSize(621, 330)) 33 | ApkInfo.setMaximumSize(QtCore.QSize(621, 330)) 34 | icon = QtGui.QIcon() 35 | icon.addPixmap(QtGui.QPixmap(_fromUtf8("C:/Users/Andy/Desktop/20150117051304968_easyicon_net_512.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) 36 | ApkInfo.setWindowIcon(icon) 37 | self.groupBox = QtGui.QGroupBox(ApkInfo) 38 | self.groupBox.setGeometry(QtCore.QRect(10, 10, 601, 311)) 39 | font = QtGui.QFont() 40 | font.setFamily(_fromUtf8("Aharoni")) 41 | font.setPointSize(9) 42 | font.setBold(True) 43 | font.setItalic(False) 44 | font.setWeight(75) 45 | self.groupBox.setFont(font) 46 | self.groupBox.setObjectName(_fromUtf8("groupBox")) 47 | self.file_size = QtGui.QLabel(self.groupBox) 48 | self.file_size.setGeometry(QtCore.QRect(10, 27, 54, 12)) 49 | font = QtGui.QFont() 50 | font.setFamily(_fromUtf8("Arial")) 51 | font.setPointSize(10) 52 | font.setBold(True) 53 | font.setWeight(75) 54 | self.file_size.setFont(font) 55 | self.file_size.setObjectName(_fromUtf8("file_size")) 56 | self.package_name = QtGui.QLabel(self.groupBox) 57 | self.package_name.setGeometry(QtCore.QRect(10, 63, 54, 12)) 58 | font = QtGui.QFont() 59 | font.setFamily(_fromUtf8("Arial")) 60 | font.setPointSize(10) 61 | font.setBold(True) 62 | font.setWeight(75) 63 | self.package_name.setFont(font) 64 | self.package_name.setObjectName(_fromUtf8("package_name")) 65 | self.version = QtGui.QLabel(self.groupBox) 66 | self.version.setGeometry(QtCore.QRect(312, 28, 54, 12)) 67 | font = QtGui.QFont() 68 | font.setFamily(_fromUtf8("Arial")) 69 | font.setPointSize(10) 70 | font.setBold(True) 71 | font.setWeight(75) 72 | self.version.setFont(font) 73 | self.version.setObjectName(_fromUtf8("version")) 74 | self.version_num = QtGui.QLabel(self.groupBox) 75 | self.version_num.setGeometry(QtCore.QRect(311, 64, 54, 12)) 76 | font = QtGui.QFont() 77 | font.setFamily(_fromUtf8("Arial")) 78 | font.setPointSize(10) 79 | font.setBold(True) 80 | font.setWeight(75) 81 | self.version_num.setFont(font) 82 | self.version_num.setObjectName(_fromUtf8("version_num")) 83 | self.version_need = QtGui.QLabel(self.groupBox) 84 | self.version_need.setGeometry(QtCore.QRect(10, 101, 54, 12)) 85 | font = QtGui.QFont() 86 | font.setFamily(_fromUtf8("Arial")) 87 | font.setPointSize(10) 88 | font.setBold(True) 89 | font.setWeight(75) 90 | self.version_need.setFont(font) 91 | self.version_need.setObjectName(_fromUtf8("version_need")) 92 | self.serial_num = QtGui.QLabel(self.groupBox) 93 | self.serial_num.setGeometry(QtCore.QRect(312, 100, 54, 12)) 94 | font = QtGui.QFont() 95 | font.setFamily(_fromUtf8("Arial")) 96 | font.setPointSize(10) 97 | font.setBold(True) 98 | font.setWeight(75) 99 | self.serial_num.setFont(font) 100 | self.serial_num.setObjectName(_fromUtf8("serial_num")) 101 | self.publisher = QtGui.QLabel(self.groupBox) 102 | self.publisher.setGeometry(QtCore.QRect(10, 227, 54, 12)) 103 | font = QtGui.QFont() 104 | font.setFamily(_fromUtf8("Arial")) 105 | font.setPointSize(10) 106 | font.setBold(True) 107 | font.setWeight(75) 108 | self.publisher.setFont(font) 109 | self.publisher.setObjectName(_fromUtf8("publisher")) 110 | self.issuer = QtGui.QLabel(self.groupBox) 111 | self.issuer.setGeometry(QtCore.QRect(10, 274, 54, 12)) 112 | font = QtGui.QFont() 113 | font.setFamily(_fromUtf8("Arial")) 114 | font.setPointSize(10) 115 | font.setBold(True) 116 | font.setWeight(75) 117 | self.issuer.setFont(font) 118 | self.issuer.setObjectName(_fromUtf8("issuer")) 119 | self.apkmd5 = QtGui.QLabel(self.groupBox) 120 | self.apkmd5.setGeometry(QtCore.QRect(11, 143, 54, 12)) 121 | font = QtGui.QFont() 122 | font.setFamily(_fromUtf8("Arial")) 123 | font.setPointSize(9) 124 | font.setBold(True) 125 | font.setWeight(75) 126 | self.apkmd5.setFont(font) 127 | self.apkmd5.setObjectName(_fromUtf8("apkmd5")) 128 | self.dexmd5 = QtGui.QLabel(self.groupBox) 129 | self.dexmd5.setGeometry(QtCore.QRect(10, 181, 54, 12)) 130 | font = QtGui.QFont() 131 | font.setFamily(_fromUtf8("Arial")) 132 | font.setBold(True) 133 | font.setWeight(75) 134 | self.dexmd5.setFont(font) 135 | self.dexmd5.setObjectName(_fromUtf8("dexmd5")) 136 | self.edt_file = QtGui.QTextEdit(self.groupBox) 137 | self.edt_file.setEnabled(False) 138 | self.edt_file.setGeometry(QtCore.QRect(70, 18, 231, 28)) 139 | font = QtGui.QFont() 140 | font.setFamily(_fromUtf8("Arial Narrow")) 141 | font.setPointSize(10) 142 | self.edt_file.setFont(font) 143 | self.edt_file.setFrameShape(QtGui.QFrame.Box) 144 | self.edt_file.setObjectName(_fromUtf8("edt_file")) 145 | self.edt_package = QtGui.QTextEdit(self.groupBox) 146 | self.edt_package.setEnabled(False) 147 | self.edt_package.setGeometry(QtCore.QRect(70, 54, 231, 28)) 148 | font = QtGui.QFont() 149 | font.setFamily(_fromUtf8("Arial Narrow")) 150 | font.setPointSize(10) 151 | self.edt_package.setFont(font) 152 | self.edt_package.setFrameShape(QtGui.QFrame.Panel) 153 | self.edt_package.setObjectName(_fromUtf8("edt_package")) 154 | self.edt_version_need = QtGui.QTextEdit(self.groupBox) 155 | self.edt_version_need.setEnabled(False) 156 | self.edt_version_need.setGeometry(QtCore.QRect(70, 91, 231, 28)) 157 | font = QtGui.QFont() 158 | font.setFamily(_fromUtf8("Arial Narrow")) 159 | font.setPointSize(10) 160 | self.edt_version_need.setFont(font) 161 | self.edt_version_need.setFrameShape(QtGui.QFrame.Panel) 162 | self.edt_version_need.setObjectName(_fromUtf8("edt_version_need")) 163 | self.edt_version = QtGui.QTextEdit(self.groupBox) 164 | self.edt_version.setEnabled(False) 165 | self.edt_version.setGeometry(QtCore.QRect(360, 19, 231, 28)) 166 | font = QtGui.QFont() 167 | font.setFamily(_fromUtf8("Arial Narrow")) 168 | font.setPointSize(10) 169 | self.edt_version.setFont(font) 170 | self.edt_version.setFrameShape(QtGui.QFrame.Box) 171 | self.edt_version.setObjectName(_fromUtf8("edt_version")) 172 | self.edt_version_num = QtGui.QTextEdit(self.groupBox) 173 | self.edt_version_num.setEnabled(False) 174 | self.edt_version_num.setGeometry(QtCore.QRect(360, 55, 231, 28)) 175 | font = QtGui.QFont() 176 | font.setFamily(_fromUtf8("Arial Narrow")) 177 | font.setPointSize(10) 178 | self.edt_version_num.setFont(font) 179 | self.edt_version_num.setFrameShape(QtGui.QFrame.Panel) 180 | self.edt_version_num.setObjectName(_fromUtf8("edt_version_num")) 181 | self.edt_serial_num = QtGui.QTextEdit(self.groupBox) 182 | self.edt_serial_num.setEnabled(False) 183 | self.edt_serial_num.setGeometry(QtCore.QRect(360, 92, 231, 28)) 184 | font = QtGui.QFont() 185 | font.setFamily(_fromUtf8("Arial Narrow")) 186 | font.setPointSize(10) 187 | self.edt_serial_num.setFont(font) 188 | self.edt_serial_num.setFrameShape(QtGui.QFrame.Panel) 189 | self.edt_serial_num.setObjectName(_fromUtf8("edt_serial_num")) 190 | self.edt_apkmd5 = QtGui.QTextEdit(self.groupBox) 191 | self.edt_apkmd5.setEnabled(False) 192 | self.edt_apkmd5.setGeometry(QtCore.QRect(70, 132, 521, 28)) 193 | font = QtGui.QFont() 194 | font.setFamily(_fromUtf8("Arial Narrow")) 195 | font.setPointSize(10) 196 | self.edt_apkmd5.setFont(font) 197 | self.edt_apkmd5.setFrameShape(QtGui.QFrame.Panel) 198 | self.edt_apkmd5.setObjectName(_fromUtf8("edt_apkmd5")) 199 | self.edt_dexmd5 = QtGui.QTextEdit(self.groupBox) 200 | self.edt_dexmd5.setEnabled(False) 201 | self.edt_dexmd5.setGeometry(QtCore.QRect(70, 170, 521, 28)) 202 | font = QtGui.QFont() 203 | font.setFamily(_fromUtf8("Arial Narrow")) 204 | font.setPointSize(10) 205 | self.edt_dexmd5.setFont(font) 206 | self.edt_dexmd5.setFrameShape(QtGui.QFrame.Panel) 207 | self.edt_dexmd5.setObjectName(_fromUtf8("edt_dexmd5")) 208 | self.edt_publisher = QtGui.QTextEdit(self.groupBox) 209 | self.edt_publisher.setEnabled(False) 210 | self.edt_publisher.setGeometry(QtCore.QRect(70, 210, 521, 41)) 211 | font = QtGui.QFont() 212 | font.setFamily(_fromUtf8("Arial Narrow")) 213 | font.setPointSize(10) 214 | self.edt_publisher.setFont(font) 215 | self.edt_publisher.setFrameShape(QtGui.QFrame.Panel) 216 | self.edt_publisher.setObjectName(_fromUtf8("edt_publisher")) 217 | self.edt_issuer = QtGui.QTextEdit(self.groupBox) 218 | self.edt_issuer.setEnabled(False) 219 | self.edt_issuer.setGeometry(QtCore.QRect(70, 260, 521, 41)) 220 | font = QtGui.QFont() 221 | font.setFamily(_fromUtf8("Arial Narrow")) 222 | font.setPointSize(10) 223 | self.edt_issuer.setFont(font) 224 | self.edt_issuer.setFrameShape(QtGui.QFrame.Panel) 225 | self.edt_issuer.setObjectName(_fromUtf8("edt_issuer")) 226 | 227 | self.retranslateUi(ApkInfo) 228 | QtCore.QMetaObject.connectSlotsByName(ApkInfo) 229 | 230 | def retranslateUi(self, ApkInfo): 231 | ApkInfo.setWindowTitle(_translate("ApkInfo", "ApkInformation", None)) 232 | self.groupBox.setTitle(_translate("ApkInfo", "文件信息", None)) 233 | self.file_size.setText(_translate("ApkInfo", "文件大小", None)) 234 | self.package_name.setText(_translate("ApkInfo", "文件包名", None)) 235 | self.version.setText(_translate("ApkInfo", "版 本", None)) 236 | self.version_num.setText(_translate("ApkInfo", "版本号", None)) 237 | self.version_need.setText(_translate("ApkInfo", "系统要求", None)) 238 | self.serial_num.setText(_translate("ApkInfo", "序列号", None)) 239 | self.publisher.setText(_translate("ApkInfo", "发 行 者", None)) 240 | self.issuer.setText(_translate("ApkInfo", "签 发 人", None)) 241 | self.apkmd5.setText(_translate("ApkInfo", "APKMD5", None)) 242 | self.dexmd5.setText(_translate("ApkInfo", "DEXMD5", None)) 243 | 244 | -------------------------------------------------------------------------------- /GUI/apkinfo_ui.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | ApkInfo 4 | 5 | 6 | Qt::WindowModal 7 | 8 | 9 | true 10 | 11 | 12 | 13 | 0 14 | 0 15 | 621 16 | 340 17 | 18 | 19 | 20 | 21 | 621 22 | 340 23 | 24 | 25 | 26 | 27 | 621 28 | 340 29 | 30 | 31 | 32 | ApkInformation 33 | 34 | 35 | 36 | C:/Users/Andy/Desktop/20150117051304968_easyicon_net_512.pngC:/Users/Andy/Desktop/20150117051304968_easyicon_net_512.png 37 | 38 | 39 | 40 | 41 | 10 42 | 10 43 | 601 44 | 321 45 | 46 | 47 | 48 | 49 | Aharoni 50 | 9 51 | 75 52 | false 53 | true 54 | 55 | 56 | 57 | 文件信息 58 | 59 | 60 | 61 | 62 | 10 63 | 27 64 | 54 65 | 12 66 | 67 | 68 | 69 | 70 | Arial 71 | 10 72 | 75 73 | true 74 | 75 | 76 | 77 | 文件大小 78 | 79 | 80 | 81 | 82 | 83 | 10 84 | 63 85 | 54 86 | 12 87 | 88 | 89 | 90 | 91 | Arial 92 | 10 93 | 75 94 | true 95 | 96 | 97 | 98 | 文件包名 99 | 100 | 101 | 102 | 103 | 104 | 312 105 | 28 106 | 54 107 | 12 108 | 109 | 110 | 111 | 112 | Arial 113 | 10 114 | 75 115 | true 116 | 117 | 118 | 119 | 版 本 120 | 121 | 122 | 123 | 124 | 125 | 311 126 | 64 127 | 54 128 | 12 129 | 130 | 131 | 132 | 133 | Arial 134 | 10 135 | 75 136 | true 137 | 138 | 139 | 140 | 版本号 141 | 142 | 143 | 144 | 145 | 146 | 10 147 | 101 148 | 54 149 | 12 150 | 151 | 152 | 153 | 154 | Arial 155 | 10 156 | 75 157 | true 158 | 159 | 160 | 161 | 系统要求 162 | 163 | 164 | 165 | 166 | 167 | 312 168 | 100 169 | 54 170 | 12 171 | 172 | 173 | 174 | 175 | Arial 176 | 10 177 | 75 178 | true 179 | 180 | 181 | 182 | 序列号 183 | 184 | 185 | 186 | 187 | 188 | 10 189 | 228 190 | 54 191 | 12 192 | 193 | 194 | 195 | 196 | Arial 197 | 10 198 | 75 199 | true 200 | 201 | 202 | 203 | 发 行 者 204 | 205 | 206 | 207 | 208 | 209 | 10 210 | 280 211 | 54 212 | 12 213 | 214 | 215 | 216 | 217 | Arial 218 | 10 219 | 75 220 | true 221 | 222 | 223 | 224 | 签 发 人 225 | 226 | 227 | 228 | 229 | 230 | 11 231 | 143 232 | 54 233 | 12 234 | 235 | 236 | 237 | 238 | Arial 239 | 9 240 | 75 241 | true 242 | 243 | 244 | 245 | APKMD5 246 | 247 | 248 | 249 | 250 | 251 | 10 252 | 181 253 | 54 254 | 12 255 | 256 | 257 | 258 | 259 | Arial 260 | 75 261 | true 262 | 263 | 264 | 265 | DEXMD5 266 | 267 | 268 | 269 | 270 | false 271 | 272 | 273 | 274 | 70 275 | 18 276 | 231 277 | 28 278 | 279 | 280 | 281 | 282 | Arial Narrow 283 | 10 284 | 285 | 286 | 287 | QFrame::Box 288 | 289 | 290 | 291 | 292 | false 293 | 294 | 295 | 296 | 70 297 | 54 298 | 231 299 | 28 300 | 301 | 302 | 303 | 304 | Arial Narrow 305 | 10 306 | 307 | 308 | 309 | QFrame::Panel 310 | 311 | 312 | 313 | 314 | false 315 | 316 | 317 | 318 | 70 319 | 91 320 | 231 321 | 28 322 | 323 | 324 | 325 | 326 | Arial Narrow 327 | 10 328 | 329 | 330 | 331 | QFrame::Panel 332 | 333 | 334 | 335 | 336 | false 337 | 338 | 339 | 340 | 360 341 | 19 342 | 231 343 | 28 344 | 345 | 346 | 347 | 348 | Arial Narrow 349 | 10 350 | 351 | 352 | 353 | QFrame::Box 354 | 355 | 356 | 357 | 358 | false 359 | 360 | 361 | 362 | 360 363 | 55 364 | 231 365 | 28 366 | 367 | 368 | 369 | 370 | Arial Narrow 371 | 10 372 | 373 | 374 | 375 | QFrame::Panel 376 | 377 | 378 | 379 | 380 | false 381 | 382 | 383 | 384 | 360 385 | 92 386 | 231 387 | 28 388 | 389 | 390 | 391 | 392 | Arial Narrow 393 | 10 394 | 395 | 396 | 397 | QFrame::Panel 398 | 399 | 400 | 401 | 402 | false 403 | 404 | 405 | 406 | 70 407 | 132 408 | 521 409 | 28 410 | 411 | 412 | 413 | 414 | Arial Narrow 415 | 10 416 | 417 | 418 | 419 | QFrame::Panel 420 | 421 | 422 | 423 | 424 | false 425 | 426 | 427 | 428 | 70 429 | 170 430 | 521 431 | 28 432 | 433 | 434 | 435 | 436 | Arial Narrow 437 | 10 438 | 439 | 440 | 441 | QFrame::Panel 442 | 443 | 444 | 445 | 446 | false 447 | 448 | 449 | 450 | 70 451 | 207 452 | 521 453 | 48 454 | 455 | 456 | 457 | 458 | Arial Narrow 459 | 10 460 | 461 | 462 | 463 | QFrame::Panel 464 | 465 | 466 | 467 | 468 | false 469 | 470 | 471 | 472 | 70 473 | 263 474 | 521 475 | 48 476 | 477 | 478 | 479 | 480 | Arial Narrow 481 | 10 482 | 483 | 484 | 485 | QFrame::Panel 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ApkDetecter 2 | +++++++++++++++++++++++++++++++++++++++++++ 3 | 运行环境: 4 | 1、python 版本 < 3.0 5 | 2、安装pyqt组件 6 | 3、双击ApkDetecter.pyw可直接运行 7 | +++++++++++++++++++++++++++++++++++++++++++ 8 | 9 | Android Apk查壳工具源代码 10 | 主要功能: 11 | 1、检测DEX文件是否加固及加固厂商 12 | 2、检测APK的基本信息: 13 | APKMD5值,APK包名,APK版本,签名信息等 14 | 3、DEX文件的字节信息 15 | 16 | 如果想增加新的apk加固检测方法 17 | 可在CheckProtect类中self.protectflag_dict添加检测点 18 | -------------------------------------------------------------------------------- /TestCSN.py: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8-*- 2 | __author__ = 'Andy' 3 | from AnalysisCSN.CSN import CSN 4 | 5 | class AnCSN(): 6 | def csnAnalysis(self, a_file): 7 | global log 8 | csn = CSN(a_file) 9 | 10 | ######################################################## 基本信息 ############################################### 11 | print "文件路径: ", csn.get_filename() 12 | print "序列号: ", csn.getCertificateSN() 13 | print "发行者: ", csn.getCertificateIDN() 14 | print "签发人: ", csn.getCertificateSDN() 15 | print "文件大小: ", csn.get_size() + " 字节" 16 | print "CSNMd5: ", csn.get_md5() 17 | print "CSNDigest: ", csn.get_digest() 18 | print "CSNSha1: ", csn.get_sha1() 19 | print "CSNSha256: ", csn.get_sha256() 20 | 21 | ######################################################## 黑名单证书 ############################################ 22 | result_csn = csn.check_black_csn(csn.getCertificateSN()) 23 | if result_csn: 24 | print "-" * 55, "" 25 | print "黑名单证书: ", '是 ' + result_csn 26 | else: 27 | pass 28 | print "-" * 55, "" 29 | raw_input('Done!') 30 | log.close() 31 | 32 | if __name__ == "__main__": 33 | obj = AnCSN() 34 | path = r"d:\sample_tx\9.09\e7fea6a5abdaf57b131d6e1fb30a7e49\META-INF\CERT.RSA" 35 | obj.csnAnalysis(path) -------------------------------------------------------------------------------- /UnzipAPK.py: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8-*- 2 | __author__ = 'Andy' 3 | import os 4 | import struct 5 | import tempfile 6 | 7 | class UnzipAPK(): 8 | 9 | def __init__(self, apkPath): 10 | self.unpackDir = apkPath 11 | self.getdexcontent() 12 | #self.Init_dexHeader() 13 | #self.unpackxml() 14 | self.dexdump() 15 | 16 | 17 | def getclassname(self): 18 | import codecs 19 | #dexdump_str = codecs.open(self.unpackDir + os.path.sep +'classes.txt', 'r', 'utf8').read() 20 | dexdump_str = codecs.open(self.unpackDir + os.path.sep +'classes.txt', 'rb').read() 21 | class_name_dict = {} 22 | buf_result = dexdump_str.split("Class #") 23 | for class_file in buf_result: 24 | try: 25 | class_code = class_file.split("\n") 26 | for smali in class_code: 27 | if " Class descriptor :" in smali: 28 | class_name = smali.split("'")[1][1:-1].replace("/", ".") 29 | class_name_dict[class_name] = "" 30 | break 31 | except: 32 | pass 33 | 34 | return class_name_dict 35 | 36 | def unpackxml(self): 37 | cmd = "java -jar tool\\AXMLPrinter2.jar %s > %s" 38 | xmlpath = os.path.join(self.unpackDir, "AndroidManifest.xml") 39 | if os.path.exists(xmlpath): 40 | try: 41 | os.system(cmd % (xmlpath, self.unpackDir + os.path.sep + "AndroidManifest_unpack.xml")) 42 | os.remove(xmlpath) 43 | self.xmlPath = self.unpackDir + os.path.sep + "AndroidManifest_unpack.xml" 44 | xmlfile_object = open(self.xmlPath) 45 | self.xml_content = xmlfile_object.read() 46 | except: 47 | pass 48 | 49 | 50 | def getdexcontent(self): 51 | 52 | self.dexcontent = open(self.unpackDir + os.path.sep +"classes.dex", 'rb').read() 53 | 54 | def getpackagename(self): 55 | fr = open(self.xmlPath, 'r') 56 | packagename = "" 57 | for line in fr: 58 | pos = line.find('package="') 59 | if pos > 0: 60 | packagename = line[pos+9:-1].strip('"') 61 | return packagename 62 | 63 | 64 | # def unzip(self): 65 | # cmd = "tool\\7z.exe x %s -y -o%s *.dex AndroidManifest.xml lib META-INF assets" 66 | # print cmd % (self.apkPath, self.unpackDir) 67 | # os.system(cmd % (self.apkPath, self.unpackDir)) 68 | 69 | def unpackxml(self): 70 | cmd = "java -jar tool\\AXMLPrinter2.jar %s > %s" 71 | xmlpath = os.path.join(self.unpackDir, "AndroidManifest.xml") 72 | if os.path.exists(xmlpath): 73 | try: 74 | os.system(cmd % (xmlpath, self.unpackDir + os.path.sep +"AndroidManifest_unpack.xml")) 75 | os.remove(xmlpath) 76 | self.xmlPath = self.unpackDir + os.path.sep +"AndroidManifest_unpack.xml" 77 | xmlfile_object = open(self.xmlPath) 78 | self.xml_content = xmlfile_object.read() 79 | #self.xml_content = self.xml_content.split('<') 80 | except: 81 | pass 82 | 83 | 84 | 85 | def dexdump(self): 86 | cmd = 'tool\\dexdump.exe -d %s > %s' 87 | dexpath = os.path.join(self.unpackDir, "classes.dex") 88 | if os.path.exists(dexpath): 89 | os.system(cmd % (dexpath, self.unpackDir + os.path.sep +"classes.txt")) 90 | 91 | def getallname(self): 92 | 93 | all_file_name = {} 94 | all_dir_name = {} 95 | for dirpath, dirnames, filenames in os.walk(self.unpackDir): 96 | for file in filenames: 97 | all_file_name[file] = "" 98 | 99 | for dir in dirnames: 100 | all_dir_name[dir] = "" 101 | 102 | return all_file_name, all_dir_name 103 | 104 | 105 | # if __name__ == "__main__": 106 | # apkPath = r"D:\original.apk" 107 | # obj = UnzipAPK(apkPath) -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'Andy' 2 | -------------------------------------------------------------------------------- /androguard/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/androguard/__init__.py -------------------------------------------------------------------------------- /androguard/core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/androguard/core/__init__.py -------------------------------------------------------------------------------- /androguard/core/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/androguard/core/__init__.pyc -------------------------------------------------------------------------------- /androguard/core/analysis/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/androguard/core/analysis/__init__.py -------------------------------------------------------------------------------- /androguard/core/analysis/sign.py: -------------------------------------------------------------------------------- 1 | # This file is part of Androguard. 2 | # 3 | # Copyright (C) 2012, Anthony Desnos 4 | # All rights reserved. 5 | # 6 | # Androguard is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU Lesser General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # Androguard is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU Lesser General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU Lesser General Public License 17 | # along with Androguard. If not, see . 18 | from CheckProtect.androguard.core.bytecodes import dvm 19 | 20 | from CheckProtect.androguard.core.analysis.analysis import TAINTED_PACKAGE_CREATE, TAINTED_PACKAGE_CALL 21 | 22 | TAINTED_PACKAGE_INTERNAL_CALL = 2 23 | FIELD_ACCESS = {"R": 0, "W": 1} 24 | PACKAGE_ACCESS = {TAINTED_PACKAGE_CREATE: 0, TAINTED_PACKAGE_CALL: 1, TAINTED_PACKAGE_INTERNAL_CALL: 2} 25 | 26 | 27 | class Sign: 28 | def __init__(self): 29 | self.levels = {} 30 | self.hlevels = [] 31 | 32 | def add(self, level, value): 33 | self.levels[level] = value 34 | self.hlevels.append(level) 35 | 36 | def get_level(self, l): 37 | return self.levels["L%d" % l] 38 | 39 | def get_string(self): 40 | buff = "" 41 | for i in self.hlevels: 42 | buff += self.levels[i] 43 | return buff 44 | 45 | def get_list(self): 46 | return self.levels["sequencebb"] 47 | 48 | 49 | class Signature: 50 | def __init__(self, tainted_information): 51 | self.tainted_packages = tainted_information.get_tainted_packages() 52 | self.tainted_variables = tainted_information.get_tainted_variables() 53 | 54 | self._cached_signatures = {} 55 | self._cached_fields = {} 56 | self._cached_packages = {} 57 | 58 | self._global_cached = {} 59 | 60 | self.levels = { 61 | # Classical method signature with basic blocks, strings, fields, packages 62 | "L0": { 63 | 0: ( "_get_strings_a", "_get_fields_a", "_get_packages_a" ), 64 | 1: ( "_get_strings_pa", "_get_fields_a", "_get_packages_a" ), 65 | 2: ( "_get_strings_a", "_get_fields_a", "_get_packages_pa_1" ), 66 | 3: ( "_get_strings_a", "_get_fields_a", "_get_packages_pa_2" ), 67 | }, 68 | 69 | # strings 70 | "L1": ["_get_strings_a1"], 71 | 72 | # exceptions 73 | "L2": ["_get_exceptions"], 74 | 75 | # fill array data 76 | "L3": ["_get_fill_array_data"], 77 | } 78 | 79 | self.classes_names = None 80 | self._init_caches() 81 | 82 | def _get_sequence_bb(self, analysis_method): 83 | l = [] 84 | 85 | for i in analysis_method.basic_blocks.get(): 86 | buff = "" 87 | if len(i.get_ins()) > 5: 88 | for ins in i.get_ins(): 89 | buff += ins.get_name() 90 | if buff != "": 91 | l.append(buff) 92 | 93 | return l 94 | 95 | def _get_sequence_bb2(self, analysis_method): 96 | l = [] 97 | 98 | buff = "" 99 | nb = 0 100 | for i in analysis_method.basic_blocks.get(): 101 | if nb == 0: 102 | buff = "" 103 | 104 | for ins in i.get_ins(): 105 | buff += ins.get_name() 106 | nb += 1 107 | 108 | if nb > 5: 109 | l.append(buff) 110 | nb = 0 111 | 112 | if nb != 0: 113 | l.append(buff) 114 | 115 | return l 116 | 117 | def _get_hex(self, analysis_method): 118 | code = analysis_method.get_method().get_code() 119 | if code == None: 120 | return "" 121 | 122 | buff = "" 123 | for i in code.get_bc().get(): 124 | buff += dvm.clean_name_instruction(i) 125 | buff += dvm.static_operand_instruction(i) 126 | 127 | return buff 128 | 129 | def _get_bb(self, analysis_method, functions, options): 130 | bbs = [] 131 | for b in analysis_method.basic_blocks.get(): 132 | l = [] 133 | l.append((b.start, "B")) 134 | l.append((b.start, "[")) 135 | 136 | internal = [] 137 | 138 | op_value = b.get_last().get_op_value() 139 | 140 | # return 141 | if op_value >= 0x0e and op_value <= 0x11: 142 | internal.append((b.end - 1, "R")) 143 | 144 | # if 145 | elif op_value >= 0x32 and op_value <= 0x3d: 146 | internal.append((b.end - 1, "I")) 147 | 148 | # goto 149 | elif op_value >= 0x28 and op_value <= 0x2a: 150 | internal.append((b.end - 1, "G")) 151 | 152 | # sparse or packed switch 153 | elif op_value >= 0x2b and op_value <= 0x2c: 154 | internal.append((b.end - 1, "G")) 155 | 156 | for f in functions: 157 | try: 158 | internal.extend(getattr(self, f)(analysis_method, options)) 159 | except TypeError: 160 | internal.extend(getattr(self, f)(analysis_method)) 161 | 162 | internal.sort() 163 | 164 | for i in internal: 165 | if i[0] >= b.start and i[0] < b.end: 166 | l.append(i) 167 | 168 | del internal 169 | 170 | l.append((b.end, "]")) 171 | 172 | bbs.append(''.join(i[1] for i in l)) 173 | return bbs 174 | 175 | def _init_caches(self): 176 | if self._cached_fields == {}: 177 | for f_t, f in self.tainted_variables.get_fields(): 178 | self._cached_fields[f] = f_t.get_paths_length() 179 | n = 0 180 | for f in sorted(self._cached_fields): 181 | self._cached_fields[f] = n 182 | n += 1 183 | 184 | if self._cached_packages == {}: 185 | for m_t, m in self.tainted_packages.get_packages(): 186 | self._cached_packages[m] = m_t.get_paths_length() 187 | n = 0 188 | for m in sorted(self._cached_packages): 189 | self._cached_packages[m] = n 190 | n += 1 191 | 192 | def _get_fill_array_data(self, analysis_method): 193 | buff = "" 194 | for b in analysis_method.basic_blocks.get(): 195 | for i in b.ins: 196 | if i.get_name() == "FILL-ARRAY-DATA": 197 | buff_tmp = i.get_operands() 198 | for j in range(0, len(buff_tmp)): 199 | buff += "\\x%02x" % ord(buff_tmp[j]) 200 | return buff 201 | 202 | def _get_exceptions(self, analysis_method): 203 | buff = "" 204 | 205 | method = analysis_method.get_method() 206 | code = method.get_code() 207 | if code == None or code.get_tries_size() <= 0: 208 | return buff 209 | 210 | handler_catch_list = code.get_handlers() 211 | 212 | for handler_catch in handler_catch_list.get_list(): 213 | for handler in handler_catch.get_handlers(): 214 | buff += analysis_method.get_vm().get_cm_type(handler.get_type_idx()) 215 | return buff 216 | 217 | def _get_strings_a1(self, analysis_method): 218 | buff = "" 219 | 220 | strings_method = self.tainted_variables.get_strings_by_method(analysis_method.get_method()) 221 | for s in strings_method: 222 | for path in strings_method[s]: 223 | buff += s.replace('\n', ' ') 224 | return buff 225 | 226 | def _get_strings_pa(self, analysis_method): 227 | l = [] 228 | 229 | strings_method = self.tainted_variables.get_strings_by_method(analysis_method.get_method()) 230 | for s in strings_method: 231 | for path in strings_method[s]: 232 | l.append(( path[1], "S%d" % len(s) )) 233 | return l 234 | 235 | 236 | def _get_strings_a(self, analysis_method): 237 | key = "SA-%s" % analysis_method 238 | if key in self._global_cached: 239 | return self._global_cached[key] 240 | 241 | l = [] 242 | 243 | strings_method = self.tainted_variables.get_strings_by_method(analysis_method.get_method()) 244 | for s in strings_method: 245 | for path in strings_method[s]: 246 | l.append(( path[1], "S")) 247 | 248 | self._global_cached[key] = l 249 | return l 250 | 251 | def _get_fields_a(self, analysis_method): 252 | key = "FA-%s" % analysis_method 253 | if key in self._global_cached: 254 | return self._global_cached[key] 255 | 256 | fields_method = self.tainted_variables.get_fields_by_method(analysis_method.get_method()) 257 | l = [] 258 | 259 | for f in fields_method: 260 | for path in fields_method[f]: 261 | l.append((path[1], "F%d" % FIELD_ACCESS[path[0]])) 262 | 263 | self._global_cached[key] = l 264 | return l 265 | 266 | def _get_packages_a(self, analysis_method): 267 | packages_method = self.tainted_packages.get_packages_by_method(analysis_method.get_method()) 268 | l = [] 269 | 270 | for m in packages_method: 271 | for path in packages_method[m]: 272 | l.append((path.get_idx(), "P%s" % (PACKAGE_ACCESS[path.get_access_flag()]) )) 273 | return l 274 | 275 | def _get_packages(self, analysis_method, include_packages): 276 | l = self._get_packages_pa_1(analysis_method, include_packages) 277 | return "".join([i[1] for i in l]) 278 | 279 | def _get_packages_pa_1(self, analysis_method, include_packages): 280 | key = "PA1-%s-%s" % (analysis_method, include_packages) 281 | if key in self._global_cached: 282 | return self._global_cached[key] 283 | 284 | packages_method = self.tainted_packages.get_packages_by_method(analysis_method.get_method()) 285 | if self.classes_names == None: 286 | self.classes_names = analysis_method.get_vm().get_classes_names() 287 | 288 | l = [] 289 | 290 | for m in packages_method: 291 | for path in packages_method[m]: 292 | present = False 293 | for i in include_packages: 294 | if m.find(i) == 0: 295 | present = True 296 | break 297 | 298 | if path.get_access_flag() == 1: 299 | if path.get_class_name() in self.classes_names: 300 | l.append((path.get_idx(), "P%s" % (PACKAGE_ACCESS[2]) )) 301 | else: 302 | if present == True: 303 | l.append((path.get_idx(), "P%s{%s%s%s}" % ( 304 | PACKAGE_ACCESS[path.get_access_flag()], path.get_class_name(), path.get_name(), 305 | path.get_descriptor()) )) 306 | else: 307 | l.append((path.get_idx(), "P%s" % (PACKAGE_ACCESS[path.get_access_flag()]) )) 308 | else: 309 | if present == True: 310 | l.append((path.get_idx(), "P%s{%s}" % (PACKAGE_ACCESS[path.get_access_flag()], m) )) 311 | else: 312 | l.append((path.get_idx(), "P%s" % (PACKAGE_ACCESS[path.get_access_flag()]) )) 313 | 314 | self._global_cached[key] = l 315 | return l 316 | 317 | def _get_packages_pa_2(self, analysis_method, include_packages): 318 | packages_method = self.tainted_packages.get_packages_by_method(analysis_method.get_method()) 319 | 320 | l = [] 321 | 322 | for m in packages_method: 323 | for path in packages_method[m]: 324 | present = False 325 | for i in include_packages: 326 | if m.find(i) == 0: 327 | present = True 328 | break 329 | 330 | if present == True: 331 | l.append((path.get_idx(), "P%s" % (PACKAGE_ACCESS[path.get_access_flag()]) )) 332 | continue 333 | 334 | if path.get_access_flag() == 1: 335 | l.append((path.get_idx(), "P%s{%s%s%s}" % ( 336 | PACKAGE_ACCESS[path.get_access_flag()], path.get_class_name(), path.get_name(), 337 | path.get_descriptor()) )) 338 | else: 339 | l.append((path.get_idx(), "P%s{%s}" % (PACKAGE_ACCESS[path.get_access_flag()], m) )) 340 | 341 | return l 342 | 343 | def get_method(self, analysis_method, signature_type, signature_arguments={}): 344 | key = "%s-%s-%s" % (analysis_method, signature_type, signature_arguments) 345 | if key in self._cached_signatures: 346 | return self._cached_signatures[key] 347 | 348 | s = Sign() 349 | 350 | #print signature_type, signature_arguments 351 | for i in signature_type.split(":"): 352 | # print i, signature_arguments[ i ] 353 | if i == "L0": 354 | _type = self.levels[i][signature_arguments[i]["type"]] 355 | try: 356 | _arguments = signature_arguments[i]["arguments"] 357 | except KeyError: 358 | _arguments = [] 359 | 360 | value = self._get_bb(analysis_method, _type, _arguments) 361 | s.add(i, ''.join(z for z in value)) 362 | 363 | elif i == "L4": 364 | try: 365 | _arguments = signature_arguments[i]["arguments"] 366 | except KeyError: 367 | _arguments = [] 368 | 369 | value = self._get_packages(analysis_method, _arguments) 370 | s.add(i, value) 371 | 372 | elif i == "hex": 373 | value = self._get_hex(analysis_method) 374 | s.add(i, value) 375 | 376 | elif i == "sequencebb": 377 | _type = ('_get_strings_a', '_get_fields_a', '_get_packages_pa_1') 378 | _arguments = ['Landroid', 'Ljava'] 379 | 380 | #value = self._get_bb( analysis_method, _type, _arguments ) 381 | #s.add( i, value ) 382 | 383 | value = self._get_sequence_bb(analysis_method) 384 | s.add(i, value) 385 | 386 | else: 387 | for f in self.levels[i]: 388 | value = getattr(self, f)(analysis_method) 389 | s.add(i, value) 390 | 391 | self._cached_signatures[key] = s 392 | return s 393 | -------------------------------------------------------------------------------- /androguard/core/androconf.py: -------------------------------------------------------------------------------- 1 | # This file is part of Androguard. 2 | # 3 | # Copyright (C) 2010, Anthony Desnos 4 | # All rights reserved. 5 | # 6 | # Androguard is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU Lesser General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # Androguard is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU Lesser General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU Lesser General Public License 17 | # along with Androguard. If not, see . 18 | 19 | import sys, os, logging, types, random, string 20 | 21 | ANDROGUARD_VERSION = "1.5" 22 | 23 | 24 | def get_ascii_string(s): 25 | try: 26 | return s.decode("ascii") 27 | except UnicodeDecodeError: 28 | d = "" 29 | for i in s: 30 | if ord(i) < 128: 31 | d += i 32 | else: 33 | d += "%x" % ord(i) 34 | return d 35 | 36 | 37 | class Color: 38 | Normal = "\033[0m" 39 | Black = "\033[30m" 40 | Red = "\033[31m" 41 | Green = "\033[32m" 42 | Yellow = "\033[33m" 43 | Blue = "\033[34m" 44 | Purple = "\033[35m" 45 | Cyan = "\033[36m" 46 | Grey = "\033[37m" 47 | Bold = "\033[1m" 48 | 49 | 50 | CONF = { 51 | "BIN_DED": "ded.sh", 52 | "PATH_DED": "./decompiler/ded/", 53 | "PATH_DEX2JAR": "./decompiler/dex2jar/", 54 | "BIN_DEX2JAR": "dex2jar.sh", 55 | "PATH_JAD": "./decompiler/jad/", 56 | "BIN_JAD": "jad", 57 | "PRETTY_SHOW": 1, 58 | 59 | # Full python or mix python/c++ (native) 60 | #"ENGINE" : "automatic", 61 | "ENGINE": "python", 62 | 63 | "RECODE_ASCII_STRING": False, 64 | "RECODE_ASCII_STRING_METH": get_ascii_string, 65 | 66 | "DEOBFUSCATED_STRING": True, 67 | # "DEOBFUSCATED_STRING_METH" : get_deobfuscated_string, 68 | 69 | "PATH_JARSIGNER": "jarsigner", 70 | 71 | "COLORS": { 72 | "OFFSET": Color.Yellow, 73 | "OFFSET_ADDR": Color.Green, 74 | "INSTRUCTION_NAME": Color.Yellow, 75 | "BRANCH_FALSE": Color.Red, 76 | "BRANCH_TRUE": Color.Green, 77 | "BRANCH": Color.Blue, 78 | "EXCEPTION": Color.Cyan, 79 | "BB": Color.Purple, 80 | "NOTE": Color.Red, 81 | "NORMAL": Color.Normal, 82 | }, 83 | 84 | "PRINT_FCT": sys.stdout.write, 85 | 86 | "LAZY_ANALYSIS": False, 87 | } 88 | 89 | 90 | def default_colors(obj): 91 | CONF["COLORS"]["OFFSET"] = obj.Yellow 92 | CONF["COLORS"]["OFFSET_ADDR"] = obj.Green 93 | CONF["COLORS"]["INSTRUCTION_NAME"] = obj.Yellow 94 | CONF["COLORS"]["BRANCH_FALSE"] = obj.Red 95 | CONF["COLORS"]["BRANCH_TRUE"] = obj.Green 96 | CONF["COLORS"]["BRANCH"] = obj.Blue 97 | CONF["COLORS"]["EXCEPTION"] = obj.Cyan 98 | CONF["COLORS"]["BB"] = obj.Purple 99 | CONF["COLORS"]["NOTE"] = obj.Red 100 | CONF["COLORS"]["NORMAL"] = obj.Normal 101 | 102 | 103 | def disable_colors(): 104 | """ Disable colors from the output (color = normal)""" 105 | for i in CONF["COLORS"]: 106 | CONF["COLORS"][i] = Color.normal 107 | 108 | 109 | def remove_colors(): 110 | """ Remove colors from the output (no escape sequences)""" 111 | for i in CONF["COLORS"]: 112 | CONF["COLORS"][i] = "" 113 | 114 | 115 | def enable_colors(colors): 116 | for i in colors: 117 | CONF["COLORS"][i] = colors[i] 118 | 119 | 120 | def save_colors(): 121 | c = {} 122 | for i in CONF["COLORS"]: 123 | c[i] = CONF["COLORS"][i] 124 | return c 125 | 126 | 127 | def long2int(l): 128 | if l > 0x7fffffff: 129 | l = (0x7fffffff & l) - 0x80000000 130 | return l 131 | 132 | 133 | def long2str(l): 134 | """Convert an integer to a string.""" 135 | if type(l) not in (types.IntType, types.LongType): 136 | raise ValueError, 'the input must be an integer' 137 | 138 | if l < 0: 139 | raise ValueError, 'the input must be greater than 0' 140 | s = '' 141 | while l: 142 | s = s + chr(l & 255L) 143 | l >>= 8 144 | 145 | return s 146 | 147 | 148 | def str2long(s): 149 | """Convert a string to a long integer.""" 150 | if type(s) not in (types.StringType, types.UnicodeType): 151 | raise ValueError, 'the input must be a string' 152 | 153 | l = 0L 154 | for i in s: 155 | l <<= 8 156 | l |= ord(i) 157 | 158 | return l 159 | 160 | 161 | def random_string(): 162 | return random.choice(string.letters) + ''.join( 163 | [random.choice(string.letters + string.digits) for i in range(10 - 1)]) 164 | 165 | 166 | def is_android(filename): 167 | """Return the type of the file 168 | 169 | @param filename : the filename 170 | @rtype : "APK", "DEX", "ELF", None 171 | """ 172 | 173 | fd = open(filename, "r") 174 | val = None 175 | 176 | f_bytes = fd.read(7) 177 | 178 | val = is_android_raw(f_bytes) 179 | 180 | fd.close() 181 | return val 182 | 183 | 184 | def is_android_raw(raw): 185 | val = None 186 | f_bytes = raw[:7] 187 | 188 | if f_bytes[0:2] == "PK": 189 | val = "APK" 190 | elif f_bytes[0:3] == "dex": 191 | val = "DEX" 192 | elif f_bytes[0:7] == "\x7fELF\x01\x01\x01": 193 | val = "ELF" 194 | elif f_bytes[0:4] == "\x03\x00\x08\x00": 195 | val = "AXML" 196 | 197 | return val 198 | 199 | # from scapy 200 | log_andro = logging.getLogger("andro") 201 | console_handler = logging.StreamHandler() 202 | console_handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s")) 203 | log_andro.addHandler(console_handler) 204 | log_runtime = logging.getLogger("andro.runtime") # logs at runtime 205 | log_interactive = logging.getLogger("andro.interactive") # logs in interactive functions 206 | log_loading = logging.getLogger("andro.loading") # logs when loading andro 207 | 208 | 209 | def set_lazy(): 210 | CONF["LAZY_ANALYSIS"] = True 211 | 212 | 213 | def set_debug(): 214 | log_andro.setLevel(logging.DEBUG) 215 | 216 | 217 | def get_debug(): 218 | return log_andro.getEffectiveLevel() == logging.DEBUG 219 | 220 | 221 | def warning(x): 222 | log_runtime.warning(x) 223 | 224 | 225 | def error(x): 226 | log_runtime.error(x) 227 | raise () 228 | 229 | 230 | def debug(x): 231 | log_runtime.debug(x) 232 | 233 | 234 | def set_options(key, value): 235 | CONF[key] = value 236 | 237 | 238 | def save_to_disk(buff, output): 239 | fd = open(output, "w") 240 | fd.write(buff) 241 | fd.close() 242 | 243 | 244 | def rrmdir(directory): 245 | for root, dirs, files in os.walk(directory, topdown=False): 246 | for name in files: 247 | os.remove(os.path.join(root, name)) 248 | for name in dirs: 249 | os.rmdir(os.path.join(root, name)) 250 | os.rmdir(directory) 251 | 252 | -------------------------------------------------------------------------------- /androguard/core/androconf.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/androguard/core/androconf.pyc -------------------------------------------------------------------------------- /androguard/core/androgen.py: -------------------------------------------------------------------------------- 1 | # This file is part of Androguard. 2 | # 3 | # Copyright (C) 2012, Anthony Desnos 4 | # All rights reserved. 5 | # 6 | # Androguard is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU Lesser General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # Androguard is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU Lesser General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU Lesser General Public License 17 | # along with Androguard. If not, see . 18 | from CheckProtect.androguard.core.bytecodes import dvm 19 | 20 | from CheckProtect.androguard.core import androconf 21 | from CheckProtect.androguard.core.bytecodes import jvm 22 | from CheckProtect.androguard.core.bytecodes import apk 23 | from CheckProtect.androguard.core.analysis import analysis 24 | 25 | 26 | class BC: 27 | def __init__(self, bc): 28 | self.__bc = bc 29 | 30 | def get_vm(self): 31 | return self.__bc 32 | 33 | def get_analysis(self): 34 | return self.__a 35 | 36 | def analyze(self): 37 | self.__a = analysis.uVMAnalysis(self.__bc) 38 | self.__bc.set_vmanalysis(self.__a) 39 | 40 | def _get(self, val, name): 41 | l = [] 42 | r = getattr(self.__bc, val)(name) 43 | for i in r: 44 | l.append(i) 45 | return l 46 | 47 | def _gets(self, val): 48 | l = [] 49 | r = getattr(self.__bc, val)() 50 | for i in r: 51 | l.append(i) 52 | return l 53 | 54 | def gets(self, name): 55 | return self._gets("get_" + name) 56 | 57 | def get(self, val, name): 58 | return self._get("get_" + val, name) 59 | 60 | def insert_direct_method(self, name, method): 61 | return self.__bc.insert_direct_method(name, method) 62 | 63 | def insert_craft_method(self, name, proto, codes): 64 | return self.__bc.insert_craft_method(name, proto, codes) 65 | 66 | def show(self): 67 | self.__bc.show() 68 | 69 | def pretty_show(self): 70 | self.__bc.pretty_show() 71 | 72 | def save(self): 73 | return self.__bc.save() 74 | 75 | def __getattr__(self, value): 76 | return getattr(self.__bc, value) 77 | 78 | 79 | class Androguard: 80 | """Androguard is the main object to abstract and manage differents formats 81 | 82 | @param files : a list of filenames (filename must be terminated by .class or .dex) 83 | @param raw : specify if the filename is in fact a raw buffer (default : False) #FIXME 84 | """ 85 | 86 | def __init__(self, files, raw=False): 87 | self.__files = files 88 | 89 | self.__orig_raw = {} 90 | for i in self.__files: 91 | self.__orig_raw[i] = open(i, "rb").read() 92 | 93 | self.__bc = [] 94 | self._analyze() 95 | 96 | def _iterFlatten(self, root): 97 | if isinstance(root, (list, tuple)): 98 | for element in root: 99 | for e in self._iterFlatten(element): 100 | yield e 101 | else: 102 | yield root 103 | 104 | def _analyze(self): 105 | for i in self.__files: 106 | #print "processing ", i 107 | if ".class" in i: 108 | bc = jvm.JVMFormat(self.__orig_raw[i]) 109 | elif ".jar" in i: 110 | x = jvm.JAR(i) 111 | bc = x.get_classes() 112 | elif ".dex" in i: 113 | bc = dvm.DalvikVMFormat(self.__orig_raw[i]) 114 | elif ".apk" in i: 115 | x = apk.APK(i) 116 | bc = dvm.DalvikVMFormat(x.get_dex()) 117 | else: 118 | ret_type = androconf.is_android(i) 119 | if ret_type == "APK": 120 | x = apk.APK(i) 121 | bc = dvm.DalvikVMFormat(x.get_dex()) 122 | elif ret_type == "DEX": 123 | bc = dvm.DalvikVMFormat(open(i, "rb").read()) 124 | elif ret_type == "ELF": 125 | from CheckProtect.androguard.core.binaries import elf 126 | 127 | bc = elf.ELF(open(i, "rb").read()) 128 | else: 129 | raise ( "Unknown bytecode" ) 130 | 131 | if isinstance(bc, list): 132 | for j in bc: 133 | self.__bc.append((j[0], BC(jvm.JVMFormat(j[1])) )) 134 | else: 135 | self.__bc.append((i, BC(bc))) 136 | 137 | def ianalyze(self): 138 | for i in self.get_bc(): 139 | i[1].analyze() 140 | 141 | def get_class(self, class_name): 142 | for _, bc in self.__bc: 143 | if bc.get_class(class_name) == True: 144 | return bc 145 | return None 146 | 147 | def get_raw(self): 148 | """Return raw format of all file""" 149 | l = [] 150 | for _, bc in self.__bc: 151 | l.append(bc._get_raw()) 152 | return l 153 | 154 | def get_orig_raw(self): 155 | return self.__orig_raw 156 | 157 | def get_method_descriptor(self, class_name, method_name, descriptor): 158 | """ 159 | Return the specific method 160 | 161 | @param class_name : the class name of the method 162 | @param method_name : the name of the method 163 | @param descriptor : the descriptor of the method 164 | """ 165 | for file_name, bc in self.__bc: 166 | x = bc.get_method_descriptor(class_name, method_name, descriptor) 167 | if x != None: 168 | return x, bc 169 | return None, None 170 | 171 | def get_field_descriptor(self, class_name, field_name, descriptor): 172 | """ 173 | Return the specific field 174 | 175 | @param class_name : the class name of the field 176 | @param field_name : the name of the field 177 | @param descriptor : the descriptor of the field 178 | """ 179 | for file_name, bc in self.__bc: 180 | x = bc.get_field_descriptor(class_name, field_name, descriptor) 181 | if x != None: 182 | return x, bc 183 | return None, None 184 | 185 | def get(self, name, val): 186 | """ 187 | Return the specific value for all files 188 | 189 | @param name : 190 | @param val : 191 | """ 192 | if name == "file": 193 | for file_name, bc in self.__bc: 194 | if file_name == val: 195 | return bc 196 | 197 | return None 198 | else: 199 | l = [] 200 | for file_name, bc in self.__bc: 201 | l.append(bc.get(name, val)) 202 | 203 | return list(self._iterFlatten(l)) 204 | 205 | def gets(self, name): 206 | """ 207 | Return the specific value for all files 208 | 209 | @param name : 210 | """ 211 | l = [] 212 | for file_name, bc in self.__bc: 213 | l.append(bc.gets(name)) 214 | 215 | return list(self._iterFlatten(l)) 216 | 217 | def get_vms(self): 218 | return [i[1].get_vm() for i in self.__bc] 219 | 220 | def get_bc(self): 221 | return self.__bc 222 | 223 | def show(self): 224 | """ 225 | Display all files 226 | """ 227 | for _, bc in self.__bc: 228 | bc.show() 229 | 230 | def pretty_show(self): 231 | """ 232 | Display all files 233 | """ 234 | for _, bc in self.__bc: 235 | bc.pretty_show() 236 | 237 | 238 | class AndroguardS: 239 | """AndroguardS is the main object to abstract and manage differents formats but only per filename. In fact this class is just a wrapper to the main class Androguard 240 | 241 | @param filename : the filename to use (filename must be terminated by .class or .dex) 242 | @param raw : specify if the filename is a raw buffer (default : False) 243 | """ 244 | 245 | def __init__(self, filename, raw=False): 246 | self.__filename = filename 247 | self.__orig_a = Androguard([filename], raw) 248 | self.__a = self.__orig_a.get("file", filename) 249 | 250 | def get_orig_raw(self): 251 | return self.__orig_a.get_orig_raw()[self.__filename] 252 | 253 | def get_vm(self): 254 | """ 255 | This method returns the VMFormat which correspond to the file 256 | 257 | @rtype: L{jvm.JVMFormat} or L{dvm.DalvikVMFormat} 258 | """ 259 | return self.__a.get_vm() 260 | 261 | def save(self): 262 | """ 263 | Return the original format (with the modifications) into raw format 264 | 265 | @rtype: string 266 | """ 267 | return self.__a.save() 268 | 269 | def __getattr__(self, value): 270 | try: 271 | return getattr(self.__orig_a, value) 272 | except AttributeError: 273 | return getattr(self.__a, value) 274 | -------------------------------------------------------------------------------- /androguard/core/bytecode.py: -------------------------------------------------------------------------------- 1 | # This file is part of Androguard. 2 | # 3 | # Copyright (C) 2012, Anthony Desnos 4 | # All rights reserved. 5 | # 6 | # Androguard is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU Lesser General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # Androguard is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU Lesser General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU Lesser General Public License 17 | # along with Androguard. If not, see . 18 | 19 | from struct import unpack, pack 20 | 21 | from androguard.core.androconf import warning, error, CONF, enable_colors, remove_colors, save_colors 22 | 23 | 24 | def disable_print_colors(): 25 | colors = save_colors() 26 | remove_colors() 27 | return colors 28 | 29 | 30 | def enable_print_colors(colors): 31 | enable_colors(colors) 32 | 33 | # Handle exit message 34 | def Exit(msg): 35 | warning("Error : " + msg) 36 | raise ("oops") 37 | 38 | 39 | def Warning(msg): 40 | warning(msg) 41 | 42 | 43 | def _PrintBanner(): 44 | print_fct = CONF["PRINT_FCT"] 45 | print_fct("*" * 75 + "\n") 46 | 47 | 48 | def _PrintSubBanner(title=None): 49 | print_fct = CONF["PRINT_FCT"] 50 | if title == None: 51 | print_fct("#" * 20 + "\n") 52 | else: 53 | print_fct("#" * 10 + " " + title + "\n") 54 | 55 | 56 | def _PrintNote(note, tab=0): 57 | print_fct = CONF["PRINT_FCT"] 58 | note_color = CONF["COLORS"]["NOTE"] 59 | normal_color = CONF["COLORS"]["NORMAL"] 60 | print_fct("\t" * tab + "%s# %s%s" % (note_color, note, normal_color) + "\n") 61 | 62 | # Print arg into a correct format 63 | def _Print(name, arg): 64 | buff = name + " " 65 | 66 | if type(arg).__name__ == 'int': 67 | buff += "0x%x" % arg 68 | elif type(arg).__name__ == 'long': 69 | buff += "0x%x" % arg 70 | elif type(arg).__name__ == 'str': 71 | buff += "%s" % arg 72 | elif isinstance(arg, SV): 73 | buff += "0x%x" % arg.get_value() 74 | elif isinstance(arg, SVs): 75 | buff += arg.get_value().__str__() 76 | 77 | print buff 78 | 79 | 80 | def PrettyShow(basic_blocks): 81 | PrettyShow1(basic_blocks) 82 | 83 | 84 | def PrettyShowEx(exceptions): 85 | if len(exceptions) > 0: 86 | CONF["PRINT_FCT"]("Exceptions:\n") 87 | for i in exceptions: 88 | CONF["PRINT_FCT"]("\t%s%s%s\n" % (CONF["COLORS"]["EXCEPTION"], i.show_buff(), CONF["COLORS"]["NORMAL"])) 89 | 90 | 91 | def _PrintXRef(tag, items): 92 | print_fct = CONF["PRINT_FCT"] 93 | for i in items: 94 | print_fct("%s: %s %s %s %s\n" % ( 95 | tag, i[0].get_class_name(), i[0].get_name(), i[0].get_descriptor(), 96 | ' '.join("%x" % j.get_idx() for j in i[1]))) 97 | 98 | 99 | def _PrintDefault(msg): 100 | print_fct = CONF["PRINT_FCT"] 101 | print_fct(msg) 102 | 103 | 104 | def PrettyShow1(basic_blocks): 105 | idx = 0 106 | nb = 0 107 | 108 | offset_color = CONF["COLORS"]["OFFSET"] 109 | offset_addr_color = CONF["COLORS"]["OFFSET_ADDR"] 110 | instruction_name_color = CONF["COLORS"]["INSTRUCTION_NAME"] 111 | branch_false_color = CONF["COLORS"]["BRANCH_FALSE"] 112 | branch_true_color = CONF["COLORS"]["BRANCH_TRUE"] 113 | branch_color = CONF["COLORS"]["BRANCH"] 114 | exception_color = CONF["COLORS"]["EXCEPTION"] 115 | bb_color = CONF["COLORS"]["BB"] 116 | normal_color = CONF["COLORS"]["NORMAL"] 117 | print_fct = CONF["PRINT_FCT"] 118 | 119 | for i in basic_blocks: 120 | print_fct("%s%s%s : \n" % (bb_color, i.name, normal_color)) 121 | instructions = i.get_instructions() 122 | for ins in instructions: 123 | #for ins in i.ins : 124 | 125 | notes = ins.get_notes() 126 | if notes != []: 127 | for note in notes: 128 | _PrintNote(note, 1) 129 | 130 | print_fct("\t%s%-3d%s(%s%08x%s) " % (offset_color, nb, normal_color, offset_addr_color, idx, normal_color)) 131 | print_fct("%s%-20s%s %s" % (instruction_name_color, ins.get_name(), normal_color, ins.get_output(idx))) 132 | 133 | op_value = ins.get_op_value() 134 | if ins == instructions[-1] and i.childs != []: 135 | print_fct(" ") 136 | # packed/sparse-switch 137 | if (op_value == 0x2b or op_value == 0x2c) and len(i.childs) > 1: 138 | values = i.get_special_ins(idx).get_values() 139 | 140 | print_fct("%s[ D:%s%s " % (branch_false_color, i.childs[0][2].name, branch_color)) 141 | print_fct(' '.join("%d:%s" % (values[j], i.childs[j + 1][2].name) for j in 142 | range(0, len(i.childs) - 1)) + " ]%s" % normal_color) 143 | else: 144 | if len(i.childs) == 2: 145 | print_fct("%s[ %s%s " % (branch_false_color, i.childs[0][2].name, branch_true_color)) 146 | print_fct(' '.join("%s" % c[2].name for c in i.childs[1:]) + " ]%s" % normal_color) 147 | else: 148 | print_fct("%s[ " % branch_color + ' '.join( 149 | "%s" % c[2].name for c in i.childs) + " ]%s" % normal_color) 150 | 151 | idx += ins.get_length() 152 | nb += 1 153 | 154 | print_fct("\n") 155 | 156 | if i.exception_analysis != None: 157 | print_fct("\t%s%s%s\n" % (exception_color, i.exception_analysis.show_buff(), normal_color)) 158 | 159 | print_fct("\n") 160 | 161 | 162 | def method2dot(mx): 163 | """ 164 | Export analysis method to dot format 165 | 166 | @param mx : MethodAnalysis object 167 | 168 | @rtype : dot format buffer 169 | """ 170 | 171 | vm = mx.get_vm() 172 | buff = "" 173 | for i in mx.basic_blocks.get(): 174 | val = "green" 175 | if len(i.childs) > 1: 176 | val = "red" 177 | elif len(i.childs) == 1: 178 | val = "blue" 179 | 180 | for j in i.childs: 181 | buff += "\"%s\" -> \"%s\" [color=\"%s\"];\n" % ( i.get_name(), j[-1].get_name(), val ) 182 | if val == "red": 183 | val = "green" 184 | 185 | idx = i.start 186 | label = "" 187 | for ins in i.get_instructions(): 188 | label += "%x %s\l" % (idx, vm.dotbuff(ins, idx)) 189 | idx += ins.get_length() 190 | 191 | buff += "\"%s\" [color=\"lightgray\", label=\"%s\"]\n" % (i.get_name(), label) 192 | return buff 193 | 194 | 195 | def method2format(output, _format="png", mx=None, raw=False): 196 | """ 197 | Export method to a specific file format 198 | 199 | @param output : output filename 200 | @param _format : format type (png, jpg ...) (default : png) 201 | @param mx : specify the MethodAnalysis object 202 | @param raw : use directly a dot raw buffer 203 | """ 204 | try: 205 | import pydot 206 | except ImportError: 207 | error("module pydot not found") 208 | 209 | buff = "digraph code {\n" 210 | buff += "graph [bgcolor=white];\n" 211 | buff += "node [color=lightgray, style=filled shape=box fontname=\"Courier\" fontsize=\"8\"];\n" 212 | 213 | if raw == False: 214 | buff += method2dot(mx) 215 | else: 216 | buff += raw 217 | 218 | buff += "}" 219 | 220 | d = pydot.graph_from_dot_data(buff) 221 | if d: 222 | getattr(d, "write_" + _format)(output) 223 | 224 | 225 | def method2png(output, mx=None, raw=False): 226 | """ 227 | Export method to a png file format 228 | 229 | @param output : output filename 230 | @param mx : specify the MethodAnalysis object 231 | @param raw : use directly a dot raw buffer 232 | """ 233 | buff = raw 234 | if raw == False: 235 | buff = method2dot(mx) 236 | 237 | method2format(output, "png", mx, buff) 238 | 239 | 240 | def method2jpg(output, mx=None, raw=False): 241 | """ 242 | Export method to a jpg file format 243 | 244 | @param output : output filename 245 | @param mx : specify the MethodAnalysis object 246 | @param raw : use directly a dot raw buffer 247 | """ 248 | buff = raw 249 | if raw == False: 250 | buff = method2dot(mx) 251 | 252 | method2format(output, "jpg", mx, buff) 253 | 254 | 255 | class SV: 256 | """SV is used to handle more easily a value""" 257 | 258 | def __init__(self, size, buff): 259 | self.__size = size 260 | self.__value = unpack(self.__size, buff)[0] 261 | 262 | def _get(self): 263 | return pack(self.__size, self.__value) 264 | 265 | def __str__(self): 266 | return "0x%x" % self.__value 267 | 268 | def __int__(self): 269 | return self.__value 270 | 271 | def get_value_buff(self): 272 | return self._get() 273 | 274 | def get_value(self): 275 | return self.__value 276 | 277 | def set_value(self, attr): 278 | self.__value = attr 279 | 280 | 281 | class SVs: 282 | """SVs is used to handle more easily a structure of different values""" 283 | 284 | def __init__(self, size, ntuple, buff): 285 | self.__size = size 286 | 287 | self.__value = ntuple._make(unpack(self.__size, buff)) 288 | 289 | def _get(self): 290 | l = [] 291 | for i in self.__value._fields: 292 | l.append(getattr(self.__value, i)) 293 | return pack(self.__size, *l) 294 | 295 | def _export(self): 296 | return [x for x in self.__value._fields] 297 | 298 | def get_value_buff(self): 299 | return self._get() 300 | 301 | def get_value(self): 302 | return self.__value 303 | 304 | def set_value(self, attr): 305 | self.__value = self.__value._replace(**attr) 306 | 307 | def __str__(self): 308 | return self.__value.__str__() 309 | 310 | 311 | def object_to_str(obj): 312 | if isinstance(obj, str): 313 | return obj 314 | elif isinstance(obj, bool): 315 | return "" 316 | elif isinstance(obj, int): 317 | return pack("", "") 437 | i = i.replace("$", "_") 438 | 439 | return i 440 | 441 | 442 | def FormatDescriptorToPython(input): 443 | i = input.replace("/", "_") 444 | i = i.replace(";", "") 445 | i = i.replace("[", "") 446 | i = i.replace("(", "") 447 | i = i.replace(")", "") 448 | i = i.replace(" ", "") 449 | i = i.replace("$", "") 450 | 451 | return i 452 | 453 | ####################### class/method/field export ######################## 454 | def ExportVMToPython(vm): 455 | """ 456 | Export classes/methods/fields' names in the python namespace 457 | 458 | @param vm : a VM object (DalvikVMFormat, JVMFormat) 459 | """ 460 | for _class in vm.get_classes(): 461 | ### Class 462 | name = "CLASS_" + FormatClassToPython(_class.get_name()) 463 | setattr(vm, name, _class) 464 | 465 | ### Methods 466 | m = {} 467 | for method in _class.get_methods(): 468 | if method.get_name() not in m: 469 | m[method.get_name()] = [] 470 | m[method.get_name()].append(method) 471 | 472 | for i in m: 473 | if len(m[i]) == 1: 474 | j = m[i][0] 475 | name = "METHOD_" + FormatNameToPython(j.get_name()) 476 | setattr(_class, name, j) 477 | else: 478 | for j in m[i]: 479 | name = "METHOD_" + FormatNameToPython(j.get_name()) + "_" + FormatDescriptorToPython( 480 | j.get_descriptor()) 481 | setattr(_class, name, j) 482 | 483 | ### Fields 484 | f = {} 485 | for field in _class.get_fields(): 486 | if field.get_name() not in f: 487 | f[field.get_name()] = [] 488 | f[field.get_name()].append(field) 489 | 490 | for i in f: 491 | if len(f[i]) == 1: 492 | j = f[i][0] 493 | name = "FIELD_" + FormatNameToPython(j.get_name()) 494 | setattr(_class, name, j) 495 | else: 496 | for j in f[i]: 497 | name = "FIELD_" + FormatNameToPython(j.get_name()) + "_" + FormatDescriptorToPython( 498 | j.get_descriptor()) 499 | setattr(_class, name, j) 500 | 501 | -------------------------------------------------------------------------------- /androguard/core/bytecode.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/androguard/core/bytecode.pyc -------------------------------------------------------------------------------- /androguard/core/bytecodes/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/androguard/core/bytecodes/__init__.py -------------------------------------------------------------------------------- /androguard/core/bytecodes/arm.py: -------------------------------------------------------------------------------- 1 | # Radare ! 2 | 3 | from r2 import r_bin 4 | from r2 import r_asm 5 | from r2 import r_anal 6 | from r2 import r_core 7 | 8 | from miasm.arch.arm_arch import arm_mn 9 | from miasm.core.bin_stream import bin_stream 10 | from miasm.core import asmbloc 11 | 12 | 13 | class ARM2: 14 | def __init__(self): 15 | b = r_bin.RBin() 16 | b.load("./apks/exploits/617efb2d51ad5c4aed50b76119ad880c6adcd4d2e386b3170930193525b0563d", None) 17 | baddr = b.get_baddr() 18 | print '-> Sections' 19 | for i in b.get_sections(): 20 | print 'offset=0x%08x va=0x%08x size=%05i %s' % (i.offset, baddr + i.rva, i.size, i.name) 21 | 22 | core = r_core.RCore() 23 | core.config.set_i("io.va", 1) 24 | core.config.set_i("anal.split", 1) 25 | 26 | core.file_open("./apks/exploits/617efb2d51ad5c4aed50b76119ad880c6adcd4d2e386b3170930193525b0563d", 0, 0) 27 | core.bin_load(None) 28 | 29 | core.anal_all() 30 | 31 | for fcn in core.anal.get_fcns(): 32 | print type(fcn), fcn.type, "%x" % fcn.addr, fcn.ninstr, fcn.name 33 | # if (fcn.type == FcnType_FCN or fcn.type == FcnType_SYM): 34 | 35 | for s in core.bin.get_entries(): 36 | print s, type(s), s.rva, "%x" % s.offset 37 | 38 | 39 | #a = r_asm.RAsm() 40 | for s in core.bin.get_symbols(): 41 | print s, s.name, s.rva, s.offset, s.size 42 | if s.name == "rootshell": 43 | #print core.disassemble_bytes( 0x8000 + s.offset, s.size ) 44 | 45 | #core.assembler.mdisassemble( 0x8000 + s.offset, s.size ) 46 | z = core.op_anal(0x8000 + s.offset) 47 | print z.mnemonic 48 | 49 | raise ("oo") 50 | 51 | print core.bin.bins, core.bin.user 52 | d = core.bin.read_at(0x8000 + s.offset, x, s.size) 53 | print d 54 | raise ("ooo") 55 | j = 0 56 | while j < s.size: 57 | v = core.disassemble(0x8000 + s.offset + j) 58 | v1 = core.op_str(0x8000 + s.offset + j) 59 | 60 | print v1 61 | # print 0x8000 + s.offset + j, j, v.inst_len, v.buf_asm 62 | j += v.inst_len 63 | 64 | #for i in core.asm_bwdisassemble(s.rva, 4, s.size/4) : 65 | # print "la", i 66 | # print a.mdisassemble( 20, 0x90 ) #"main", "main" ) #s.name ) 67 | 68 | -------------------------------------------------------------------------------- /androguard/core/bytecodes/jvm_generate.py: -------------------------------------------------------------------------------- 1 | # This file is part of Androguard. 2 | # 3 | # Copyright (C) 2012 Anthony Desnos 4 | # All rights reserved. 5 | # 6 | # Androguard is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU Lesser General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # Androguard is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU Lesser General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU Lesser General Public License 17 | # along with Androguard. If not, see . 18 | 19 | import random 20 | 21 | from androconf import error 22 | from CheckProtect.androguard.core.bytecodes import jvm 23 | 24 | 25 | class Automaton: 26 | def __init__(self, _analysis): 27 | self.__analysis = _analysis 28 | 29 | try: 30 | from networkx import DiGraph 31 | from networkx import draw_graphviz, write_dot 32 | except ImportError: 33 | error("module networkx not found") 34 | 35 | self.__G = DiGraph() 36 | 37 | for m in self.__analysis.get_methods(): 38 | for bb in m.basic_blocks.get(): 39 | for trace in bb.stack_traces.get(): 40 | for mre in jvm.MATH_JVM_RE: 41 | if mre[0].match(trace[2].get_name()): 42 | for i in trace[3].gets(): 43 | self._add(str(i)) 44 | 45 | def _add(self, elem): 46 | l = [] 47 | x = "" 48 | for i in elem: 49 | if i not in jvm.MATH_JVM_OPCODES.values(): 50 | x += i 51 | else: 52 | l.append(x) 53 | l.append(i) 54 | x = "" 55 | 56 | if len(l) > 1: 57 | l.append(x) 58 | 59 | self._add_expr(l) 60 | 61 | def _add_expr(self, l): 62 | if l == []: 63 | return 64 | i = 0 65 | while i < (len(l) - 1): 66 | self.__G.add_edge(self._transform(l[i]), self._transform(l[i + 1])) 67 | 68 | i += 1 69 | 70 | def _transform(self, i): 71 | if "VARIABLE" in i: 72 | return "V" 73 | return i 74 | 75 | def new(self, loop): 76 | expr = [] 77 | 78 | l = list(self.__G.node) 79 | 80 | init = l[random.randint(0, len(l) - 1)] 81 | while init in jvm.MATH_JVM_OPCODES.values(): 82 | init = l[random.randint(0, len(l) - 1)] 83 | 84 | expr.append(init) 85 | 86 | i = 0 87 | while i <= loop: 88 | l = list(self.__G.edge[init]) 89 | if l == []: 90 | break 91 | 92 | init = l[random.randint(0, len(l) - 1)] 93 | expr.append(init) 94 | 95 | i += 1 96 | 97 | return expr 98 | 99 | def show(self): 100 | print self.__G.node 101 | print self.__G.edge 102 | 103 | #draw_graphviz(self.__G) 104 | #write_dot(self.__G,'file.dot') 105 | 106 | 107 | class JVMGenerate: 108 | def __init__(self, _vm, _analysis): 109 | self.__vm = _vm 110 | self.__analysis = _analysis 111 | 112 | self.__automaton = Automaton(self.__analysis) 113 | self.__automaton.show() 114 | 115 | def create_affectation(self, method_name, desc): 116 | l = [] 117 | 118 | if desc[0] == 0: 119 | l.append(["aload_0"]) 120 | l.append(["bipush", desc[2]]) 121 | l.append(["putfield", desc[1].get_name(), desc[1].get_descriptor()]) 122 | 123 | return l 124 | 125 | def write(self, method, offset, field): 126 | print method, offset, field 127 | expr = self.__automaton.new(5) 128 | 129 | print field.get_name(), "EXPR ->", expr 130 | 131 | self._transform(expr) 132 | 133 | 134 | def _transform(self, expr): 135 | if len(expr) == 1: 136 | return 137 | 138 | x = [expr.pop(0), expr.pop(1), expr.pop(0)] 139 | 140 | # while expr != [] : 141 | -------------------------------------------------------------------------------- /androguard/core/bytecodes/libdvm/Makefile: -------------------------------------------------------------------------------- 1 | SRC = dvm.cc buff.cc 2 | 3 | CUROS = $(shell uname -s) 4 | ifeq ($(CUROS),Darwin) 5 | LDFLAGS = -lpython 6 | else 7 | LDFLAGS = 8 | endif 9 | 10 | CFLAGS += -g -fPIC -I/usr/include/python2.7/ 11 | mkdir = mkdir -p 12 | CD = cd 13 | RM = rm -f 14 | 15 | CCP = g++ 16 | 17 | LIBNAME = dvmnative 18 | 19 | OBJ = $(SRC:.cc=.o) 20 | 21 | .SILENT: 22 | 23 | all : $(OBJ) LIBDVM 24 | 25 | LIBDVM : 26 | $(CCP) -o $(LIBNAME).so $(OBJ) -shared $(LDFLAGS) 27 | 28 | clean : 29 | $(RM) *.o $(LIBNAME).so 30 | 31 | %.o : %.cc 32 | echo " CCP $@" 33 | $(CCP) $(CFLAGS) -c -o $@ $< 34 | -------------------------------------------------------------------------------- /androguard/core/bytecodes/libdvm/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/androguard/core/bytecodes/libdvm/__init__.py -------------------------------------------------------------------------------- /androguard/core/bytecodes/libdvm/buff.cc: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Androguard. 3 | 4 | Copyright (C) 2011, Anthony Desnos 5 | All rights reserved. 6 | 7 | Androguard is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU Lesser General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | Androguard is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public License 18 | along with Androguard. If not, see . 19 | */ 20 | 21 | #include "buff.h" 22 | 23 | #include 24 | 25 | Buff::Buff() { 26 | 27 | } 28 | 29 | Buff::Buff(const char *data, size_t data_len) { 30 | bdata = data; 31 | bdata_len = data_len; 32 | bcurrent_idx = 0; 33 | } 34 | 35 | Buff:: Buff(const char *data, size_t data_len, size_t current_idx) { 36 | bdata = data; 37 | bdata_len = data_len; 38 | bcurrent_idx = current_idx; 39 | } 40 | 41 | void Buff::setup(const char *data, size_t data_len, size_t current_idx) { 42 | bdata = data; 43 | bdata_len = data_len; 44 | bcurrent_idx = current_idx; 45 | } 46 | 47 | const char *Buff::read(size_t len) { 48 | //cout << "read add " << bcurrent_idx << " " << len << "\n"; 49 | bcurrent_idx += len; 50 | return (bdata + (bcurrent_idx - len)); 51 | } 52 | 53 | const char *Buff::readat(size_t pos, size_t len) { 54 | return (bdata + (pos)); 55 | } 56 | 57 | const char *Buff::read_false(size_t len) { 58 | return (bdata + (bcurrent_idx)); 59 | } 60 | 61 | size_t Buff::get_current_idx() { 62 | return bcurrent_idx; 63 | } 64 | 65 | size_t Buff::get_end() { 66 | return bdata_len; 67 | } 68 | 69 | bool Buff::empty() { 70 | return bcurrent_idx == bdata_len; 71 | } 72 | 73 | int Buff::register_dynamic_offset(unsigned int *addr) { 74 | DynamicOffsets.push_back( addr ); 75 | } 76 | 77 | int Buff::set_idx(unsigned int idx) { 78 | bcurrent_idx = idx; 79 | } 80 | 81 | unsigned char Buff::read_uc() { 82 | return *( reinterpret_cast( const_cast(this->read(1))) ); 83 | } 84 | 85 | char Buff::read_c() { 86 | return *( reinterpret_cast( const_cast(this->read(1))) ); 87 | } 88 | 89 | unsigned long Buff::read_ul() { 90 | return *( reinterpret_cast( const_cast(this->read(4))) ); 91 | } 92 | 93 | unsigned int Buff::read_ui() { 94 | return *( reinterpret_cast( const_cast(this->read(4))) ); 95 | } 96 | 97 | unsigned short Buff::read_us() { 98 | return *( reinterpret_cast( const_cast(this->read(2))) ); 99 | } 100 | -------------------------------------------------------------------------------- /androguard/core/bytecodes/libdvm/buff.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Androguard. 3 | 4 | Copyright (C) 2011, Anthony Desnos 5 | All rights reserved. 6 | 7 | Androguard is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU Lesser General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | Androguard is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public License 18 | along with Androguard. If not, see . 19 | */ 20 | #ifndef BUFF_H 21 | #define BUFF_H 22 | 23 | #ifdef __cplusplus 24 | 25 | #if defined __GNUC__ || defined __APPLE__ 26 | #include 27 | #else 28 | #include 29 | #endif 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | using namespace __gnu_cxx; 36 | using namespace std; 37 | using std::cout; 38 | using std::endl; 39 | 40 | class Buff { 41 | public : 42 | const char *bdata; 43 | size_t bdata_len; 44 | size_t bcurrent_idx; 45 | 46 | vector DynamicOffsets; 47 | public : 48 | Buff(); 49 | Buff(const char *data, size_t data_len); 50 | Buff(const char *data, size_t data_len, size_t current_idx); 51 | void setup(const char *data, size_t data_len, size_t current_idx); 52 | const char *read(size_t len); 53 | const char *readat(size_t pos, size_t len); 54 | const char *read_false(size_t len); 55 | size_t get_current_idx(); 56 | size_t get_end(); 57 | bool empty(); 58 | int register_dynamic_offset(unsigned int *addr); 59 | int set_idx(unsigned int); 60 | unsigned char read_uc(); 61 | char read_c(); 62 | unsigned long read_ul(); 63 | unsigned int read_ui(); 64 | unsigned short read_us(); 65 | }; 66 | 67 | #endif 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /androguard/core/bytecodes/libdvm/dvm.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Androguard. 3 | 4 | Copyright (C) 2011, Anthony Desnos 5 | All rights reserved. 6 | 7 | Androguard is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU Lesser General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | Androguard is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public License 18 | along with Androguard. If not, see . 19 | */ 20 | #ifndef DVM_H 21 | #define DVM_H 22 | 23 | #include 24 | 25 | #ifdef __cplusplus 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #if defined __GNUC__ || defined __APPLE__ 32 | #include 33 | #else 34 | #include 35 | #endif 36 | 37 | #include "buff.h" 38 | 39 | #define OPVALUE 0 40 | #define REGISTER 1 41 | #define FIELD 2 42 | #define METHOD 3 43 | #define TYPE 4 44 | #define INTEGER 5 45 | #define STRING 6 46 | #define INTEGER_BRANCH 7 47 | 48 | 49 | //#define DEBUG_DESTRUCTOR 50 | #undef DEBUG_DESTRUCTOR 51 | 52 | using namespace __gnu_cxx; 53 | using namespace std; 54 | using std::cout; 55 | using std::endl; 56 | 57 | typedef struct fillarraydata { 58 | unsigned short ident; 59 | unsigned short element_width; 60 | unsigned int size; 61 | } fillarraydata_t; 62 | 63 | typedef struct sparseswitch { 64 | unsigned short ident; 65 | unsigned short size; 66 | } sparseswitch_t; 67 | 68 | typedef struct packedswitch { 69 | unsigned short ident; 70 | unsigned short size; 71 | unsigned int first_key; 72 | } packedswitch_t; 73 | 74 | class DBC { 75 | public : 76 | unsigned char op_value; 77 | const char *op_name; 78 | size_t op_length; 79 | vector *voperands; 80 | vector *vdescoperands; 81 | vector *vstrings; 82 | 83 | public : 84 | DBC(unsigned char value, const char *name, vector *v, vector *vdesc, size_t length); 85 | ~DBC(); 86 | int get_opvalue(); 87 | const char *get_opname(); 88 | size_t get_length(); 89 | }; 90 | 91 | class DBCSpe { 92 | public : 93 | virtual const char *get_opname()=0; 94 | virtual size_t get_length()=0; 95 | virtual size_t get_type()=0; 96 | }; 97 | 98 | class FillArrayData : public DBCSpe { 99 | public : 100 | fillarraydata_t fadt; 101 | char *data; 102 | size_t data_size; 103 | public : 104 | FillArrayData(Buff *b, unsigned int off); 105 | ~FillArrayData(); 106 | const char *get_opname(); 107 | size_t get_length(); 108 | size_t get_type(); 109 | }; 110 | 111 | class SparseSwitch : public DBCSpe { 112 | public : 113 | sparseswitch_t sst; 114 | vector keys; 115 | vector targets; 116 | 117 | public : 118 | SparseSwitch(Buff *b, unsigned int off); 119 | ~SparseSwitch(); 120 | const char *get_opname(); 121 | size_t get_length(); 122 | size_t get_type(); 123 | }; 124 | 125 | class PackedSwitch : public DBCSpe { 126 | public : 127 | packedswitch_t pst; 128 | vector targets; 129 | 130 | public : 131 | PackedSwitch(Buff *b, unsigned int off); 132 | ~PackedSwitch(); 133 | const char *get_opname(); 134 | size_t get_length(); 135 | size_t get_type(); 136 | }; 137 | 138 | class DCode { 139 | public : 140 | vector bytecodes; 141 | vector bytecodes_spe; 142 | 143 | public : 144 | DCode(); 145 | ~DCode(); 146 | DCode(vector*, vector*)> *parsebytecodes, 147 | vector *, vector *, vector *, unsigned int *)> *postbytecodes, 148 | vector *bytecodes_names, 149 | Buff *b); 150 | int size(); 151 | DBC *get_bytecode_at(int i); 152 | }; 153 | 154 | class DalvikBytecode { 155 | public : 156 | vector*, vector*)> bytecodes; 157 | vector *, vector *, vector *, unsigned int *)> postbytecodes; 158 | 159 | vector bytecodes_names; 160 | 161 | public : 162 | DalvikBytecode(); 163 | DCode *new_code(const char *data, size_t data_len); 164 | }; 165 | 166 | typedef struct { 167 | PyObject_HEAD; 168 | DBC *d; 169 | PyObject *operands; 170 | } dvm_DBCObject; 171 | 172 | PyObject *DBC_new(PyTypeObject *type, PyObject *args, PyObject *kwds); 173 | void DBC_dealloc(dvm_DBCObject* self); 174 | PyObject *DBC_new(PyTypeObject *type, PyObject *args, PyObject *kwds); 175 | int DBC_init(dvm_DBCObject *self, PyObject *args, PyObject *kwds); 176 | PyObject *DBC_get_opvalue(dvm_DBCObject *self, PyObject* args); 177 | PyObject *DBC_get_length(dvm_DBCObject *self, PyObject* args); 178 | PyObject *DBC_get_name(dvm_DBCObject *self, PyObject* args); 179 | PyObject *DBC_get_operands(dvm_DBCObject *self, PyObject* args); 180 | PyObject *DBC_get_type_ins(dvm_DBCObject *self, PyObject* args); 181 | 182 | static PyMethodDef DBC_methods[] = { 183 | {"get_op_value", (PyCFunction)DBC_get_opvalue, METH_NOARGS, "get nb bytecodes" }, 184 | {"get_length", (PyCFunction)DBC_get_length, METH_NOARGS, "get nb bytecodes" }, 185 | {"get_name", (PyCFunction)DBC_get_name, METH_NOARGS, "get nb bytecodes" }, 186 | {"get_operands", (PyCFunction)DBC_get_operands, METH_NOARGS, "get nb bytecodes" }, 187 | {"get_type_ins", (PyCFunction)DBC_get_type_ins, METH_NOARGS, "get type ins" }, 188 | {NULL, NULL, 0, NULL} /* Sentinel */ 189 | }; 190 | 191 | static PyTypeObject dvm_DBCType = { 192 | PyObject_HEAD_INIT(NULL) 193 | 0, /*ob_size*/ 194 | "dvm.DBC", /*tp_name*/ 195 | sizeof(dvm_DBCObject), /*tp_basicsize*/ 196 | 0, /*tp_itemsize*/ 197 | (destructor)DBC_dealloc, /*tp_dealloc*/ 198 | 0, /*tp_print*/ 199 | 0, /*tp_getattr*/ 200 | 0, /*tp_setattr*/ 201 | 0, /*tp_compare*/ 202 | 0, /*tp_repr*/ 203 | 0, /*tp_as_number*/ 204 | 0, /*tp_as_sequence*/ 205 | 0, /*tp_as_mapping*/ 206 | 0, /*tp_hash */ 207 | 0, /*tp_call*/ 208 | 0, /*tp_str*/ 209 | 0, /*tp_getattro*/ 210 | 0, /*tp_setattro*/ 211 | 0, /*tp_as_buffer*/ 212 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ 213 | "DBC objects", /* tp_doc */ 214 | 0, /* tp_traverse */ 215 | 0, /* tp_clear */ 216 | 0, /* tp_richcompare */ 217 | 0, /* tp_weaklistoffset */ 218 | 0, /* tp_iter */ 219 | 0, /* tp_iternext */ 220 | DBC_methods, /* tp_methods */ 221 | NULL, /* tp_members */ 222 | NULL, /* tp_getset */ 223 | 0, /* tp_base */ 224 | 0, /* tp_dict */ 225 | 0, /* tp_descr_get */ 226 | 0, /* tp_descr_set */ 227 | 0, /* tp_dictoffset */ 228 | (initproc)DBC_init, /* tp_init */ 229 | 0, /* tp_alloc */ 230 | DBC_new, /* tp_new */ 231 | }; 232 | 233 | typedef struct { 234 | PyObject_HEAD; 235 | DBCSpe *d; 236 | } dvm_DBCSpeObject; 237 | 238 | void DBCSpe_dealloc(dvm_DBCSpeObject* self); 239 | PyObject *DBCSpe_new(PyTypeObject *type, PyObject *args, PyObject *kwds); 240 | int DBCSpe_init(dvm_DBCSpeObject *self, PyObject *args, PyObject *kwds); 241 | PyObject *DBCSpe_get_opvalue(dvm_DBCSpeObject *self, PyObject* args); 242 | PyObject *DBCSpe_get_name(dvm_DBCSpeObject *self, PyObject* args); 243 | PyObject *DBCSpe_get_operands(dvm_DBCSpeObject *self, PyObject* args); 244 | PyObject *DBCSpe_get_targets(dvm_DBCSpeObject *self, PyObject* args); 245 | PyObject *DBCSpe_get_length(dvm_DBCSpeObject *self, PyObject* args); 246 | PyObject *DBCSpe_get_type_ins(dvm_DBCSpeObject *self, PyObject* args); 247 | 248 | static PyMethodDef DBCSpe_methods[] = { 249 | {"get_name", (PyCFunction)DBCSpe_get_name, METH_NOARGS, "get nb bytecodes" }, 250 | {"get_op_value", (PyCFunction)DBCSpe_get_opvalue, METH_NOARGS, "get nb bytecodes" }, 251 | {"get_operands", (PyCFunction)DBCSpe_get_operands, METH_NOARGS, "get nb bytecodes" }, 252 | {"get_targets", (PyCFunction)DBCSpe_get_targets, METH_NOARGS, "get nb bytecodes" }, 253 | {"get_length", (PyCFunction)DBCSpe_get_length, METH_NOARGS, "get nb bytecodes" }, 254 | {"get_type_ins", (PyCFunction)DBCSpe_get_type_ins, METH_NOARGS, "get type ins" }, 255 | {NULL, NULL, 0, NULL} /* Sentinel */ 256 | }; 257 | 258 | static PyTypeObject dvm_DBCSpeType = { 259 | PyObject_HEAD_INIT(NULL) 260 | 0, /*ob_size*/ 261 | "dvm.DBCSpe", /*tp_name*/ 262 | sizeof(dvm_DBCSpeObject), /*tp_basicsize*/ 263 | 0, /*tp_itemsize*/ 264 | (destructor)DBCSpe_dealloc, /*tp_dealloc*/ 265 | 0, /*tp_print*/ 266 | 0, /*tp_getattr*/ 267 | 0, /*tp_setattr*/ 268 | 0, /*tp_compare*/ 269 | 0, /*tp_repr*/ 270 | 0, /*tp_as_number*/ 271 | 0, /*tp_as_sequence*/ 272 | 0, /*tp_as_mapping*/ 273 | 0, /*tp_hash */ 274 | 0, /*tp_call*/ 275 | 0, /*tp_str*/ 276 | 0, /*tp_getattro*/ 277 | 0, /*tp_setattro*/ 278 | 0, /*tp_as_buffer*/ 279 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ 280 | "DBC objects", /* tp_doc */ 281 | 0, /* tp_traverse */ 282 | 0, /* tp_clear */ 283 | 0, /* tp_richcompare */ 284 | 0, /* tp_weaklistoffset */ 285 | 0, /* tp_iter */ 286 | 0, /* tp_iternext */ 287 | DBCSpe_methods, /* tp_methods */ 288 | NULL, /* tp_members */ 289 | NULL, /* tp_getset */ 290 | 0, /* tp_base */ 291 | 0, /* tp_dict */ 292 | 0, /* tp_descr_get */ 293 | 0, /* tp_descr_set */ 294 | 0, /* tp_dictoffset */ 295 | (initproc)DBCSpe_init, /* tp_init */ 296 | 0, /* tp_alloc */ 297 | DBCSpe_new, /* tp_new */ 298 | }; 299 | 300 | 301 | #endif 302 | #endif 303 | -------------------------------------------------------------------------------- /androguard/core/bytecodes/libdvm/test_dvm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Androguard. 4 | # 5 | # Copyright (C) 2011, Anthony Desnos 6 | # All rights reserved. 7 | # 8 | # Androguard is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Lesser General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # Androguard is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public License 19 | # along with Androguard. If not, see . 20 | 21 | import sys, itertools, time, os, random 22 | from ctypes import cdll, c_float, c_int, c_uint, c_void_p, Structure, addressof, create_string_buffer, cast, POINTER, pointer 23 | from struct import pack, unpack, calcsize 24 | 25 | PATH_INSTALL = "../../../" 26 | sys.path.append(PATH_INSTALL + "./") 27 | sys.path.append(PATH_INSTALL + "./core") 28 | sys.path.append(PATH_INSTALL + "./core/bytecodes") 29 | sys.path.append(PATH_INSTALL + "./core/analysis") 30 | 31 | import apk, dvm, analysis, msign 32 | 33 | if __name__ == "__main__": 34 | # a = apk.APK( PATH_INSTALL + "examples/android/TestsAndroguard/bin/TestsAndroguard.apk" ) 35 | # a = apk.APK( PATH_INSTALL + "apks/drweb-600-android-beta.apk" ) 36 | # a = apk.APK( PATH_INSTALL + "debug/062d5e38dc4618a8b1c6bf3587dc2016a3a3db146aea0d82cc227a18ca21ad13") 37 | a = apk.APK(PATH_INSTALL + "apks/malwares/kungfu/sample2.apk") 38 | 39 | t1 = time.time() 40 | 41 | if len(sys.argv) > 1: 42 | d = dvm.DalvikVMFormat(a.get_dex(), engine=["python"]) 43 | else: 44 | d = dvm.DalvikVMFormat(a.get_dex()) 45 | 46 | t2 = time.time() 47 | x = analysis.VMAnalysis(d) 48 | 49 | t3 = time.time() 50 | print '-> %0.8f %0.8f %0.8f' % ((t2 - t1, t3 - t2, t3 - t1)) 51 | 52 | sys.exit(0) 53 | 54 | for method in d.get_methods(): 55 | print method.get_class_name(), method.get_name(), method.get_descriptor() 56 | 57 | code = method.get_code() 58 | if code == None: 59 | continue 60 | 61 | bc = code.get_bc() 62 | 63 | idx = 0 64 | for i in bc.get(): 65 | print "\t", "%x" % idx, i.get_op_value(), i.get_name(), i.get_operands()#, i.get_formatted_operands() 66 | idx += i.get_length() 67 | 68 | sys.exit(0) 69 | -------------------------------------------------------------------------------- /androguard/core/data/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/androguard/core/data/__init__.py -------------------------------------------------------------------------------- /androguard/core/data/data.py: -------------------------------------------------------------------------------- 1 | # This file is part of Androguard. 2 | # 3 | # Copyright (C) 2012, Anthony Desnos 4 | # All rights reserved. 5 | # 6 | # Androguard is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU Lesser General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # Androguard is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU Lesser General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU Lesser General Public License 17 | # along with Androguard. If not, see . 18 | 19 | import os 20 | from xml.sax.saxutils import escape 21 | 22 | from networkx import DiGraph 23 | from CheckProtect.androguard.core.analysis import analysis 24 | 25 | 26 | try: 27 | from CheckProtect.androguard.core.analysis.libsign.libsign import entropy 28 | except ImportError: 29 | import math 30 | 31 | def entropy(data): 32 | entropy = 0 33 | 34 | if len(data) == 0: 35 | return entropy 36 | 37 | for x in range(256): 38 | p_x = float(data.count(chr(x))) / len(data) 39 | if p_x > 0: 40 | entropy += - p_x * math.log(p_x, 2) 41 | return entropy 42 | 43 | DEFAULT_SIGNATURE = analysis.SIGNATURE_L0_4 44 | 45 | 46 | def create_entropies(vmx, m): 47 | try: 48 | default_signature = vmx.get_method_signature(m, predef_sign=DEFAULT_SIGNATURE).get_string() 49 | l = [default_signature, 50 | entropy(vmx.get_method_signature(m, "L4", {"L4": {"arguments": ["Landroid"]}}).get_string()), 51 | entropy(vmx.get_method_signature(m, "L4", {"L4": {"arguments": ["Ljava"]}}).get_string()), 52 | entropy(vmx.get_method_signature(m, "hex").get_string()), 53 | entropy(vmx.get_method_signature(m, "L2").get_string()), 54 | ] 55 | return l 56 | except KeyError: 57 | return ["", 0.0, 0.0, 0.0, 0.0] 58 | 59 | 60 | def create_info(vmx, m): 61 | E = create_entropies(vmx, m) 62 | 63 | H = {} 64 | H["signature"] = E[0] 65 | H["signature_entropy"] = entropy(E[0]) 66 | H["android_api_entropy"] = E[1] 67 | H["java_api_entropy"] = E[2] 68 | H["hex_entropy"] = E[3] 69 | H["exceptions_entropy"] = E[4] 70 | 71 | return H 72 | 73 | 74 | class Data: 75 | def __init__(self, vm, vmx, gvmx, a=None): 76 | self.vm = vm 77 | self.vmx = vmx 78 | self.gvmx = gvmx 79 | self.a = a 80 | 81 | self.apk_data = None 82 | self.dex_data = None 83 | 84 | if self.a != None: 85 | self.apk_data = ApkViewer(self.a) 86 | 87 | self.dex_data = DexViewer(vm, vmx, gvmx) 88 | 89 | self.gvmx.set_new_attributes(create_info) 90 | self.export_methods_to_gml() 91 | 92 | def export_methodcalls_to_gml(self): 93 | return self.gvmx.export_to_gml() 94 | 95 | def export_methods_to_gml(self): 96 | print self.gvmx.G 97 | 98 | for node in self.gvmx.G.nodes(): 99 | print self.gvmx.nodes_id[node].method_name, self.gvmx.nodes_id[node].get_attributes() 100 | 101 | def export_apk_to_gml(self): 102 | if self.apk_data != None: 103 | return self.apk_data.export_to_gml() 104 | 105 | def export_dex_to_gml(self): 106 | if self.dex_data != None: 107 | return self.dex_data.export_to_gml() 108 | 109 | 110 | class DexViewer: 111 | def __init__(self, vm, vmx, gvmx): 112 | self.vm = vm 113 | self.vmx = vmx 114 | self.gvmx = gvmx 115 | 116 | 117 | def _create_node(self, id, height, width, color, label): 118 | buff = "\n" % id 119 | buff += "\n" 120 | buff += "\n" 121 | 122 | buff += "\n" % (16 * height, 7.5 * width) 123 | buff += "\n" % color 124 | 125 | buff += "\n" 126 | 127 | buff += escape(label) 128 | 129 | buff += "\n" 130 | buff += "\n" 131 | buff += "\n" 132 | 133 | buff += "\n" 134 | 135 | return buff 136 | 137 | def add_exception_node(self, exception, id_i): 138 | buff = "" 139 | # 9933FF 140 | height = 2 141 | width = 0 142 | label = "" 143 | 144 | label += "%x:%x\n" % (exception.start, exception.end) 145 | for i in exception.exceptions: 146 | c_label = "\t(%s -> %x %s)\n" % (i[0], i[1], i[2].get_name()) 147 | label += c_label 148 | 149 | width = max(len(c_label), width) 150 | height += 1 151 | 152 | return self._create_node(id_i, height, width, "9333FF", label) 153 | 154 | def add_method_node(self, i, id_i): 155 | height = 0 156 | width = 0 157 | label = "" 158 | 159 | label += i.get_name() + "\n" 160 | label += i.get_descriptor() 161 | 162 | height = 3 163 | width = len(label) 164 | 165 | return self._create_node(id_i, height, width, "FF0000", label) 166 | 167 | def add_node(self, i, id_i): 168 | height = 0 169 | width = 0 170 | idx = i.start 171 | label = "" 172 | for ins in i.ins: 173 | c_label = "%x %s\n" % (idx, self.vm.dotbuff(ins, idx)) 174 | idx += ins.get_length() 175 | label += c_label 176 | width = max(width, len(c_label)) 177 | height += 1 178 | 179 | if height < 10: 180 | height += 3 181 | 182 | return self._create_node(id_i, height, width, "FFCC00", label) 183 | 184 | def add_edge(self, i, id_i, j, id_j, l_eid, val): 185 | buff = "\n" % (len(l_eid), id_i, id_j) 186 | 187 | buff += "\n" 188 | buff += "\n" 189 | buff += "\n" 190 | 191 | if val == 0: 192 | buff += "\n" 193 | elif val == 1: 194 | buff += "\n" 195 | else: 196 | buff += "\n" 197 | 198 | buff += "\n" 199 | buff += "\n" 200 | 201 | buff += "\n" 202 | 203 | l_eid["%d+%d" % (id_i, id_j)] = len(l_eid) 204 | return buff 205 | 206 | def new_id(self, i, l): 207 | try: 208 | return l[i] 209 | except KeyError: 210 | l[i] = len(l) 211 | return l[i] 212 | 213 | def export_to_gml(self): 214 | H = {} 215 | 216 | for _class in self.vm.get_classes(): 217 | name = _class.get_name() 218 | name = name[1:-1] 219 | 220 | buff = "" 221 | 222 | buff += "\n" 223 | buff += "\n" 224 | 225 | buff += "\n" 226 | buff += "\n" 227 | buff += "\n" 228 | 229 | buff += "\n" 230 | 231 | print name 232 | 233 | buff_nodes = "" 234 | buff_edges = "" 235 | l_id = {} 236 | l_eid = {} 237 | 238 | for method in _class.get_methods(): 239 | mx = self.vmx.get_method(method) 240 | exceptions = mx.exceptions 241 | 242 | id_method = self.new_id(method, l_id) 243 | buff_nodes += self.add_method_node(method, id_method) 244 | 245 | for i in mx.basic_blocks.get(): 246 | 247 | id_i = self.new_id(i, l_id) 248 | print i, id_i, i.exception_analysis 249 | 250 | buff_nodes += self.add_node(i, id_i) 251 | 252 | # add childs nodes 253 | val = 0 254 | if len(i.childs) > 1: 255 | val = 1 256 | elif len(i.childs) == 1: 257 | val = 2 258 | 259 | for j in i.childs: 260 | print "\t", j 261 | 262 | id_j = self.new_id(j[-1], l_id) 263 | buff_edges += self.add_edge(i, id_i, j[-1], id_j, l_eid, val) 264 | if val == 1: 265 | val = 0 266 | 267 | # add exceptions node 268 | if i.exception_analysis != None: 269 | id_exceptions = self.new_id(i.exception_analysis, l_id) 270 | buff_nodes += self.add_exception_node(i.exception_analysis, id_exceptions) 271 | buff_edges += self.add_edge(None, id_exceptions, None, id_i, l_eid, 2) 272 | 273 | buff_edges += self.add_edge(None, id_method, None, id_method + 1, l_eid, 2) 274 | 275 | buff += buff_nodes 276 | buff += buff_edges 277 | 278 | buff += "\n" 279 | buff += "\n" 280 | 281 | H[name] = buff 282 | return H 283 | 284 | 285 | class Directory: 286 | def __init__(self, name): 287 | self.name = name 288 | self.basename = os.path.basename(name) 289 | self.color = "FF0000" 290 | 291 | self.width = len(self.name) 292 | 293 | def set_color(self, color): 294 | self.color = color 295 | 296 | 297 | class File: 298 | def __init__(self, name, file_type, file_crc): 299 | self.name = name 300 | self.basename = os.path.basename(name) 301 | self.file_type = file_type 302 | self.file_crc = file_crc 303 | 304 | self.color = "FFCC00" 305 | 306 | self.width = max(len(self.name), len(self.file_type)) 307 | 308 | 309 | def splitall(path, z): 310 | if len(path) == 0: 311 | return 312 | 313 | l = os.path.split(path) 314 | z.append(l[0]) 315 | 316 | for i in l: 317 | return splitall(i, z) 318 | 319 | 320 | class ApkViewer: 321 | def __init__(self, a): 322 | self.a = a 323 | 324 | self.G = DiGraph() 325 | self.all_files = {} 326 | self.ids = {} 327 | 328 | root = Directory("APK") 329 | root.set_color("00FF00") 330 | 331 | self.ids[root] = len(self.ids) 332 | self.G.add_node(root) 333 | 334 | for x, y, z in self.a.get_files_information(): 335 | print x, y, z, os.path.basename(x) 336 | 337 | l = [] 338 | splitall(x, l) 339 | l.reverse() 340 | l.pop(0) 341 | 342 | last = root 343 | for i in l: 344 | if i not in self.all_files: 345 | tmp = Directory(i) 346 | self.ids[tmp] = len(self.ids) 347 | self.all_files[i] = tmp 348 | else: 349 | tmp = self.all_files[i] 350 | 351 | self.G.add_edge(last, tmp) 352 | last = tmp 353 | 354 | n1 = last 355 | n2 = File(x, y, z) 356 | self.G.add_edge(n1, n2) 357 | 358 | self.ids[n2] = len(self.ids) 359 | 360 | def export_to_gml(self): 361 | buff = "\n" 362 | buff += "\n" 363 | 364 | buff += "\n" 365 | buff += "\n" 366 | 367 | buff += "\n" 368 | 369 | for node in self.G.nodes(): 370 | print node 371 | 372 | buff += "\n" % self.ids[node] 373 | buff += "\n" 374 | buff += "\n" 375 | 376 | buff += "\n" % (60.0, 7 * node.width) 377 | buff += "\n" % node.color 378 | 379 | buff += "\n" 380 | buff += "%s\n" % node.basename 381 | 382 | if isinstance(node, File): 383 | buff += "%s\n" % node.file_type 384 | buff += "%s\n" % hex(node.file_crc) 385 | 386 | buff += "\n" 387 | 388 | buff += "\n" 389 | buff += "\n" 390 | 391 | buff += "\n" 392 | 393 | nb = 0 394 | for edge in self.G.edges(): 395 | buff += "\n" % (nb, self.ids[edge[0]], self.ids[edge[1]]) 396 | buff += "\n" 397 | nb += 1 398 | 399 | buff += "\n" 400 | buff += "\n" 401 | 402 | return buff 403 | -------------------------------------------------------------------------------- /core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/core/__init__.py -------------------------------------------------------------------------------- /core/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/core/__init__.pyc -------------------------------------------------------------------------------- /core/chilkatCert/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/core/chilkatCert/__init__.py -------------------------------------------------------------------------------- /core/chilkatCert/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/core/chilkatCert/__init__.pyc -------------------------------------------------------------------------------- /core/chilkatCert/mac/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/core/chilkatCert/mac/__init__.py -------------------------------------------------------------------------------- /core/chilkatCert/mac/_chilkat.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/core/chilkatCert/mac/_chilkat.so -------------------------------------------------------------------------------- /core/chilkatCert/win32/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/core/chilkatCert/win32/__init__.py -------------------------------------------------------------------------------- /core/chilkatCert/win32/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/core/chilkatCert/win32/__init__.pyc -------------------------------------------------------------------------------- /core/chilkatCert/win32/_chilkat.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/core/chilkatCert/win32/_chilkat.pyd -------------------------------------------------------------------------------- /core/chilkatCert/win32/chilkat.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/core/chilkatCert/win32/chilkat.pyc -------------------------------------------------------------------------------- /core/chilkatCert/win64/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/core/chilkatCert/win64/__init__.py -------------------------------------------------------------------------------- /core/chilkatCert/win64/_chilkat.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/core/chilkatCert/win64/_chilkat.pyd -------------------------------------------------------------------------------- /core/extraTools.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | from sys import argv 3 | from os import path, walk 4 | from platform import system 5 | 6 | SYS = system() 7 | 8 | 9 | class myTools(): 10 | extraLib = path.join(path.split(argv[0])[0], 'ExtraLib') 11 | 12 | def __int__(self, extraLib): 13 | self.extraLib = extraLib 14 | 15 | def getFile(self, OPT): 16 | for parent, dirNames, fileNames in walk(self.extraLib): 17 | for fileName in fileNames: 18 | if fileName == OPT: 19 | return path.join(parent, fileName) 20 | 21 | #def cert(self): 22 | # return self.getFile('cert.jar') 23 | # 24 | #def certSN(self): 25 | # return self.getFile('certSN.jar') 26 | # 27 | #def certIDN(self): 28 | # return self.getFile('certIDN.jar') 29 | # 30 | #def certSDN(self): 31 | # return self.getFile('certSDN.jar') 32 | 33 | def apkTool(self): 34 | return self.getFile('apktool.jar') 35 | 36 | def dex2jar(self): 37 | if SYS == "Darwin": 38 | return self.getFile('dex2jar.sh') 39 | if SYS == "Windows": 40 | return self.getFile('dex2jar.bat') 41 | 42 | def jdGui(self): 43 | if SYS == "Darwin": 44 | return self.getFile('jd-gui') 45 | if SYS == "Windows": 46 | return self.getFile('jd-gui.exe') 47 | 48 | def smali(self): 49 | return self.getFile('smali.jar') 50 | 51 | def baksmali(self): 52 | return self.getFile('baksmali.jar') 53 | 54 | def SSS(self): 55 | return self.getFile('SimpleShellSystem.jar') 56 | 57 | def parser(self): 58 | return self.getFile('parser.js') 59 | 60 | #def temp(self): 61 | # return path.join(path.split(argv[0])[0], 'temp') -------------------------------------------------------------------------------- /tool/7z.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/tool/7z.dll -------------------------------------------------------------------------------- /tool/7z.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/tool/7z.exe -------------------------------------------------------------------------------- /tool/AXMLPrinter2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/tool/AXMLPrinter2.jar -------------------------------------------------------------------------------- /tool/baksmali.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/tool/baksmali.jar -------------------------------------------------------------------------------- /tool/dexdump: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/tool/dexdump -------------------------------------------------------------------------------- /tool/dexdump.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/tool/dexdump.exe -------------------------------------------------------------------------------- /tool/libeay32.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/tool/libeay32.dll -------------------------------------------------------------------------------- /tool/openssl.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/tool/openssl.exe -------------------------------------------------------------------------------- /tool/smaliParserX.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/tool/smaliParserX.jar -------------------------------------------------------------------------------- /tool/ssleay32.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/tool/ssleay32.dll -------------------------------------------------------------------------------- /tool/wget.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aylhex/ApkDetecter/47b2c2db8f946d848fdd92ebbe75e3a21d60b204/tool/wget.exe --------------------------------------------------------------------------------