原始APK文件指纹文件包括如下三个文件:
● manifest.mf:原始APK的文件指纹,文件格式见2.3.1;
● cert.sig:manifest.mf经过RSA加密后的签名;
● cer.pub:用于验证cert.sig的RSA公钥。
这里的RSA签名,并不是APK开发者的签名,而是BB自己的签名。
4.1.1 验证cert.pub文件正确性
在BB的libdexhelper.so文件中保存着cert.pub的MD5值,但是这个MD5值是经过加密后的,而且其加密的流程还是比较复杂的。解密流程首先 实现了一个从APK文件中提取文件的C语言版本解压程序,包括如下函数:
● dexZipOpenArchive //打开zip文件获得ZipArchive结构
● dexZipFindEntry //从ZIP中获取指定文件的入口结构
● dexZipGetEntryInfo //得到指定文件入口结构对应的信息
● ReadToBufFromZipFile //将指定文件的内容读到BUF中
● dexZipCloseArchive //关闭zip文件
利用上面的函数,将cert.pub读取到内存中,然后计算其MD5值。接着开始获取原始APK的MD5值,其经过如下4个步骤:
1、计算0x52600开始0x1000个字节的MD5 值;
2、构造一个斐波那契数列,1 1 2 3 5 8 13 21 34 55;
3、以斐波那契数列为索引从数组0x52600取出对应的数值,然后与步骤1得到的MD5值按字节亦或,获得一个0x10大小的KEY。实际上是下面RC4解密的KEY
4、利用步骤3获得的RC4 KEY ,对525E0开始的0x10大小的数据,进行RC4解密。解密的结果就是原始的cer.pub对应的MD5值。
然后,将2个MD5值进行比较,如果不一致,则终止应用。
4.1.2 验证manifest.mf正确性
经过如下步骤进行验证:
1、 读取manifest.mf文件到内存;
2、 读取cert.sig文件到内存;
3、 使用cert.pub对manifest.mf进行RSA签名;
4、 利用步骤3获得签名与cert.sig进行比较,如果不一致,则终止应用。
4 .2 里程碑
至此确定原始APK的识别指纹没有被篡改,下面开始进行真正的防篡改流程。
4.3 提取当前APK的文件指纹1
将APK\\META-INF\ MANIFEST.MF读到内存,并进行一行一行的遍历,将文件名和对应的sha1数值存储在结构BB_HashTable中。 BB_HashTable结构见2.3.2。
4.3 提取原始manifest.mf的4种类型的文件指纹
对原始manifest.mf文件进行解析,并将解析结果存储到ORG_file_Sign_list结构中,ORG_file_Sign_list结构见2.33。
4.4 提取当前文件的文件指纹2
遍历APK,过滤掉“assert\ meta-data”、“META-INF\”目录,并且获得每个文件的CRC32的数值,并存储在CUR_file_crc32结构中,CUR_file_crc32结构见2.3.4。
4.5 文件指纹验证
前面已经将原始APK的4种文件指纹,以及当前APK的4种文件指纹都获取到,然后就开始进行判断,只要有任何一个文件指纹不一致,则终止应用。
5 终止应用的方法
对于通用的终止应用的方法,一般可能采用kill、abort、exit等系统函数,BB显然知道这样去终止会带来很大的安全问题。因此其采用了另外一种终止方式。
当需要终止应用时,首先破坏堆栈内容,然后将PC指针指向存储APK路径名的位置,而其对应的代码是无法执行的,从而引发异常来使应用终止运行。
6 总结
1、 提取原始文件的的文件指纹,并分为4种类型;
2、 使用RSA对原始文件指纹进行加密;
3、 同时在SO中保存RSA公钥的MD5值,而这个MD5值是经过多重加密存放的。里面用到了MD5\斐波那契数列\RC4\base64等加密算法;
4、 验证RSA公钥正确性;
5、 验证原始文件指纹的正确性,使用RSA公钥验证;
6、 至此确保原始文件的所有指纹都是正确的,下面开始进行真正的校验过程;
7、 获取原始文件的4种文件指纹
8、 获取当前文件的4种文件指纹
9、进行4种文件指纹的一一比较,只要有一个不符合,则终止进程。
参考资料: