Ptrace在iOS上反调试的利用和破解

调试器究竟是怎么工作的?如何阻止一个进程attach(挂载)到app上以及又如何破解这些保护(所谓反调试和反反调试)?

关于系统调用

ptrace是一个系统调用。那系统调用是什么东东呢?它是一个系统提供的很强大的底层服务。用户层的框架是构建在system call之上的。
macOS Sierra大约提供了500个系统调用。通过以下命令来了解你系统上的系统调用的个数:
➜ ~ sudo dtrace -ln 'syscall:::entry' | wc -l
这个命令使用了另外一个更强大的工具叫DTrace,暂不详谈它。

调试的基础--ptrace

在命令行中执行:(注意必须关闭SIP(system integrity protection))
➜ ~ sudo dtrace -qn 'syscall::ptrace:entry { printf("%s(%d, %d, %d, %d) from %s\n", probefunc, arg0, arg1, arg2, arg3, execname); }'
这个命令创建了一个DTrace探针,它在每次ptrace函数执行时都会得到执行。
在命令行另外一个Tab中执行:
➜ ~ lldb -n Finder
此时dtrace那个tab会输出:
ptrace(14, 283, 0, 0) from debugserver
这看起来看起来像是一个名字叫debugserver的进程调用了ptrace并attach到了Finder进程上。
但debugserver是如何调用的呢?我们通过LLDB来attach到Finder,并不是debugserver。另外,这个debugserver进程是否还存活呢?
➜ ~ pgrep debugserver ==> 43474
既然这个进程存在,我们就来观察下它是如何启动以及有哪些启动参数

➜  ~ ps -fp `pgrep -x debugserver
  UID   PID  PPID   C STIME   TTY           TIME CMD
  501 43474 43473   0  4:24PM ttys004    0:00.15 /Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/debugserver --native-regs --setsid --reverse-connect 127.0.0.1:63719
cmd: /path/to/debugserver --native-regs --setsid --reverse-connect 127.0.0.1:63719

接下来看看如果我们去掉或修改一些启动参数会造成什么影响。去掉--reverse-connect 127.0.0.1:63719会发生什么事情呢
查看哪个进程启动了debugserver:

➜  ~ ps -o ppid= $(pgrep -x debugserver)
43473
➜  ~ ps -a 43473
  PID TTY           TIME CMD
43473 ttys004    0:05.19 /Applications/Xcode.app/Contents/Developer/usr/bin/lldb -n Finder
# 到这里可以看到是LLDB启动了debugserver进程,然后debugserver通过ptrace系统调用把自己attach到Finder上。

ptrace的参数

创建Mac上的命令行应用,执行这样一段Swift代码:

import Foundation

// ptrace(PT_DENY_ATTACH, 0, nil, 0)  # 当前并不需要,只是用来帮助跳转到头文件

while true {
  sleep(2)
  print("Hello, Ptrace")
}

程序执行后又捕捉到2次ptrace调用:

ptrace(14, 45762, 0, 0) from debugserver
ptrace(13, 45762, 5891, 0) from debugserver

点击进入可以看到ptrace所在的头文件,其定义如下:

#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 */

int ptrace(int _request, pid_t _pid, caddr_t _addr, int _data);

第一个参数指明要ptrace要做的事情;第二个参数指明了要操作进程的PID,第三个和第四个取决于第一个参数。
可以看到上面ptrace的输出的14,就是PT_ATTACHEXC。可以通过man ptrace然后搜索它来查看这个具体是什么意思:

This request allows a process to gain control of an otherwise unrelated process and begin tracing it. It does not need any cooperation from the to-be-traced process. In this case, pid specifies the process ID of the to-be-traced process, and the other two arguments are ignored.

基于这个信息,可以知道为何会发生了第一次的ptrace调用了。
至于13的PT_THUPDATE,苹果并没有给出更多说明。它大概与控制进程(lldb)如何处理传递给被控制进程(Xcode run的app)的Unix信号和Mach消息有关。

如何反调试

对上面代码中的被注释行取消注释:ptrace(PT_DENY_ATTACH, 0, nil, 0)
Xcode中Run起来后会发现debug console打印出这个:Program ended with exit code: 45
这是因为Xcode默认启动程序的同时用lldb attach上去。如果执行ptrace函数并带上PT_DENY_ATTACH参数,lldb就会提前退出,程序会中止执行。如果你尝试单独运行程序,稍后再去attach,lldb同样会失败,程序依旧正常地运行下去不受影响。
有很多MacOS的应用就是用了这种方法来达到反调试。然而,这种方式还是非常容易被破解的。

如何反反调试

开发者要达到反调试的目的,必然是在某个地方(大多数还是在main函数)执行了ptrace(PT_DENY_ATTACH, 0, 0, 0)。所以反反调试的思路非常简单,就是阻止这个执行的发生。
既然lldb有-w这个选项来等待一个进程的启动,你可以使用lldb来捕获到一个进程的启动并在程序执行到ptrace命令之前修改或忽略PT_DENY_ATTACH命令。
命令行执行:➜ ~ sudo lldb -n "helloptrace" -w。这里用sudo是因为lldb的一个bug,当你让lldb等待某个进程的启动时不用sudo会出错。
找到上述项目的二进制文件,拖到命令行中执行,然后lldb就应该能够成功attach上去:

➜  ~ sudo lldb -n "helloptrace" -w
(lldb) process attach --name "helloptrace" --waitfor
Process 8336 stopped
* thread #1, stop reason = signal SIGSTOP
    frame #0: 0x0000000109522b9a dyld`__ioctl + 10
dyld`__ioctl:
->  0x109522b9a <+10>: jae    0x109522ba4               ; <+20>
    0x109522b9c <+12>: mov    rdi, rax
    0x109522b9f <+15>: jmp    0x109522325               ; cerror
    0x109522ba4 <+20>: ret

Executable module set to "/Users/gogleyin/Library/Developer/Xcode/DerivedData/helloptrace-bjtaxdebpzdyraaogpbcrihdgwku/Build/Products/Debug/helloptrace".
Architecture set to: x86_64h-apple-macosx.

创建如下断点:
(lldb) rb ptrace -s libsystem_kernel.dylib
continue继续执行后你就会在ptrace函数将要执行时停下来。你可以用lldb来让程序不执行那个函数并提前返回:
(lldb) thread return 0
continue继续执行,一个反反调试就达成了!虽然程序进入了ptrace函数,但你是告诉lldb让它提前返回使得函数逻辑没有得到执行。

后续

但我们并不知道一个进程在什么时候执行了ptrace系统调用时,上面的方法就有些捉急了。此时又该怎样反反调试呢?两者孰能技高一筹,请看后续文章。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,755评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,369评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,799评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,910评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,096评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,159评论 3 411
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,917评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,360评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,673评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,814评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,509评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,156评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,123评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,641评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,728评论 2 351

推荐阅读更多精彩内容