android签名检测和绕过
PackageManagerService获取签名
正常APP中获取PackageInfo
中的签名信息是通过Binder通讯向PackageManagerService
发送TRANSACTION_getPackageInfo
请求,同时设置请求的参数的flag为GET_SIGNATURES
。当PackageManagerService
判断是TRANSACTION_getPackageInfo
请求后会去调用PackageManagerService.getPackageInfo
。
PackageManagerService.getPackageInfo
会进一步调用PackageManagerService.getPackageInfoInternal
PackageManagerService.getPackageInfoInternal
会进行一些权限校验和匹配,最后调用PackageManagerService.generatePackageInfo
PackageManagerService.generatePackageInfo
获取到包名对应的PackageParser.Package
,然后调用PackageParser.generatePackageInfo
PackageParser.generatePackageInfo
就是取出PackageParser.Package
对象中的成员mSigningDetails.pastsigningcertificates[0] / mSigningDetails.signatures
的值,此值就是apk对应的签名信息。
而每个apk包对应的PackageParser.Package
保存在PackageManagerService
的mPackages
成员中。这是一个map表,键是包名,值就是PackageParser.Package
,而apk的签名信息就保存在PackageParser.Package
对象中的成员mSigningDetails.pastsigningcertificates[0] / mSigningDetails.signatures
中。在apk安装的时候,会将解析的apk签名保存(put)在mPackages
中。
总结:APK进程中获取自身签名实际就是获取PackageManagerService
的mPackages
成员中包名对应的PackageParser.Package.mSigningDetails.pastsigningcertificates[0] / mSigningDetails.signatures
。
PackageManagerService获取签名绕过
- APP进程直接通过
getApplicationContext().getPackageManager().getPackageInfo(packagename, PackageManager.GET_SIGNATURES)
获取签名信息 - APP进程利用
Binder通讯
直接向PackageManagerService
发送TRANSACTION_getPackageInfo
请求获取签名信息 - 将1和2java层的操作拿到native层利用反射执行同样的操作。
以上获取签名的方式本质上都是获取PackageManagerService
的mPackages
成员中包名对应的PackageParser.Package.mSigningDetails.pastsigningcertificates[0] / mSigningDetails.signatures
,只要在整个通讯的中间的任意一个位置进行hook就可以将签名信息进行替换,获取直接修改PackageManagerService
的mPackages
成员中包名对应的PackageParser.Package.mSigningDetails.pastsigningcertificates[0] / mSigningDetails.signatures
值为指定签名就可以绕过上面的签名检测。