除了签名校验之外,还有一种情况是 classes.dex 的 MD5 检验,也可以发现被篡改的 classes.dex。怎么区分这两种不同的校验呢?拿到 apk 之后对其重新签名,如果仍然可以正常安装运行的即说明是 classes.dex 的 MD5 校验,反之则是签名校验。
一般在程序内进行的校验有两种途径,在线比对和离线比对,逆向者在意的是比对的这个过程及其参数。在线比对和离线比对的区别是:在断网情况下仍旧闪退的是离线比对,断网后先提示没有网络连接再闪退的是在线比对。
既然校验的过程是在本地程序进行的,那么在反编译得到代码之后,只要修改一下比较时的对应条件就可以简单的绕过校验了,整个校验过程有点掩耳盗铃的意思。
Signature · smali
获取当前 apk 签名的 Java 代码如下:PackageInfo packageInfo = getPackageManager().getPackageInfo( "xx.xxx.xx", PackageManager.GET_SIGNATURES); Signature[] signs = packageInfo.signatures;
对应的 smali 代码为:
Landroid/content/pm/PackageInfo;->signatures:[Landroid/content/pm/Signature
所以对付签名校验,只要通过这段关键代码找到对应的调用位置,不断跟进,确定最终判断的位置然后修改比较条件即可。
另外有的时候会进入 native 层判断,这个时候搜索关键字 signature 然后判断跟进即可。
MD5 · smali
这类首先会在 smali 层获取当前 apk 的目录,然后再传入 native 层面进行比较,典型代码如下所示:iget-object v1, v0,Landroid/content/pm/ApplicationInfo;->sourceDir:Ljava/lang/String; const-string v1, "/sdcard/buyudaren.apk" # 本行目的是 bypass 校验,路径为原版 apk 路径,覆盖 v1 invoke-static {v1}, Lorg/cocos2dx/lib/Cocos2dxHelper;->nativeSetApkPath(Ljava/lang/String;)V
简单添加中间一行即可绕过 MD5 的判断,因为此时进入 native 层的是原版 apk 的路径,所以校验的也是原版 apk,此时当然没有问题。可以看到,看似复杂的进入 native 层面有的时候只是掩耳盗铃的一种方式。
如果要进入 native 层面去 Bypass 检查,在把 .so 文件拖入 IDA Pro 后搜索 “classes.dex” 即可,跟进可以发现 MD5 字符串或是进行比对的特征值。
另外有时存在 .so 和 classes.dex 文件相互验证的情况,这个时候就对应的搜索 “classes.dex” 和 “xxx.so” 两个特征字符串,找到程序运行中校验的文件路径,然后对应地修改成原版文件的路径即可。
REFERENCE
* 另外说一下,有的时候两个程序的 AndroidManifest.xml 中定义了 SharedUserId 并进行交互,这时必须两个程序的签名相同才可以正常安装。