49fcef44fafc6f56d1a474d0353b1b35
安全攻与防篇:调试与反调试下篇之 sysctl

1.防:sysctl 反调试

前面我们介绍了 ptrace(《安全攻与防篇:调试与反调试上篇之 ptrace》) 进行调试的攻与防,这里介绍一个新的系统函数:sysctl,进行调试的攻与防学习。

我们还是新建一个工程,添加监控进程调试代码:

#import <sys/sysctl.h>

static dispatch_source_t timer;

/// 检查进程是否被调试
BOOL gofProcIsDebugger(){
    int queryInfo[4];  // 查询字节码的信息数组
    queryInfo[0] = CTL_KERN;  // 内核(kernel)查询
    queryInfo[1] = KERN_PROC;  // 查询进程信息
    queryInfo[2] = KERN_PROC_PID;  // 根据进程 ID 查询(进程 ID)
    queryInfo[3] = getpid();  // 当前进程 ID

    struct kinfo_proc resultInfo;  // 保存结果信息的结构体
    size_t resultInfoSize = sizeof(resultInfo);  // 结果信息结构体的大小

    /**
     sysctl 方法重要参数说明
     参数1:查询字节码的信息数组
     参数2:查询字节码的信息数组的大小
     参数3:结果信息的结构体指针
     参数4:结果信息的结构体大小的指针
     */
    int errorCode = sysctl(queryInfo, sizeof(queryInfo)/sizeof(*queryInfo), &resultInfo, &resultInfoSize, 0, 0);
    assert(errorCode == 0);  // 0 表示没有错误

    return ((resultInfo.kp_proc.p_flag & P_TRACED) != 0);
}

/// 定时检查进程是否被调试
void gofDebugCheck(){
    timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 5.0 * NSEC_PER_SEC, 0.0 * NSEC_PER_SEC);
    dispatch_source_set_event_handler(timer, ^{
        if (gofProcIsDebugger()) {
            NSLog(@"当前进程正在被调试");
            // 进行其他控制或者退出程序
        } else {
            NSLog(@"进程正常执行,没有被调试");
        }
    });
    dispatch_resume(timer);
}

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    gofDebugCheck();
}

@end

运行工程,可以看到 Xcode 中运行时,可以检测到进程被调试的输出。

2.攻:反反调试

sysctl 是一个系统函数,我们同样可以使用 fishhook 来进行破解。添加一个 Framework,进行代码的注入。
```

import "fishhook.h"

import

@implementation GofInjectSysctl

//原始函数的地址
int (*sysSysctl)(int *, u_int, void *, size_t *, void *, size_t);

//定义新的函数
int gofSysctl(int * queryInfo, u_int queryInfolen, void * resultInfo, size_t * resultInfosize, void * newinfo, size_t newinfosize){
if (queryInfolen == 4
&& queryInfo[0] == CTL_KERN
&& queryInfo[1] == KERN_PROC
&& queryInfo[2] == KERN_PROC_PID
&& resultInfo
&& (int)*resultInfosize == sizeof(struct kinfo_proc))
{
int err = sysSysctl(queryInfo, queryInfolen, resultInfo, resultInfosize, newinfo, newinfosize);
// 根据 resultInfo 判断
struct kinfo_proc * myinfo = (struct kinfo_proc *)resultInfo;
// 进程被调试
if ((myinfo->kp_proc.p_flag & P_TRACED) != 0) {
// 使用异或取反
myinfo->kp_proc.p_flag ^= P_TRACED;
}

    return err;
}

return sysSysctl(queryInfo, queryInfolen, resultInfo, resultInfosize, newinfo, newinfosize);

}

  • (void)load {
    rebind_symbols((struct rebinding[1]){{"sysctl", gofSysctl, (void *)&sysSysctl}}, 1);
    }
top Created with Sketch.