diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1fa8dbf --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.pyc +*~ +#*# \ No newline at end of file diff --git a/AnalysisCSN/CSN.py b/AnalysisCSN/CSN.py index 369790f..a419ad2 100644 --- a/AnalysisCSN/CSN.py +++ b/AnalysisCSN/CSN.py @@ -3,7 +3,16 @@ import os from hashlib import md5, sha1, sha256 from base64 import b64encode -from core.chilkatCert.win32 import chilkat +from platform import system, architecture + +SYS = system() +if SYS == "Darwin": + from core.chilkatCert.mac import chilkat +if SYS == "Windows": + if architecture()[0] == "32bit": + from core.chilkatCert.win32 import chilkat + elif architecture()[0] == "64bit": + from core.chilkatCert.win64 import chilkat BLACK_LIST_CSN = [ ('936eacbe07f201df', 'Google测试证书(打包党)'), diff --git a/ApkDetecter.py b/ApkDetecter.py index 6344c02..c470af6 100644 --- a/ApkDetecter.py +++ b/ApkDetecter.py @@ -8,6 +8,7 @@ import hashlib import thread import shutil +import subprocess from PyQt4 import QtCore, QtGui from AnalysisXML.AXML import AXML from DexInfo import DexInfoForm @@ -16,7 +17,7 @@ from CheckProtect import CheckProtect from AnalysisCSN.CSN import CSN from GUI.apkdetecter_ui import Ui_APKDetecter - +from platform import system @@ -27,8 +28,7 @@ def __init__(self, parent = None): self._want_to_close = True self.dexheader = {} self.loadfile_path = "" - #self.unpackDir = tempfile.mktemp() - self.unpackDir = ur"d:\APK" + self.unpackDir = tempfile.mkdtemp() self.ui = Ui_APKDetecter() self.ui.setupUi(self) @@ -37,9 +37,19 @@ def __init__(self, parent = None): self.ui.apk_info.clicked.connect(self.apkinfo_dialog) self.ui.extend_info.clicked.connect(self.extendinfo_dialog) + self.apkinfo = None + self.dexinfo = None + def closeEvent(self, evnt): if self._want_to_close: super(ApkDetecterForm, self).closeEvent(evnt) + + # Clean up UI if present + if self.apkinfo and self.apkinfo.isVisible(): + self.apkinfo.close() + if self.dexinfo and self.dexinfo.isVisible(): + self.dexinfo.close() + self.clearfiles(self.unpackDir) print "Andy" @@ -53,11 +63,21 @@ def probar_thread(self, no, interval): def unzip(self, apkpath): apkpath = unicode(apkpath, "utf8") - cmd = "tool\\7z.exe x %s -y -o%s *.dex AndroidManifest.xml lib META-INF assets" - print cmd % (apkpath, self.unpackDir) + + path7zip = "" + # This all should likely just become python code, however + # in the mean time, attempt to find 7zip via a `which` command + # on non-Windows environments + if system() == "Windows": + path7zip = "tool\\7z.exe" + else: + path7zip = subprocess.check_output(["which","7za"]).rstrip() + + cmd = "%s x %s -y -o%s *.dex AndroidManifest.xml lib META-INF assets" + print cmd % (path7zip, apkpath, self.unpackDir) self.ui.progressBar.setMaximum(29) thread.start_new_thread(self.probar_thread, (3, 30)) - os.system(cmd % (apkpath, self.unpackDir)) + os.system(cmd % (path7zip, apkpath, self.unpackDir)) def Init_Main_text(self): @@ -166,12 +186,11 @@ def GetFileMd5(self, path): file.close() return strMd5 except: + # TODO: "Sorry, error calculating MD5!" return u"Sorry,计算出错!" - - def apkinfo_dialog(self): self.apkinfo = MyApkInfoForm() self.Init_Apkinfo_text() @@ -232,10 +251,9 @@ def apkinfo_dialog(self): self.apkinfo.ui.edt_version_num.setText(axml_analysis.get_androidversion_code()) self.apkinfo.ui.edt_version_need.setText(axml_analysis.getMinSdkVersion()) - - self.apkinfo.show() + def extendinfo_dialog(self): self.dexinfo = DexInfoForm() self.Init_DexInfo_text() @@ -269,7 +287,24 @@ def extendinfo_dialog(self): if __name__ == "__main__": + # Attempt to detect user Locale + locale = QtCore.QSettings().value("locale/userLocale").toString() + if not locale: + locale = 'en' + else: + locale = locale[0:2] + localePath = os.path.join(os.path.dirname(__file__), 'i18n/', + '{}.qm'.format(locale)) + app = QtGui.QApplication(sys.argv) + + if os.path.exists(localePath): + translator = QtCore.QTranslator() + if translator.load(localePath): + app.installTranslator(translator) + else: + print 'Failed to load translator - defaulting to zh!' + myapp = ApkDetecterForm() myapp.show() - sys.exit(app.exec_()) \ No newline at end of file + sys.exit(app.exec_()) diff --git a/CheckProtect.py b/CheckProtect.py index a745b2c..1ca1556 100644 --- a/CheckProtect.py +++ b/CheckProtect.py @@ -4,17 +4,36 @@ import os from UnzipAPK import UnzipAPK from AnalysisXML.AXML import AXML +from PyQt4 import QtGui +try: + _encoding = QtGui.QApplication.UnicodeUTF8 + def _translate(context, text, disambig): + return QtGui.QApplication.translate(context, text, disambig, _encoding) +except AttributeError: + def _translate(context, text, disambig): + return QtGui.QApplication.translate(context, text, disambig) + + class CheckProtect(): def __init__(self, apkPath): #self.apkPath = r"D:\original.apk" self.apkPath = apkPath self.protectflag = "" - self.protectflag_dict = {"libsecexe.so": u"该APK已加固=>梆梆加固", "libAPKProtect.so": u"该APK已加固=>APKProtect加固", - "libprotectClass.so": u"该APK已加固=>360加固", "libNSaferOnly.so": u"该APK已加固=>通付盾加固", - "libnqshield.so": u"该APK已加固=>网秦加固", "libshell.so": u"该APK已加固=>腾讯加固", - "ijiami.dat": u"该APK已加固=>爱加密加固", "libddog.so": u"该APK已加固=>娜迦加固", - "libmobisec.so": u"该APK已加固=>阿里加固", "libbaiduprotect.so": u"该APK已加固=>百度加固"} + self.protectflag_dict = { + "libsecexe.so": _translate("ProtectDictionary", "该APK已加固=>梆梆加固", None), + "libAPKProtect.so": _translate("ProtectDictionary", "该APK已加固=>梆梆加固(APKProtect)", None), + "libprotectClass.so": _translate("ProtectDictionary", "该APK已加固=>360加固", None), + "libNSaferOnly.so": _translate("ProtectDictionary", "该APK已加固=>通付盾加固", None), + "libnqshield.so": _translate("ProtectDictionary", "该APK已加固=>网秦加固", None), + "libshell.so": _translate("ProtectDictionary", "该APK已加固=>腾讯加固", None), + "ijiami.dat": _translate("ProtectDictionary", "该APK已加固=>腾讯加固(Ijiami)", None), + "libddog.so": _translate("ProtectDictionary", "该APK已加固=>娜迦加固", None), + "libmobisec.so": _translate("ProtectDictionary", "该APK已加固=>阿里加固", None), + "libbaiduprotect.so": _translate("ProtectDictionary", "该APK已加固=>百度加固", None), + "libmd.so": _translate("ProtectDictionary", "该APK已加固=>Medusa", None), + "LIAPPClient.sc": _translate("ProtectDictionary", "该APK已加固=>LIAPP", None) + } def getactivity(self, path): axml_analysis = AXML(path + os.path.sep +"AndroidManifest.xml") @@ -61,8 +80,8 @@ def check_protectflag(self): self.protectflag = self.protectflag + self.protectflag_dict[key] if file_name.has_key("key.dat") and all_dir_name.has_key("apkprotect.com"): - if self.protectflag == "" or (u"APKProtect加固" not in self.protectflag): - self.protectflag = self.protectflag + u"APKProtect加固" + if self.protectflag == "" or (_translate("ProtectDictionary", "APKProtect加固", None) not in self.protectflag): + self.protectflag = self.protectflag + _translate("ProtectDictionary", "APKProtect加固", None) if self.protectflag != "": return self.protectflag @@ -76,10 +95,10 @@ def check_protectflag(self): self.flag = 1 if self.protectflag == "" and self.flag == 1: - self.protectflag = u"疑似未知加密" + self.protectflag = _translate("ProtectDictionary", "疑似未知加密", None) if self.protectflag == "": - self.protectflag = u"该APK未加密" + self.protectflag = _translate("ProtectDictionary", "该APK未加密", None) return self.protectflag @@ -87,4 +106,4 @@ def check_protectflag(self): if __name__ == "__main__": obj = CheckProtect() - obj.check_protectflag() \ No newline at end of file + obj.check_protectflag() diff --git a/GUI/dexinfor_ui.py b/GUI/dexinfor_ui.py index 7f3a20f..511013b 100644 --- a/GUI/dexinfor_ui.py +++ b/GUI/dexinfor_ui.py @@ -44,7 +44,7 @@ def setupUi(self, DexInfo): self.groupBox.setFont(font) self.groupBox.setObjectName(_fromUtf8("groupBox")) self.lab_magic = QtGui.QLabel(self.groupBox) - self.lab_magic.setGeometry(QtCore.QRect(6, 20, 81, 16)) + self.lab_magic.setGeometry(QtCore.QRect(6, 20, 98, 16)) font = QtGui.QFont() font.setBold(True) font.setWeight(75) @@ -72,7 +72,7 @@ def setupUi(self, DexInfo): self.lab_header_size.setFont(font) self.lab_header_size.setObjectName(_fromUtf8("lab_header_size")) self.lab_endian_tag = QtGui.QLabel(self.groupBox) - self.lab_endian_tag.setGeometry(QtCore.QRect(6, 144, 71, 16)) + self.lab_endian_tag.setGeometry(QtCore.QRect(6, 144, 74, 16)) font = QtGui.QFont() font.setBold(True) font.setWeight(75) diff --git a/GUI/dexinfor_ui.ui b/GUI/dexinfor_ui.ui index b2cea4b..a44fcd7 100644 --- a/GUI/dexinfor_ui.ui +++ b/GUI/dexinfor_ui.ui @@ -60,7 +60,7 @@ 6 20 - 81 + 98 16 @@ -136,7 +136,7 @@ 6 144 - 71 + 74 16 diff --git a/README.md b/README.md index e3a857c..745d540 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,29 @@ -# ApkDetecter +ApkDetecter +=========== + android apk查壳工具源代码 -主要功能: -1、检测DEX文件是否加固及加固厂商 -2、检测APK的基本信息: - APKMD5值,APK包名,APK版本,签名信息等 -3、DEX文件的字节信息 +主要功能 : +---------- +1. 检测DEX文件是否加固及加固厂商 +2. 检测APK的基本信息: + 1. APKMD5值 + 2. APK包名 + 3. APK版本 + 4. 签名信息等 +3. DEX文件的字节信息 + +Translation +----------- + +Tool for providing Android APK protector detection with UI + +Main Features: +-------------- +1. Detect DEX file protectors, obfuscators +2. Detect APK basic information + 1. APK MD5 + 2. APK Package name + 3. APK version + 4. Signature informaton +3. Detailed information about the DEX file bytes \ No newline at end of file diff --git a/UnzipAPK.py b/UnzipAPK.py index dfb88b8..0502494 100644 --- a/UnzipAPK.py +++ b/UnzipAPK.py @@ -3,6 +3,8 @@ import os import struct import tempfile +import subprocess +from platform import system class UnzipAPK(): @@ -83,10 +85,16 @@ def unpackxml(self): def dexdump(self): - cmd = 'tool\\dexdump.exe -d %s > %s' + pathdexdump = "" + if system() == "Windows": + pathdexdump = "tool\\dexdump.exe" + else: + pathdexdump = subprocess.check_output(["which","dexdump"]).rstrip() + + cmd = '%s -d %s > %s' dexpath = os.path.join(self.unpackDir, "classes.dex") if os.path.exists(dexpath): - os.system(cmd % (dexpath, self.unpackDir + os.path.sep +"classes.txt")) + os.system(cmd % (pathdexdump, dexpath, self.unpackDir + os.path.sep +"classes.txt")) def getallname(self): @@ -104,4 +112,4 @@ def getallname(self): # if __name__ == "__main__": # apkPath = r"D:\original.apk" -# obj = UnzipAPK(apkPath) \ No newline at end of file +# obj = UnzipAPK(apkPath) diff --git a/i18n/en.qm b/i18n/en.qm new file mode 100644 index 0000000..b7c69fe Binary files /dev/null and b/i18n/en.qm differ diff --git a/i18n/en.ts b/i18n/en.ts new file mode 100644 index 0000000..b146618 --- /dev/null +++ b/i18n/en.ts @@ -0,0 +1,351 @@ + + + + + APKDetecter + + + APKDetecter + APKDetecter + + + + 文 件 + File + + + + 打 开 + Open + + + + DEX信息 + Dex Information + + + + 连接段大小 + Link Seg. Size + + + + DEX 标 识 + Dex Flags + + + + DEX头大小 + Header Size + + + + 连接段偏移 + Link Seg. Offset + + + + 文件大小 + File Size + + + + 字节序列 + Endian Tag + + + + 扩展信息 + Extra Info + + + + About + About + + + + ApkInfo + Apk Info + + + + ApkInfo + + + ApkInformation + ApkInformation + + + + 文件信息 + File Information + + + + 文件大小 + File Size + + + + 文件包名 + Package + + + + 版 本 + Version + + + + 版本号 + Version # + + + + 系统要求 + Min SDK + + + + 序列号 + Serial # + + + + 发 行 者 + Publisher + + + + 签 发 人 + Issuer + + + + APKMD5 + APK MD5 + + + + DEXMD5 + Dex MD5 + + + + DexInfo + + + DexInformation + DexInformation + + + + DexInfo + DexInfo + + + + Magic标识 + Magic Number + + + + 校验码 + Checksum + + + + DEX文件大小 + File Size + + + + 文件头长度 + Header Size + + + + 字节序标记 + Endian Tag + + + + 链接段大小 + Link Size + + + + 链接段基地址 + Link Offset + + + + Map数据基地址 + Map Offset + + + + 字符串列表的字符串数 + String IDs Size + + + + 字符串列表表基地址 + String IDs Offset + + + + 字段列表里字段数 + Field IDs Size + + + + 原型列表里原型数 + Proto IDs Size + + + + 方法列表里方法数 + Method IDs Size + + + + 字段列表基地址 + Data Size + + + + 方法列表基地址 + Proto Ids Offset + + + + 数据段的大小 + Method IDs Offset + + + + 原型列表基地址 + Data Size + + + + 类型列表基地址 + Type IDs Offset + + + + 类定义类表中类的数 + Class Defs Size + + + + 类定义列表基地址 + Class Defs Offset + + + + 类型列表中类型数 + Type IDs Size + + + + 数据段基地址 + Data Offset + + + + SHA-1签名 + File SHA1 + + + + ProtectDictionary + + + 该APK已加固=>梆梆加固 + APK is Packed => Bangcle/SecNeo + + + + 该APK已加固=>通付盾加固 + APK is Packed => Qihoo360 Packer + + + + 该APK已加固=>网秦加固 + APK is Packed => Pass Pay Shield Packer + + + + 该APK已加固=>腾讯加固 + APK is Packed => Netqin Packer + + + + 该APK已加固=>娜迦加固 + APK is Packed => Tencent Packer + + + + 该APK已加固=>阿里加固 + APK is Packed => Naga Packer + + + + 该APK已加固=>百度加固 + Apk is Packed => Alibaba Packer + + + + 该APK已加固=>梆梆加固(2) + APK is Packed => APKProtector + + + + 该APK已加固=>360加固 + APK is Packed => Baidu Packer + + + + 该APK已加固=>梆梆加固(APKProtect) + APK is Packed => APKProtector + + + + 该APK已加固=>腾讯加固(Ijimai) + APK is Packed => Ijiami + + + + 该APK已加固=>腾讯加固(Ijiami) + APK is Packed => Ijiami + + + + APKProtect加固 + APKProtected (potentially only with bad code injected) + + + + 疑似未知加密 + Potentially Unknown Protector Used + + + + 该APK未加密 + No Protections Detected + + + + 该APK已加固=>Medusa + APK is Packed => Medusa + + + + 该APK已加固=>LIAPP + APK is Packed => LIAPP + + +