一、前言
在之前介绍了很多破解相关的文章,在这个过程中我们难免会遇到一些反调试策略,当时只是简单的介绍了如何去解决反调试,其实在去年我已经介绍了一篇关于Android中的安全逆向防护之战的文章:Android安全逆向防护解析;那么这篇文章就来详细总结一下,现阶段比较流行的几种反调试解决方案。
二、反调试策略方案
第一种:先占坑,自己附加
代码非常简单,在so中加上这行代码即可:ptrace(PTRACE_TRACEME, 0, 0, 0);
其中PTRACE_TRACEME代表:本进程被其父进程所跟踪。其父进程应该希望跟踪子进程,一般一个进程只能被附加一次,我们在破解调试的时候都会附加需要调试应用的进程,如果我们先占坑,父进程附加自己,那么后面在附加调试就会失败。加上这段代码我们运行之后看一下效果:
我们在进行破解动态调试的时候都知道附加进程的status文件中的TracerPid字段就是被调试的进程pid,这里我们运行程序之后,查看进程对应的status文件,发现TracerPid值就是进程的父进程pid值。那么后面如果有进程在想附加调试就是会失败的。这种方式启动一定的调试作用,但是不是绝对安全的。关于解决这种反调试方案后面再说。
第二种:签名校验
其实签名校验,准备来说不算是反调试方案,但是也是一种安全防护策略,就在这里提一下了,而签名校验一般现在有很多用途,用意在于防止二次打包,一般方案有两种:
第一:直接在本地做防护,如果发现签名不一致直接退出应用
第二:将签名信息携带请求参数中参与加密,服务端进行签名校验,失败就返回错误数据即可
而这两种方式也都不是最安全的防护,因为只要有签名校验的逻辑,在本地都可以进行过滤掉。而在之前的好几篇文章中都介绍了如何过滤这种签名校验的方法,不了解的同学可以去查看:Android中破解某应用的签名校验;而对于服务器签名校验以及将签名校验放到so中的文章后面会单独在介绍一篇。
第三种:调试状态检查
这种方式是纯属借助Android中的api进行检验,有两种方法:
第一:检查应用是否属于debug模式
直接调用Android中的flag属性:ApplicationInfo.FLAG_DEBUGGABLE,判断是否属于debug模式:
这个其实就是为了防止现在破解者为了调试应用将应用反编译在AndroidManifest.xml中添加:android:debuggable属性值,将其设置true。然后就可以进行调试。
添加这个属性之后,我们可以用 dumpsys package [packagename] 命令查看debug状态:
所以我们可以检查应用的AppliationInfo的flag字段是否为debuggable即可。不过这种方式也不是万能的,后面会介绍如何解决这种反调试问题。
第二:检查应用是否处于调试状态
这个也是借助系统的一个api来进行判断:android.os.Debug.isDebuggerConnected();这个就是判断当前应用有没有被调试,我们加上这段代码之后,按照之前的那篇文章:脱掉360加固保护壳,其中有一个步骤进行jdb连接操作:
jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700,当连接成功之后,这个方法就会返回true,那么我们可以利用这个api来进行判断当前应用是否处于调试状态来进行反调试操作。但是这种方式不是万能的,后面会介绍如何解决这种反调试问题。
第四种:循环检查端口
我们在之前破解逆向的时候,需要借助一个强大利器,那就是IDA,在使用IDA的时候,我们知道需要在设备中启动android_server作为通信,那么这个启动就会默认占用端口23946:
我们可以查看设备的tcp端口使用情况 cat /proc/net/tcp:
其中5D8A转化成十进制就是23946,而看到uid是0,因为我们运行android_server是root身份的,uid肯定是0了。所以我们可以利用端口检查方式来进行反调试策略,当然这种方式不是万能的,后面会详细介绍如何解决这样的反调试方法。
第五种:循环检查TracerPid值
在第一种方式中,我们简单的介绍了如果应用被调试了,那么他的TracerPid值就是调试进程的pid值,而在使用IDA进行调试的时候,需要在设备端启动android_server进行通信,那么被调试的进程就会被附加,这就是android_server进程的pid值了:
查看一下android_server的pid值:
所以我们可以在自己的应用中的native层加上一个循环检查自己status中的TracerPid字段值,如果非0或者是非自己进程pid(如果采用了第一种方案的话,这里也是需要做一次过滤的);那么就认为被附加调试了。当然这里还有一种方案,就是可以检查进程列表中有没有android_server进程,不过这种方式都不是万能的,后面会详细介绍如何解决这种反调试方案。
三、方案策略总结
下面简单几句话总结这几种方案:
第一、自己附加进程,先占坑,ptrace(PTRACE_TRACEME, 0, 0, 0)!
第二、签名校验不可或缺的一个选择,本地校验和服务端校验双管齐下!
第三、借助系统api判断应用调试状态和调试属性,最基础的防护!
第四、轮训检查android_server调试端口信息和进程信息,防护IDA的一种有效方式!
第五、轮训检查自身status中的TracerPid字段值,防止被其他进程附加调试的一种有效方式!
上面就简单的介绍了现在流行的几种应用反调试策略方案,这几种方案可以全部使用,也可以采用几种使用,但是要记住一点,就是如果要做到更安全点,记得把反调试方案放到native层中,时机最早,一般在JNI_OnUnload函数里面,为了更安全点,native中的函数可以自己手动注册,函数名自己混淆一下也是可以的。具体可参见这篇文章:Android安全逆向防护解析。现在一些加固平台为了更有效的防护,启动的多进程之间的防护监听,多进程一起参与反调试方案,这种方式对于破解难度就会增大,但是也不是绝对安全的。文章中对于每种方式最后都说到了,都不是万能安全的,都有方法解决,而这内容放到下一篇来详细介绍了。
反调试方案策略代码下载:https://github.com/fourbrother/android_anti_debug
四、总结
本文主要介绍了Android中应用在进行反调试反破解的几种方案,对于每种方案进行了详细原理分析,代码也给出了下载地址,可以自行运行看效果,而对于这几种反调试方案并非是绝对安全的,后面会再详细介绍如何解决这些反调试功能,但是为了应用安全,这几种方案也不可以不用,有总比没有好!最后读完文章,记得多多点赞分享扩散,要是有打赏就最好啦啦!