在「iOS 逆向入门 - 绕过抖音反调试」中提到常用反调试手段,这里写下具体实现。

一、常用反逆向手段

1、反调试:ptrace

ptrace 被常用于防止 lldb 依附,原理是一个进程只能被 ptrace 只能被一次,先于别人调用 ptrace 则可以防止别人依附。

ptrace 有几种方式进行调用:

1)直接调用

#import <sys/ptrace.h>

ptrace(PT_DENY_ATTACH,0,0,0);

iOS SDK 中不包含 ptrace.h 头文件,无法使用此方法调用,可使用以下方法。

2)通过 dlopen + dlsym 调用

#import <dlfcn.h>
#import <sys/types.h>
 
typedef int (*ptrace_ptr_t)(int _request, pid_t _pid, caddr_t _addr, int _data);
#if !defined(PT_DENY_ATTACH)
#define PT_DENY_ATTACH 31
#endif
 
void disable_attach() {
    void* handle = dlopen(0, RTLD_GLOBAL | RTLD_NOW);
    ptrace_ptr_t ptrace_ptr = dlsym(handle, "ptrace");
    ptrace_ptr(PT_DENY_ATTACH, 0, 0, 0);
    dlclose(handle);
}

3)通过 syscall 调用

#import <sys/syscall.h>

#if !defined(PT_DENY_ATTACH)
#define PT_DENY_ATTACH 31
#endif

void disable_attach() {
    syscall(SYS_ptrace, PT_DENY_ATTACH, 0, 0, 0); // #define SYS_ptrace 26
}

4)通过汇编调用

内联 svc + ptrace 实现,相当于直接调用 ptrace(PT_DENY_ATTACH,0,0,0);

static __attribute__((always_inline)) void disable_attach() {
#ifdef __arm64__
    __asm__("mov X0, #0x1F");
    __asm__("mov X1, #0");
    __asm__("mov X2, #0");
    __asm__("mov X3, #0");
    __asm__("mov X16, #0x1A");
    __asm__("svc #0x80");
#endif
}

内联 svc + syscall + ptrace 实现,相当于 syscall(SYS_ptrace, PT_DENY_ATTACH, 0, 0, 0);

static __attribute__((always_inline)) void disable_attach() {
#ifdef __arm64__
    __asm__("mov X0, #0x1A");
    __asm__("mov X1, #0x1F");
    __asm__("mov X2, #0");
    __asm__("mov X3, #0");
    __asm__("mov X4, #0");
    __asm__("mov X16, #0");
    __asm__("svc #0x80");
#endif
}

2、sysctl

通过 sysctl 去查看当前进程的信息,看有没有这个标记位即可检查当前调试状态。

#import <sys/sysctl.h>

bool isBeingAttach() {
    size_t size = sizeof(struct kinfo_proc);
    struct kinfo_proc info;
    int ret = 0, name[4];
    memset(&info, 0, sizeof(struct kinfo_proc));
    
    name[0] = CTL_KERN;
    name[1] = KERN_PROC;
    name[2] = KERN_PROC_PID;
    name[3] = getpid();
    
    if (ret == (sysctl(name, 4, &info, &size, NULL, 0))) {
        return ret != 0;
    }
    return (info.kp_proc.p_flag & P_TRACED) ? YES : NO;
}