美文网首页爬虫专题iOS Developer程序员
破解抖音反调试功能的思路与实践

破解抖音反调试功能的思路与实践

作者: 秦砖 | 来源:发表于2018-07-08 22:41 被阅读122次

    一直在用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);
    }
    

    至此,抖音的反调试功能就成摆设了,尽情的揉虐它吧。

    相关文章

      网友评论

      本文标题:破解抖音反调试功能的思路与实践

      本文链接:https://www.haomeiwen.com/subject/qjevuftx.html