反调试往往在我们脱壳的第一步,虽然大佬们都能轻松过掉,甚至是修改内核一劳永逸。但是对我这样的小白来讲,还是有些困难,一需要c/c++的基础,二需要经验,三需要耐心。最近尝试apk脱壳,就常常卡死在反调试,深感无奈,只 怪正常的软件太社会,还经常有一些混淆,在此自己实现反调试,并尝试过掉,还挺有收获,写篇博客记录下来。
准备工作:
1 反调试检测的原理及实现 请参考 Android反调试方法总结以及源码实现之检测篇(一)
2 如何进行用ida进行android原生层so动态调试 请参考 Android IDA So的动态调试大法
3 如何进行android NDK开发(因为反调试大部分在init_array,JNI_OnLoad中实现),请参考Android Ndk开发入门(实现静态注册,动态注册)
练习环境:
1 android 5.1 三星手机 J7
2 ida
3 过程可能需要重打包,推荐android killler,改之理,需要请自行百度下载,或在看雪搜索
反调试练习 1 尝试过掉anti_debug01
我们的进程只能被一个进程ptrace,这里就是通过ptrace自己来实现反调试。对此我们只能通过分析,找到函数在so文件中的位置,NOP掉。将跳转到这个函数的BL,BLX指令通过16进制编辑器,修改为 00 00 00 00,也就是MOV R0,R0。将修改完的so库替换,进行重打包,实现过反调试。
通过分析这里的sub_B0567004就是我们实现的anti_debug01,减去so在内存中的起始位置,得到这条
bl指令在so中的位置是1A62,当然通过静态分析也很容易得到这条跳转指令的位置。接下来就是用010Editor修改相应位置的指令
通过改之理重打包,过反调试成功。
反调试练习 2 过掉anti_debug02
原理是通过检测 /proc/pid/status下的TracerPid,处于调试状态不为0
通过查看上面的源代码可得,这种调试方式的特征是会进入循环,按照Name,State,Tgid...的顺序直到TracerPid开始进行检测。当然有一定经验的老手也可以通过NOP过掉。
ida 动态调试走起
这里为了练习,我把几种反调试检测反到了一起,连着一起5个bl指令就是,当然NOP可以轻松过掉,但是我们的目标是为了exp,我们要用最笨的方法,修改内存的值达到过反调试的目的。
第一条就是我们的anti_bug02了,通过F7步入目标函数。
在我们调试的时候应该动静结合,格外注意bl,blx指令,这里我们为了学习!跟进每一条bl指令,当然一定要提前在bl的下一条指令下好断点,因为常常会调用libc中的函数,当我们大致明白这条bl指令的大概作用后,可以F9回到断点处。跟进每一条bl函数后我们会发现就是一些系统函数的调用,对应我们的源码,恰好是getpid,sprintf,fopen,fgets的顺序,至于函数的作用...篇幅有限,请自行百度。
我们会发现在fgets函数我们进入一个循环,
很好,大概这里就是我们挑选TracePid的地方了,我们在B1D5E5C0处下断点,可以验证。很好那最后的关键大概就是循环跳出的地方了,就是BNE loc_xxx最后一条指令的地方,我们跟进离它最近的一条bl unk_xxx那个地方,是atoi,好这就是拿到了TracerPid的地方,再跟零比较,同零kill进程,所以我们及时在这条bl指令出来及时修改R0 的值 zero value
好,这样我们就成功过掉了anti_bug02.
反调试练习 3,4
这里就是检测我们的调试器 android_server的名称和惯用端口,我们可以改掉名称和-p参数修改启动端口,不必进入动调,
端口转发adb forward tcp:23333 tcp:23333
当然还有其他反调试检测的方式,比如检测断点,像这种就只能在积累一定经验后,准备找到关键位置,NOP掉,动态修改太累。。。还有检测时间的,除了课余NOP,大概就类似anti_bug02的方式,不慌不忙慢慢找到关键点,关键函数,修改内存的值,BL,BLX,CMP是关键。
-------------------------------------------------------------2017.11.19----------------------------------------------------------
刚看到大佬写的反调试总结,收益颇多,特来更新,直接上链接
好,今天的反调试练习就到这里,慢慢积累经验把!