美文网首页安全防护
iOS 逆向 -- 动态调试防护

iOS 逆向 -- 动态调试防护

作者: 木扬音 | 来源:发表于2021-06-12 00:07 被阅读0次

    ptrace

    debugserver通过ptrace函数调试app

    ptrace是系统函数,此函数提供一个进程去监听和控制另一个进程,并且可以检测被控制进程的内存和寄存器里面的数据。ptrace可以用来实现断点调试和系统调用跟踪。

    ptrace防护

    • 导入 MyPtraceHeader.h到自己工程,其中代码如下
    #ifndef    _SYS_PTRACE_H_
    #define    _SYS_PTRACE_H_
    
    #include <sys/appleapiopts.h>
    #include <sys/cdefs.h>
    
    enum {
        ePtAttachDeprecated __deprecated_enum_msg("PT_ATTACH is deprecated. See PT_ATTACHEXC") = 10
    };
    
    
    #define    PT_TRACE_ME    0    /* child declares it's being traced */
    #define    PT_READ_I    1    /* read word in child's I space */
    #define    PT_READ_D    2    /* read word in child's D space */
    #define    PT_READ_U    3    /* read word in child's user structure */
    #define    PT_WRITE_I    4    /* write word in child's I space */
    #define    PT_WRITE_D    5    /* write word in child's D space */
    #define    PT_WRITE_U    6    /* write word in child's user structure */
    #define    PT_CONTINUE    7    /* continue the child */
    #define    PT_KILL        8    /* kill the child process */
    #define    PT_STEP        9    /* single step the child */
    #define    PT_ATTACH    ePtAttachDeprecated    /* trace some running process */
    #define    PT_DETACH    11    /* stop tracing a process */
    #define    PT_SIGEXC    12    /* signals as exceptions for current_proc */
    #define PT_THUPDATE    13    /* signal for thread# */
    #define PT_ATTACHEXC    14    /* attach to running process with signal exception */
    
    #define    PT_FORCEQUOTA    30    /* Enforce quota for root */
    #define    PT_DENY_ATTACH    31
    
    #define    PT_FIRSTMACH    32    /* for machine-specific requests */
    
    __BEGIN_DECLS
    
    
    int    ptrace(int _request, pid_t _pid, caddr_t _addr, int _data);
    
    
    __END_DECLS
    
    #endif    /* !_SYS_PTRACE_H_ */
    
    • 在合适的地方加入下面方法
        //告诉系统,当前进程.拒绝被debugserver附加!
        //arg1:ptrace要做到事情
        //arg2:需要操作的进程
        //arg3:附加的地址
        //arg4:附加的数据
        //arg4/arg3:取决于第一个参数!
        ptrace(PT_DENY_ATTACH, 0, 0, 0);
        //如果附加就闪退!!
        
    

    破解ptrace防护

    因为ptrace是系统函数,所有它最终在间接符号表中,我们可以通过符号断点ptrace,来定位到当前的执行方法,通过fishhook符号的重绑定来进行fishhook

    #import "InjectCode.h"
    #import "fishhook.h"
    #import "MyPtraceHeader.h"
    
    @implementation InjectCode
    
    //定义函数指针!
    int   (*ptrace_p)(int _request, pid_t _pid, caddr_t _addr, int _data);
    
    +(void)load
    {
        //交换
        struct rebinding ptraceBd;
        ptraceBd.name ="ptrace";
        ptraceBd.replacement = my_ptrace;
        ptraceBd.replaced = (void *)&ptrace_p;
        
        struct rebinding bds[] = {ptraceBd};
        rebind_symbols(bds, 1);
    }
    
    
    //自定义
    int   my_ptrace (int _request, pid_t _pid, caddr_t _addr, int _data){
        if (_request != PT_DENY_ATTACH) {//如果不是拒绝附加,保持调用!
            return ptrace_p(_request,_pid,_addr,_data);
        }
        return 0;
    }
    
    
    @end
    

    sysctl

    通过sysctl函数检测是否被动态调试比ptrace相对隐蔽点,可延展性强

    • stsctl函数可以检测进程状态

    sysctl防护代码

    #import "ViewController.h"
    #import <sys/sysctl.h>
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    BOOL isDebugger(){
        int name[4];//里面放字节码。查询的信息
        name[0] = CTL_KERN;//内核查询
        name[1] = KERN_PROC;//查询进程
        name[2] = KERN_PROC_PID;//传递的参数是进程的ID(PID)
        name[3] = getpid();//PID的值告诉它!
        
        struct kinfo_proc info;//接收进程信息的结构体
        size_t info_size = sizeof(info);
        /**
         1、查询信息数组
         2、数组中数据类型的大小
         3、接受信息结构体的指针
         4、接受信息结构体的大小的指针
         */
        int error = sysctl(name, sizeof(name)/sizeof(*name), &info, &info_size, 0, 0);
        assert(error == 0);//0 就是没有错误,其他就是错误码!
        
        return  ((info.kp_proc.p_flag & P_TRACED) != 0);
    }
    
    static dispatch_source_t timer;
    
    void debugCheck(){
        timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
        dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC, 0.0 * NSEC_PER_SEC);
        dispatch_source_set_event_handler(timer, ^{
            if (isDebugger()) {
                NSLog(@"检测到了调试!");
            }else{
                NSLog(@"正常!!");
            }
        });
        dispatch_resume(timer);
    }
    
    
    
    - (void)viewDidLoad {
        [super viewDidLoad];
       
        debugCheck();
    }
    
    
    @end
    

    sysctl破解

    同理通过fishhook破解

    #import "InjectCode.h"
    #import <sys/sysctl.h>
    #import "fishhook.h"
    
    @implementation InjectCode
    +(void)load
    {
        rebind_symbols((struct rebinding[1]){{"sysctl",my_sysctl,(void *)&sysctl_p}}, 1);
    }
    
    //原始函数地址
    int (*sysctl_p)(int *, u_int, void *, size_t *, void *, size_t);
    
    
    //定义新的函数
    int my_sysctl(int *name, u_int namelen, void *info, size_t *infosize, void *newinfo, size_t newinfosize){
        if (namelen == 4
            && name[0] == CTL_KERN
            && name[1] == KERN_PROC
            && name[2] == KERN_PROC_PID
            && info) {
            int err = sysctl_p(name,namelen,info,infosize,newinfo,newinfosize);
            
            struct kinfo_proc * myinfo = (struct kinfo_proc *)info;
            if (myinfo->kp_proc.p_flag & P_TRACED) {
                //使用异或可以取反!
                myinfo->kp_proc.p_flag ^= P_TRACED;
            }
            return err;
        }
        
        
        return  sysctl_p(name,namelen,info,infosize,newinfo,newinfosize);
    }
    
    @end
    
    

    提前执行防护代码

    因为fishhookrebind_symbols函数都在load中执行,如果防护代码在load之前就执行了,就可以达到防护的目的

    我们可以将防护代码封装成一个动态库,达到提前执行的目的,但是只能在第一次的时候才能检测到防护fishhook在后面会替换掉相应的防护函数

    破解 --> 修改二进制文件

    • 可以通过MonkeyDev,通过断点,判断有没有ptrace方法的防护,
    • 然后通过bt打印函数调用栈来获得对应的动态库动态库虚拟内存地址
    • 通过image list找到对应动态库地址
    • 虚拟地址减去动态库地址得到偏移地址
    • 使用Hopper Disassembler查看动态库的二进制地址
    • 定位到偏移地址,查看汇编,修改对应的汇编二进制
    • 导出一个新的可执行文件
    • 替换动态库中的可执行文件

    相关文章

      网友评论

        本文标题:iOS 逆向 -- 动态调试防护

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