反调试方法一 - 读取进程status文件
栗子:阿里移动安全挑战赛第二题
本栗反调试方法:
用fopen打开/proc/<pid>/status
文件读取其中的TracerPid
值来检测自己的进程是否被attach,
TracerPid如果为0说明没有别的进程在调试这个进程,如果不为0说明有程序在调试。
使用ida附加进程,关键函数下断点F9之后,进程退出,ida退出.
调试过后发现JNI_OnLoad中有反调试方法(实际上是前辈的结论 :p).
根据使用ida调试so文件的步骤在library load
处断下.
验证
打开Debugger windows -> Module list,找到/data/app-lib/com.yaotong.crackme-1/libcrackme.so
,为其中的JNI_OnLoad方法右键Add breakpoint
.这里我们也可以得到libcrackme.so的基址为0x520AE000.
(当然如果反调试方法是在.initarray中,其地址需要手动计算.)
一步一步F8发现在执行这一句之后程序退出.
F7进去,发现是pthread_create
函数.
所以上上图中的unk_520AF6A4
函数就是线程回调函数咯.
先不去分析(其实是水平达不到 :( ),所以我们要用守株待兔的方法.
在module list中找到libc.so
,在fopen函数下断点,以此检验程序是否打开了某些文件检测状态值.
同时打开一个hex view(View -> Open subviews -> Hex dump),设置数据与R0同步.
F9运行到fopen函数处(有时并不能一次就断在fopen,注意看注释).
所以程序确实是读取了status文件. :P
这是需要找到是谁调用了fopen函数,然后修改读取status的返回值为0(不然就露馅了).
一直摁F8直到fopen函数返回,于是我们来到了这里.
一边是数据一边是代码,完全找不到函数开始的地方哇.
但是我们知道此处地址为520AF420
,减去我们之前记下的libcrackme.so的基址520AE000,得到相对地址为1420
另开一个ida,摁G键跳至此地址,F5发现是函数sub_130c
.
将sub_130c
的文件偏移转换为绝对地址:130c+520AE000=520AF30C.
p键将此处数据视为代码变成这样:
程序随后会用fgets()和strstr()来获取TracerId的值,于是我们在strstr()处下个断点,然后让hex view的数据与R0同步.
一直F9,直到R0的值变为这样:
F2修改为这样:
但是过一会程序又要获取,我们得一直不停的改,所以我们需要将这段代码nop掉,世界才安静.
patch so
如果静态分析时找到JNI_OnLoad中关键的那句代码:
进入线程的回调函数,发现竟然是这样子的!
回调函数sub_16a4
中调用了sub_130c
!
跟我们在动态调试时看到的完全不一样嘛.
现在将回调函数中的这一句nop掉就好了呗.
右键选择copy to assembly
我们的目标是BL sub_130C
. arm中没有nop语句,所以将movs r0,r0
作为NOP,对应的机器码为00 00 A0 E1
.
右键进入hex view.
摁F2将13 FF FF EB
改为00 00 A0 E1
,再摁F2应用.
点击Edit -> Patch program -> Apply patches to input file...
保存即可.
将原apk中的so文件替换为此so文件,重新打包签名安装,现在直接打开app调试就不会退出了. Success!
番外
ida中按三下D,将数据格式从字符转化为指针形式.