回顾
《Android逆向小技巧③:批量注入日志,打印目标程序执行流程》
在上一篇2019年的文章中,我们使用python写了一个简单的文本处理工具:
https://github.com/encoderlee/android_tools
在使用apktool对目标应用的apk解包以后,用这个python写的小工具,分析反编译出来的smali代码,并在每个方法中注入日志,然后对apk重新打包,这样,但APP运行的时候,我们每做一个操作,都可以从日志中看出目标代码的执行流程。
不过这种方式有一个很大的缺点,就是现在很多APP都做了签名校验,重新打包后,APP启动时检查到自身签名不对,发现自己被重新打包了,就罢工不再工作了。
签名校验
以支付宝目前的最新版10.2.50 (2021-12-20) 为例,使用apktool重新打包后,你需要使用apksigner重新签名才能安装:
apksigner sign --ks encoderlee.jks alipay.apk
但是重新签名签的这个名,只能用自己生成的证书去签名,因为你不可能搞到支付宝的证书和私钥。
这个时候如果直接安装运行这个APK,会出现这样的问题:
抱歉,请求参数不合法。
其实这就是因为APP检测到自身签名不对,就拒绝服务的表现,有的APP会表现为闪退。
其实想想也很容易理解,apktool解包,修改,重新打包APP那么简单,没有哪个厂商愿意让自己的APP被随意的玩弄和修改,所以目前绝大多数的APP都做了签名校验。
常规对抗
常规的对抗思路是,既然你在代码中做了签名校验,那么我找到你校验签名的代码,通过修改smali文件或用Xposed干掉它,不久OK了。于是你在网上可以搜到很多如何校验签名的代码:
public static int verifySignature(Context context) {
boolean isValidated = false;
try {
//得到签名
PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(),PackageManager.GET_SIGNATURES);
Signature[] signs = packageInfo.signatures;
//将签名文件MD5编码一下
String signStr = md5(signs[0].toCharsString());
//将应用现在的签名MD5值和我们正确的MD5值对比
return signStr.equals("这里写正确的签名的MD5加密后的字符串");
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return isValidated;
}
本质上来说这些签名校验的代码,都是调用 PackageManager.getPackageInfo().signatures 去获取自身的签名信息,进行比较判断自己是否被重新打包。
实际上,你在微信和支付宝反编译出的代码中,也能找到这些调用,但当你尝试修改smali或用xposed干掉这些调用的,替换原版的 signatures 数据,就会发现:
并没有什么卵用
想想也不可能那么简单,微信支付宝可是和这帮打包者对抗多年了,实际上在微信支付宝中,还使用了多种手段来校验自身签名,其中就包括在so中使用本机代码来实现校验,这样使得我们解决起来非常麻烦。
当然理论上来说,你完全可以找到它在so中检验签名的代码,干掉它,但是时间成本未免太高,看看微信支付宝的那个JAVA代码量,以及so的数量,想在这些海量代码中分析出关键点来,非常麻烦,就不要在这个思路上浪费时间了。
剑走偏锋
那么,能不能找到一种通用的办法,干掉大多数APP的签名校验呢?
我们先来分析,apksigner对APK签名,本质上是做了什么事情?
我们可以比较apktool重打包后没有签名的APK文件和apksigner签名后的APK文件,发现在APK文件中多了一个【META-INF】目录,里面的文件保存的实际上就是签名和文件校验信息。
那么,我们直接把原版APK中的【META-INF】覆盖到打包后的APK中,不就可以了?这样APK运行后,获取到的signatures 仍然是自己原版的 signatures 。
理想是美好的,但是Android的这套签名机制当然不会那么傻,这样简单替换【META-INF】目录后的APK,自然是无法正常安装的,提示【INSTALL_PARSE_FAILED_NO_CERTIFICATES】错误,因为android系统在安装的时候检测到签名和文件摘要信息对不上,自然就不允许安装。
Android签名校验原理可以看这篇文章:《Android 端 V1/V2/V3 签名的原理》
但要知道,Android系统是开源的,我们能不能修改Android系统源代码,让它允许安装签名错误的APK呢?当然是可以的。实际上也不需要这么麻烦,如果我们有root权限或有xposed,一样可以Hook Android系统本身的代码,让Android系统跳过签名校验,安装这个签名错误的APK。
这样的Xposed模块早已有人写好了,就是【幸运破解器「Lucky Patcher」】
https://www.luckypatchers.com/download/
幸运破解器有两种方式来运行,一种是手机已经Root,一种是手机已装好Xposed。
推荐Xposed的方式来运行,装好幸运破解器后,在Xposed中勾选启用该模块,打开幸运破解器APP。
【工具箱】-》【Android核心破解】-》勾选【签名验证始终真实】,勾选【禁用ZIP签名验证】
一番操作后,我们就可以把重新打包后签名不对的APK安装到这个手机上。而且APK里的【META-INF】目录里的文件,都是原封不动的原本APP里的签名文件,即使APP运行起来后,动态检查签名,也不会有什么问题,于是我们就可以正常运行我们重新打包修改过的微信支付宝APP了,当然其它大多数APP都可以这样来搞。
神器【VirtualXposed】
有人说,这种方式也太苛刻了吧,这样一搞,虽然是个通用和万能的方法破解了签名校验,但是要求安装该APP的手机,必须是一个ROOT过的手机,或者装了Xposed的手机呀,现在最新的小米华为手里,想要ROOT和Xposed,实在太麻烦了。而且我修改过的APP,想发布到群里给大家伙使用,不可能大家伙都要去ROOT手机吧?
那就要借助大名鼎鼎的 【VirtualXposed】了!
https://github.com/android-hacker/VirtualXposed
这个神器,可以在没有Root权限的手机上创建一个虚拟环境,然后对该虚拟环境内的APP启用Xposed模块!
这个项目的作者真的是个天才,这个思路都被他想出来并且付诸实现了。
而且 【VirtualXposed】本身实际上已经集成了【幸运破解器「Lucky Patcher」】的【Android核心破解】功能,即允许在【VirtualXposed】中安装签名不对的APK。
我们只需要在【VirtualXposed】的【高级设置】中勾选【允许安装没有签名的应用】
这样就不需要【幸运破解器「Lucky Patcher」】了,绝大多数APK,我们使用apktool重新修改打包后,只需把原APK的签名文件【META-INF】覆盖回去,然后通过这样的方式,安装签名不对的APK文件,就可以暴力绕过APK签名校验,愉快的重新打包和分发各种APP了。