内容简介:对 Dex 文件的局部(可以是头部、代码段等等)求MD5值,并将MD5写入dex文件的末尾或其他不影响dex文件加载运行的位置(本人暂时还没碰到)
一、静态完整性校验
1、对Dex文件进行完整性校验
由于 Android 稍高版本在安装 APK 的过程中会把 classes.dex 抠出来转化为odex或者 vdex 等其他格式的优化文件,原 APK 中无 classes.dex ,但是会存在除 classes.dex 外的其他多dex文件(比如 classes2.dex 、 classes3.dex 等),故 无法校验 classes.dex ,也无法校验整个 APK 文件哈希值。
通过读取 APK 包中的除 classes.dex 外的其他 dex 文件,并计算其 CRC 的值,将得到的 CRC 与原始 CRC 进行比较,判断是否被修改过,原始 CRC 值保存在资源文件或其他自定义文件中相关代码:
String apkPath=context.getPackageCodePath();//获取Apk的路径 ZipFile zipFile=new ZipFile(apkPath); ZipEntry dexEntry=ZipFile.getEntry("classes.dex");//读取zip包中的classes.dex文件 String dexCRC=dexEntry.getCrc().toString();//计算dex的CRC文件值
对 Dex 文件的局部(可以是头部、代码段等等)求MD5值,并将MD5写入dex文件的末尾或其他不影响dex文件加载运行的位置(本人暂时还没碰到)
相关代码:
MessageDigest digest=MessageDigest.getInstance("MD5"); byte[] bytes=new byte[1024]; FileInputStream fileinputStream=new FileInputStream(new File(dexPath)); int byteCount; while(fileinputStream.read(bytes)!=-1){ digest.update(bytes,0,byteCount); } BigInteger bigInteger=new BigInteger(1,digest.digest());//计算dex的哈希 String MD5=bigInteger.toString();//dex的哈希值
2、对Apk文件进行完整性校验(Android 5.0以下)
通过 APK 包的 MD5 摘要进行判断文件是否被修改过,这里需要计算 APK 的 MD5 值,然后将 MD5 上传到服务器进行判断,或者等待服务器下发原始文件的 MD5 值,进行比较判断。
相关代码:
String apkPath=context.getPackageCodePath();//获取Apk的路径 MessageDigest digest=MessageDigest.getInstance("MD5"); byte[] bytes=new byte[1024]; FileInputStream fileinputStream=new FileInputStream(new File(apkPath));//读取apk文件 int byteCount; while(fileinputStream.read(bytes)!=-1){ digest.update(bytes,0,byteCount); } BigInteger bigInteger=new BigInteger(1,digest.digest());//计算apk的哈希 String MD5=bigInteger.toString();//apk的哈希值
3、签名信息校验
(1)通过 A ndroid.content.pm.PackageInfo.getPacketInfo() 函数获取包信息,然后拿到签名信息。
(2)该签名信息为一个 byte 数组,可以转换成 X.509 格式的证书信息,或者直接对该签名信息求哈希。
(3)现阶段为了增加分析的难度,通常都会将部分代码放到.so文件中。
相关代码:
PackageInfo packageInfo=content.getPackageManager() .getPackageInfo(content.getPackageName() PackageManager.GET_SIGNATURES);//获取包信息 Signature[] signature=packageInfo.signatures; Signature sign=signature[0]; MessageDigest digest=MessageDigest.getInstance("MD5"); digest.update(sign);
二、静态完整性校验apk的一些逆向思路
1、获取apk签名需要获取APK的路径
我们可以在获取APK路径的地方下断点。这样可以定位到相关校验代码。通过修改参数,传入一个官方APK路径,也可以绕过校验。
Context.getPackageCodePath() 用来获得当前应用程序对应的 apk 文件的路径:/data/app/包名/xxx.apk Context.getPackageResourcePath() 获取该程序的安装包路径 : /data/app/包名/xxx.apk packageInfo.applicationInfo.sourceDir 这里面也可以获取apk路径
2、在相关API下断
大部分应用在获取签名信息时都会调用系统API,我们可以在相关的API下断:
V1签名( Android 7.0 以下):
android.content.pm.PackageInfo.getPacketInfo(ClassName,flags).signatures
这里需要注意 当 flags 为64的时候,该函数会获取签名信息。 所以需要在 getpackageinfo 下断点,当flags为64的时候,就是获取签名信息。
V2签名( Android 7-9 ):
// 1.反射实例化PackageParser对象 Object packageParser = getPackageParser(path); // 2.反射获取parsePackage方法 Object packageObject = getPackageInfo(path,packageParser); // 3.调用collectCertificates方法 Method collectCertificatesMethod = packageParser.getClass(). getDeclaredMethod("collectCertificates",packageObject.getClass(),int.class); collectCertificatesMethod.invoke(packageParser,packageObject,0); // 4.获取mSignatures属性 Field signaturesField = packageObject.getClass().getDeclaredField("mSignatures"); signaturesField.setAccessible(true); Signature[] mSignatures = (Signature[]) signaturesField.get(packageObject);
V3签名( Android 9 及以上):
这几个是v3签名的系统验证函数
PackageManagerService.InstallPackageLI() PackageParser.collectCertificates() ApkSignatureVerifier.verify() ApkSignatureSchemeV3Verifier.verify() ApkSigningBlockUtils.findSignature() ApkSigningBlockUtils.findApkSigningBlock() ApkSigningBlockUtils.findApkSignatureSchemeBlock() SignatureInfo.SignatureInfo() ApkSignatureSchemeV3Verifier.verify() ApkSignatureSchemeV3Verifier.verifySigner() ApkSignatureSchemeV3Verifier.verifyAdditionalAttributes() ApkSignatureSchemeV3Verifier.verifyProofOfRotationStruct() ApkSignatureSchemeV3Verifier.VerifiedProofOfRotation()
3、可以在获取哈希相关的API处下断。
4、可以通过弹出窗口或者toast提示进行代码回溯,定位到签名校验的附近。
三、动态完整性
1、Xpose Hook 检测
(1)检测关键字
de.robv.android.xposed.XposedHelpers类的 静态fieldCache字段 保存被hook的字段信息 静态methodCache字段 保存被hook的方法信息 静态constructorCache字段 保存被hook的类信息
(2)检测内存
检测内存映射列表中是否包含如下文件:
XposedBridge.so XposedBridge.jar
(3)检测方法的调用栈
handleHookMethod invokeOriginalMethodNative
注:
(1)在 dalvik.system.NativeStart.main 方法后出现 de.robv.android.xposed.XposedBridge.main 的方法调用
(2)如果Xposed hook了调用栈里的一个方法, 还会有 de.robv.android.xposed.XposedBridge.handleHookedMethod 和 de.robv.android.xposed.XposedBridge.invokeOriginalMethodNative 调用
(3)检测标记位
d e.robv.android.xposed.XposedBridge 类, 静态 disableHooks 成员变量, 这个字段表示是否对当前应用进行hook操作。
2、Frida Hook 检测
(1)检测进程
FridaServer 通过 TCP 与 PC 上的 Frida 进行通信,所以可以检测进程中是否存在 FridaServer 进程
(2)检测端口
默认端口: 2704 7
非默认端口:
A. 用 nmap -sV 来找到开放端口
B. 对每个开放端口发送 D-Bus 认证协议
C. 哪个端口回复了哪个就是 FridaServer 进程的端口
(3)检测内存
搜索内存是否存在以下两个文件
frida-gadget.so
frida-agent.so`
(4)暴力扫描
在映射的s o 文件中扫描Frida的库特征,例如:“ gadgets ”,“ LIBFRIDA ”等等,这 两个在Frida的所有版本中都有存在
3、Cydia Substrate Hook检测
(1)检测包名
检测设备安装目录是否存在 com.saurik.substrate
(2)检测调用栈
com.android.internal.os.ZygoteInit
com.saurik.substrate.MS$2
注:
(1) 在dalvik.system.NativeStart.main 调用后会出现2次
com.android.internal.os.ZygoteInit.main ,而不是一次。
(2) 如果Substrate hook了调用栈里的一个方法,还会出现 com.saurik.substrate.MS$2.invoked、
com.saurik.substrate.MS$MethodPointer.invok e和跟S ubstrat e扩展相关的方法。
(3)检测内存
检测内存映射中是否存在 com.saurik.substrate 文件
4、动态完整性校验的一些逆向思路
(1)搜索字符串
例如:搜索 d e.robv.android.xposed.XposedBridge 或者搜索上述字符串的base64编码后的值。
(2)获取堆栈的函数下断
大部分应用都是主动触发异常,然后获取堆栈信息,判断里面是否有相关hook的关键字, 可以对 getStackTrace() 下断,这个是获取堆栈的API。
(3)对文件读取函数下断
如果获取内存,需要打开当前进程的 / proc 文件,可以对文件读取相关的 API 下断, 例如: new file 、new FildeReader。
(4)对相关的获取包名下断
函数 getPackageName() 获取相关的包名信息,判断参数里是否包含 hook 工具的包名。
- End -
看雪ID: 陌殇
https://bbs.pediy.com/user-759951.htm
本文由看雪论坛 陌殇 原创
转载请注明来自看雪社区
:warning: 注意
2019 看雪安全开发者峰会门票正在热售中!
长按识别下方 二维码 , 即可享受 2.5折 优惠!
﹀
﹀
﹀
公众号ID:ikanxue
官方微博:看雪安全
商务合作:wsc@kanxue.com
↙ 点击下方“阅读原文”,查看更多干货
以上所述就是小编给大家介绍的《Android应用完整性保护总结》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Python网络编程基础
John Goerzen / 莫迟 等 / 电子工业出版社 / 2007 / 68.00元
《Python网络编程基础》可以作为各层次Python、Web和网络程序的开发人员的参考书,在实际工作中使用书中的技术,效果更佳。一起来看看 《Python网络编程基础》 这本书的介绍吧!