Android签名认证分析
**一.Android签名验证流程基础知识及源码解析:****
Android应用程序签名过程分析:
http://blog.csdn.net/roland_sun/article/details/42029019
Android应用程序签名过程源码分析:
http://blog.csdn.net/roland_sun/article/details/42029019
源码涉及到签名的类为:
1.PackageManangerService(代码位于frameworks\base\services\core\java\com\android\server\pm\PackageManagerService.java)
2.PackageParser(代码位于frameworks\base\core\java\android\content\pm\PackageParser.java,编译后存在于framework.jar文件中)
3.StrictJarFile(代码位于libcore\luni\src\main\java\java\util\jar\StrictJarFile.java,编译后存在于core.jar文件中)
4.JarVeirifer(代码位于libcore\luni\src\main\java\java\util\jar\JarVerifier.java文件中,编译后存在于core.jar文件中)
- JarUtils(代码位于libcore\luni\src\main\java\org\apache\harmony\security\utils\JarUtils.java文件中,编译后存在于core.jar文件中)
验证过程主要使用*JarUtils中的
JarVeirifer.verifyCertificate
*函数。
Android采用 PKCS7 信封进行装载 X509 证书和签名封装。
X509证书:http://baike.baidu.com/view/3579227.htm
在源码libcore/luni/src/main/java/org/apache/harmony/security中有具体的实现
Apk签名流程:
Paste_Image.png二.证书格式分析
涉及到的两种证书格式:
X509 是证书规范
PKCS7 是消息语法
(常用于数字签名与加密)作用就是电子信封
PKCS7 一般是把证书分成两个文件,一个公钥一个私钥,有PEM和DER两种编码方式。PEM比较多见,就是纯文本的,P7一般是分发公钥用,看到的就是一串可见字符串,扩展名经常是.crt,.cer,.key等。
DER是二进制编码。在Android中使用的DER的编码格式。
查看命令
查看证书指纹.keystores命令
keytool –list –v –keystore debug.keystore
查看证书指纹.RSA文件命令
keytool –printcert –file CERT.RSA
使用openssl查看.RSA文件
openssl pkcs7 -inform DER -in CERT.RSA -noout -print_certs -text
查看证书指纹后会发现,RSA文件和.keystores,证书指纹相同,MD5,SHA1,SHA256三种指纹均相同。
证书分析:
1.X.509证书格式如下图所示:
Paste_Image.png• 这里看到证书中并不包含apk签名流程中第三部生成CERT.RSA时对用私钥计算出的签名。所以证书的信息是不会改变的,这也验证了上面所说的RSA中证书指纹和.keystone中的指纹相同的问题
2.对CERT.RSA进行详细解析
明确了上面的问题之后,对CERT.RSA 文件进行详细解析,得到下图:
Paste_Image.png说明:
(1)首先,我们的通常所说的证书的签名,是生成证书的时候CA对整个证书的所有域签名的得到的,而不是对某一部分签名得到的。整个签名就是上图中部分一的最下面的一段十六进制的内容;
(2)编程中的获取到的内容实质上是就是上图中的部分二,这是一个证书的所有内容;
使用openssl pkcs7 -inform DER -in CERT.RSA -print_certs 可得到
(3)部分一中的公钥等信息就是从部分二中得来的,可以直接在部分二中找到。
(4)可以猜测,部分一中的其他信息也是从部分二中得来,只不过编码方式不一样,所以显示不同而已。
三.破解方式
二次打包的目的:
可以修改apk内部构造,接口等,最常见的刷广告,接入广告即可,通过二次打包伪造官方APP应用,从而获取利益
Apk所符合被破解的条件
1.Java层通过
getPackageManager().getPackageInfo.signatures
来获取签名信息;
2.Native方法
/DLL/Lua脚本等通过获取Java的context/Activity对象,反射调用getPackageInfo等来获取签名;
3.首先获取apk的路径,定位到META-INF*.RSA文件,获取其中的签名信息;
4.能自动识别apk的加固类型;
破解方式
方式一:substrate框架libhooksig By空道
1.so文件用于hook sign
2.应用于在程序运行时获取当前进程的签名信息而进行的验证;
原理见:http://www.kanxue.com/bbs/showthread.php?p=1265295
方式二:重写继承类packageInfo和PackageManager By小白
1.适用于Java层packageInfo获取签名信息的方式;
2.亦适用于Native/DLL/LUA层反射packageInfo获取签名信息的方式;
3.该种方式可能会使PackageInfo中的versionCode和versionName为NULL,对程序运行有影响的话,需自主填充修复;
方式三:重写继承类,重置Sign信息;
1.适用于Java层packageInfo获取签名信息的方式;
2.亦适用于Native/DLL/LUA层反射packageInfo获取签名信息的方式;
3.该种方式可能会使PackageInfo中的versionCode和versionName为NULL,对程序运行有影响的话,需自主填充修复;
方式四:针对定位到具体RSA文件路径获取签名的验证方式;
1.针对定位到具体RSA文件路径获取签名的验证方式;
2.曾经破解过消消乐_Ver1.27,但是如果程序本身对META-INF签名文件中的MANIFEST.MF进行了校验,此方式无效,那就非签名校验,而是文件校验了;
方式五:hook android 解析的packageparse类中的两个验证方法pp.collectCertificates(pkg, parseFlags);
pp.collectManifestDigest(pkg);
修改实现方式。
如何加固APP防止APP被二次打包
通过以上信息,我们可以得到的是,证书作为不变的内容放在PKCS7格式的.RSA文件中,我们在RSA文件上验证的也只有证书。
方案一:
通过
Paste_Image.png Paste_Image.png
通过PackageManag对象可以获取APK自身的签名(方法有很多,最后是都通过
context.getPackageManager().getPackageInfo(
this.getPackageName(), PackageManager.GET_SIGNATURES).signature获得
signature)。
这里得到的sign为证书的所有数据,对其做摘要算法,例如
MD5可以得到MD5指纹,对比指纹可以进行安全验证。
Java程序都可以使用jni反射在native实现,分解Java代码太累赘,
方案二:调用隐藏类PackageParser.java中的collectCertificates方法,从源头获取cert证书
方案三:使用openssl使用JNI做RSA解析破解难度是相当的大,同样的解析出x.509证书,java解析转换为native解析so文件,但得到的文件比较大1.3M。。。。显然不可取。。(openssl自己百度下吧)
方案四:通过源码解析我们可以知道,apk文件验证是按照zip文件目录形式查找到.RSA文件结尾,我们可以直接去取文件的绝对路径,拿到证书的公钥信息进行验证(但需要引入PKCS7的库)
方案五:由棒棒加固和爱加密做的思路可以知道,自己重新定制摘要算法,在asset
里面重新搞一套验证流程(代码还没搞完)思路就是生成一个定制的CERT,另外开辟一套验证流程,不使用Android固有的签名认证流程。
关注微信公众号 Android历练记 或扫一扫二维码:
让我们一起来搞事情。