一直在用1.7.5版本的抖音,慢慢地升级并使用了好几个版本,中间有几位同学提及抖音加入了反调试功能。我说自己动态调试好好的,没有碰到过啊!直到最近1.9.0版本动态调试时发现lldb连接正常,后面操作app就会闪退的现象。这跟我平时遇到的反动态调试效果有点不一致哎,然后就研究了下这个问题,发现抖音使用了sysctl这种反调试技术。
现有的反调试技术
网上已经有很多优秀的文章论述了这个话题,我在这里也只是简单的列举下这几种技术。
- ptrace
这是我最常碰到的反调试技术,它能够对进程进行跟踪与控制,通过传入的参数来决定进程被调试后的操作。 - sysctl
进程有一个状态标识是否正在被调试,而sysctl就是通过读取该状态值来判断进程的调试状态。 - syscall
该方案的本质是间接调用sysctl来达到目的,但想比于上一方案,本方案更为隐蔽一些。 - arm
末遇到过,其具体原理网上也大都含含糊糊的没说清楚
定位反调试技术
ptrace技术在整个程序的生命周期中都会进行监控,造成的现象就是lldb刚连上程序,程序就退出了。从这个现象来判断,抖音应该不时采用了这种方案。
sysctl/syscall本质上是同一种方案,只是在程序调用该接口时才可能是做调试判断,这点跟抖音闪退的现象较为相似。
最好的检验方法是实践,lldb连接到抖音后,在ptrace/sysctl上直接下断点,随便操作抖音app,发现其很容易触发sysctl断点,而ptrace断点没有触发。
给ptrace/sysctl都下断点
sysctl断点很容易就触发了
使用bt命令查看该断点的调用堆栈,通过Aweme关键字定位属于抖音代码的调用分支地址,使用image list命令查看Aweme的偏移地址,通过计算器计算出hopper中的基地址,再用hopper跳转到该偏移地址,然后就可以分析抖音调用sysctl接口的具体用途了。
使用bt命令查看断点时的堆栈调用信息
查看应用的偏移地址
分析这段代码发现,原来sysctl原来不仅仅只是用来查看进程的调试状态的,其也被用在了获取机器ip地址的接口中,这也是sysctl断点很容易触发的原因所在了。
getifaddrs内部实现中同样调用了sysctl接口
看来这次触发的断点,不是预想中的反调试功能。保持耐心,断续C下去,反复多次出现这种情况后,反调试的断点终于出现了。重复上面的操作过程,就会定位到抖音的-[UIViewController dolphin_viewDidLoad]函数中,分析下其代码实现,其确定无疑就是反调试功能代码。
该函数会使用sysctl判断当前应用是否被调试,是的话直接退出程序,否则检查程序是否加载有IPAPatch或者IPAPatchEntry模块,加载了的话同样会退出程序。至于这个IPAPatch是干什么用,这是另外一个话题了,参见这里。
破解反调试
定位到了反调试的技术后,应对的破解手段就有很多了。比如直接使用register write命令修改寄存器值,使代码不再走入exit分支。比如通过hook sysctl函数,使其返回的判断值不再是调试状态等。
这里选择了hook sysctl手段的具体原因是,抖音将反调试的判断逻辑加入到了与用户交互的逻辑中,导致sysctl很频繁的调用,使用register write修改寄存器值的方法会修改到你怀疑人生。废话不多说,上代码。
int (*orig_sysctl)(int * name, u_int namelen, void * info, size_t * infosize, void * newinfo, size_t newinfosize);
int new_sysctl(int * name, u_int namelen, void * info, size_t * infosize, void * newinfo, size_t newinfosize){
int ret = orig_sysctl(name,namelen,info,infosize,newinfo,newinfosize);
if(namelen == 4 && name[0] == 1 && name[1] == 14 && name[2] == 1){
struct kinfo_proc *info_ptr = (struct kinfo_proc *)info;
if(info_ptr && (info_ptr->kp_proc.p_flag & P_TRACED) != 0){
NSLog(@"wxq - sysctl query trace status.");
info_ptr->kp_proc.p_flag ^= P_TRACED;
if((info_ptr->kp_proc.p_flag & P_TRACED) == 0){
NSLog(@"wxq trace status reomve success!");
}
}
}
return ret;
}
%ctor
{
%init;
MSHookFunction((void *)sysctl,(void*)new_sysctl,(void**)&orig_sysctl);
}
至此,抖音的反调试功能就成摆设了,尽情的揉虐它吧。
网友评论