Anti Debug主要是通过各种函数去确定当前进程是否处于被调试的状态。
1.将文件拖入jdax-gui中,进行静态分析,会发现OnCreate里面没多少内容,并且上面加载了so库,如下图所示。
2.将SO文件拖入,找到JNI_OnLoad,如下图所示。
3.按F5查看伪代码,如下图所示。
4.除了动态注册这个参数外,还有两个参数的传递,其中一个是简单的if判断,它使用的是或运算符,只要其中有一个成立,就会成功执行,返回return-1,相反则返回65540,如下图所示。
5.进入第一个anti_time,分析逻辑,如下图所示。
6.先获取线程ip给v0,前面两个gettimeofday的函数,传入两个值进行操作,如下图所示。
7.查看gettimeofday引用,如下图所示。
8.点击进行查看,如下图所示。
9.进来后,查看关键字眼,是和时间相关的,如下图所示。
10.v3和tv分别是两个不同的时间点,分别获取两个时间,lv_sec是秒数,如下图所示。
11.获取两个间隔做差值放到v1寄存器,然后继续if判断,小于零则给上一层的if返回0,反之,直接kill,返回1,如下图所示。
12.查看并分析if的简单判断逻辑,下面有一个for循环,里面又是各种嵌套,如下图所示。
13.for循环结束后,返回上一层的布尔值,并不是在for的外层,如果for结束后,执行++v4操作,会返回默认值false(布尔值的默认值是false),如下图所示。
14.关键点就在于for循环里面的分析,查看for循环,发现有一个break,在C语言中,for循环里面的break就是跳出for循环的意思,如下图所示。
15.判断成立后会直接break,如下图所示。
在汇编里面将它进行修改,直接break,就可以直接给上一层返回一个false。
16.分析一下,如果v4大于等于v6,v4上面初始值为0,而v6是一个获取得到的返回值,如下图所示。
17.这个位置显示的是什么?如下图所示。
18.查看v3,有v2赋值,v2是一个方法的返回值,如下图所示。
19.回到break的判断,v4固定值0,v6是一个返回值+44,然后整体取地址,这个肯定是大于零的(因为地址不可能是负数),也就是说,这个if判断永远小于零,break永远不会执行。
那么,修改方法有以下几种:
(1)直接把if判断nop掉,也就是进来for循环就直接break;
(2)把判断的大于等于改成小于,也可以执行到break;
(3)直接改动break指令的位置,比如放到for循环外面。
20.继续分析逻辑,这里面有几个linux编程涉及的函数,如下图所示。
pthread_self:获取自己的线程id;
pipe管道:实现进程通信;
pthread_create:创建线程,它有四个参数,查看它的第三个参数,这个是自己的定义的程序,做一些其他操作。
21.同理,我们分析的这个也是在第三个参数,做了一些获取线程的操作,也就是这个函数,如下图所示。
22.继续分析这个函数,如下图所示。
23.点击进入,如下图所示。
24.它的作用就是进出函数时,堆栈是否平衡和数据是否被修改,如下图所示。
25.v0是获取当前进程id,那么这个打印的结果就是当前的进程,如下图所示。
26.调用fork函数,父进程调用fork函数可以创建子进程,那么这个返回值就是子进程,如下图所示。
27.然后一个if判断,如果创建成功,把值最终传给了childpid这个变量,紧接着else,如果没成功,就关闭,如下图所示。
28.else下面还有其他的操作,就是静态so层分析,如下图所示。
1.在jni_onload处下断点,然后运行到此处,如下图所示。
2.这几个函数就是有反调试函数的地方,如下图所示。
3.直接把这三个函数nop掉,如下图所示。
4.然后F4直接原型到后面的指令,就完美的过掉了反调试,如图7.31所示。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)