最近在阅读《Android设备指纹攻防与风险环境检测》时,发现光靠阅读书中的思路和代码片段不能很好的理解,所以打算自己写一个app,实践一下
java层通常使用PackageManager进行签名校验
在Android9以上,签名可以通过PackageInfo -> signingInfo -> signatures获得,以下则是通过PackageInfo -> signatures
无论是哪种,获取PackageInfo都会使用getPackageInfo这个api
在Android9引入了密钥轮换机制,因此废弃了GET_SIGNATURES,转而推荐使用GET_SIGNING_CERTIFICATES获取证书
但是单纯java层检测并不安全:PackageManager的getPackageInfo可能会被hook、用来比对的签名值也可能被篡改
在MainActivity调用这个方法
并对应用重新签名

此时签名校验失败,尝试通过hook PackageManger返回正确校验值
脚本hook了getPackageInfo方法,返回了伪造的PackageInfo -> SigningInfo -> SigningDetails值

此时签名校验失败。
如何防止这种方式hook getPackageInfo呢
最直接的思路就是不使用getPackageInfo,可以通过反射获取Binder对象,直接和系统服务进行通信
不使用getPackageInfo,减少hook点。运行应用观察,发现此方法的签名校验失败

但这种方法同样有缺点
上面这段代码中
解析PackageInfo.CREATOR为PackageInfo对象,所以可以通过反射替换此静态变量,伪造签名信息
hook方法如下
CREATOR里包含两个方法
1.createFromParcel(Parcel source) 从二进制字节流里读取数据 拼装还原出一个完整的Java对象
2.newArray(int size) 用来创建该对象的数组
在我们自己创建的CREATOR中,截取到数据之后将PackageInfo替换即可成功替换

在Java代码中新建一个方法检测PackageInfo.CREATOR是否被替换
现在运行完整脚本,发现此方法被检测到

先来写一个简单的native检测
native-lib.cpp
(有些工具类函数,比如解析v2 v3签名的函数,使用ai辅助生成)
在上面这个例子中,完全可以hook open函数,将参数一的地址替换成原始apk,这样签名校验一定会成功
hook脚本如下:
编译保护将open函数自动替换为__open_2,所以这里不能只hook open函数,效果如下

传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 14小时前
被mb_wckjnnha编辑
,原因: