返回

反调试&反反调试 -- 利用sysctl检测调试器是否存在

IOS

前言

在软件开发过程中,调试器是一个非常有用的工具,它可以帮助我们快速定位和修复代码中的错误。然而,在某些情况下,我们可能希望我们的程序在被调试时能够正常运行,而不被调试器所干扰。这时,我们就需要用到反调试技术。

反调试

反调试技术有很多种,其中一种常用的方法就是利用sysctl函数检测调试器是否存在。sysctl函数可以获取当前进程的各种信息,包括是否正在被调试。如果sysctl函数返回的值包含了CTL_DEBUG_NAME的值,则说明该进程正在被调试。

#include <sys/sysctl.h>

int main() {
  int mib[4];
  size_t len;

  mib[0] = CTL_KERN;
  mib[1] = KERN_PROC;
  mib[2] = KERN_PROC_PID;
  mib[3] = getpid();

  len = sizeof(int);
  sysctl(mib, 4, &mib, &len, NULL, 0);

  if (mib[3] & CTL_DEBUG_NAME) {
    printf("This process is being debugged.\n");
  } else {
    printf("This process is not being debugged.\n");
  }

  return 0;
}

反反调试

当我们使用反调试技术时,调试器可能会检测到我们的反调试行为并采取相应的措施来绕过我们的反调试技术。这时,我们就需要用到反反调试技术。

反反调试技术有很多种,其中一种常用的方法就是利用fishhook交换掉系统的sysctl函数。fishhook是一个开源的库,它可以帮助我们动态地修改函数的实现。

#include <fishhook.h>

static int (*orig_sysctl)(int*, size_t, void*, size_t*, void*, size_t);

static int my_sysctl(int* name, size_t namelen, void* oldp, size_t* oldlenp, void* newp, size_t newlen) {
  if (name[0] == CTL_KERN && name[1] == KERN_PROC && name[2] == KERN_PROC_PID && name[3] == getpid()) {
    name[3] &= ~CTL_DEBUG_NAME;
  }

  return orig_sysctl(name, namelen, oldp, oldlenp, newp, newlen);
}

__attribute__((constructor)) static void init() {
  fishhook_replace(sysctl, my_sysctl, (void**)&orig_sysctl);
}

这段代码首先将原始的sysctl函数保存到orig_sysctl变量中,然后将my_sysctl函数替换掉原始的sysctl函数。在my_sysctl函数中,我们判断sysctl函数是否正在被用来获取当前进程的调试信息,如果是,我们就将调试信息中的CTL_DEBUG_NAME标志位清除。这样,调试器就无法检测到当前进程正在被调试。

结语

反调试和反反调试技术在某些情况下是非常有用的,但我们也应该谨慎使用这些技术。因为这些技术可能会影响程序的正常运行,甚至可能会导致程序崩溃。