MSC-2015移动安全挑战赛 第二题 antiDebug分析

2015年02月06日

通过分析这道题目的反调试原理,发现我的方法能搞定纯属运气啊————反调试线程在调试模式下被阻塞了,没有抢在我F8执行之前运行完毕。下面来具体分析一下这个反调试:

首先关注一个重要的内存区域6290。(在我的模拟器上,apk的加载基址是47ff2000,截图都是绝对地址,我说明时候都使用相对地址)。这个区域存放反调试、以及解密jolin函数所要用到的关键数据。

图

当然在Onload入口点,这块内存区域是都是00。经过几个函数调用后,发现(如上图),这块区域被数据填满了。除了后面的字符串,前面部分实际上是一个和后面字符串函数对应的libc函数的内存地址。等同于一个函数跳转表。

其次反调试函数的入口点:

图

图中BLX R7实际上调用pthread_create函数创建线程(这个R7的地址也是动态生成的,和静态分析的函数调用是不同的),紧跟在后面的BL 17F4就是jolin的解密函数。这个线程就是专门用来反调试的。看其线程函数16A4

图

就是每隔3秒调用一次130C进行调试器检测。

接下来就是最最关键的反调试函数130C:

图 图

代码我都进行了名称标注和注释。这段代码为了增加逆向的难度,实际上使用了6290处的跳转表,静态分析根本就是不知所以。

具体说说其判断apk是否处于被调试状态的原理吧:

图 图

实际上就是打开进程对应的/proc/pid/status文件,查看里面的TracerPid条目,对于>=1的值(对应跟踪者不是root==0),则认为apk被调试器跟踪,kill(pid, -9)强制关闭整个进程。

最后需要说明的是,为了增加逆向难度,反调试里面所有的函数调用地址都==真实地址+1。 我们知道ARM模式指令长度都是4字节,函数地址不可能出现在奇数地址上。这种调用方式ARM会自动处理到4字节边界上,不影响程序执行,但可以模糊IDA的函数地址分析机制,使得IDA不能正确识别出调用的是哪个系统或库函数。

我是一个一个地址手动去查的。这说明需要有个脚本能自动分析和比对相应so/dll的导出函数地址,并进行比对

另外说说多线程的线程函数的调试: 调试器的原理是将断点处的指令改成CC,然后执行,cpu产生异常(int 3)后,调试器接管程序。 一旦程序暂停后所有线程都被暂停,一旦开始运行,理论上这个时候cpu是自主的可以运行任意线程,直到遇到CC为止。 F8、F7由于CC`靠的非常近,cpu被频繁中断,看上去似乎是在一个线程函数里调试一样。实际上后台线程的状态是无法确定的。 要调试到另一个线程的线程函数,比较好的方法是只在这个线程函数中设置断点,F9后会自然的中断在那里。因为cpu什么时候调度线程执行是我们无法精确控制的。