(三) Ptrace与反调试

1. 你好Ptrace

1.1 系统调用

系统调用是由系统核心提供的强大底层服务,是用户系统框架(比如C的stdlib、Cocoa、UIKit和你自己的框架)的建立基础。

1.2 附着的基础:ptrace

我们利用dtrace来监视ptrace的调用,并把参数打印出来。

sudo dtrace -qn 'syscall::ptrace:entry { printf("%s(%d, %d, %d, %d) from %s\n", probefunc, arg0, arg1, arg2, arg3, execname); }'

之后我们新建一个tab用LLDB附着Finder

lldb -n Finder
(lldb) process attach --name "Finder"
//之前的tab输出
ptrace(14, 358, 0, 0) from debugserver

我们看到有一个叫debugserver的进程调用了ptrace,并且附着到了Finder的进程上。debugserver是如何被调用的?我们用的是LLDB而不是debugserver,现在debugserver进程还是活跃的么?

要回答这些问题,我们新开一个tab,再输入

 ~> pgrep debugserver
2917

LLDB如果成功附着且还在运行,我们看到了一个输出2917,代表了debugserver的进程ID,即PID,说明debugserver还在运行。我们来看看debugserver是如何启动起来的。

 ~> ps -fp `pgrep -x debugserver`
  UID   PID  PPID   C STIME   TTY           TIME CMD
  502  2917  2916   0 10:28AM ttys001    0:00.21 /Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/debugserver --fd=5 --native-regs --setsid

这个命令打印了debugserver的完整路径和启动这个进程的所有参数。那哪个进程启动了它呢?

 ~> ps -o ppid= $(pgrep -x debugserver)
 2916
 ~> ps -a 2916
  PID TTY           TIME CMD
 2916 ttys001    0:08.60 /Applications/Xcode.app/Contents/Developer/usr/bin/lldb -n Finder

正如你所看到的,LLDB启动了debugserver这个进程,然后用ptrace系统调用把它自己附着到了Finder上。

1.3 ptrace的参数

虽然我们可以看到ptrace的执行,但这些都是些数字,我们需要在<sys/ptrace.h>中查看它们的具体含义。

//mac项目中运行下面的代码
while true {
  sleep(2)
  print("helloptrace")
}

ptrace监听tab窗我们可以看到

ptrace(14, 3365, 0, 0) from debugserver
ptrace(13, 3365, 7939, 0) from debugserver

暂停工程,我们来看看<sys/ptrace.h>头文件,ptrace的方法定义。

//$1: 是你想ptrace做什么
//$2: 你想应用到哪个pid上
//$3、$4取决于$1是什么
int ptrace(int _request, pid_t _pid, caddr_t _addr, int _data);

那么

// #define PT_ATTACHEXC    14      /* attach to running process with signal exception */
ptrace(14, 3365, 0, 0) from debugserver

关于PT_ATTACHEXC的详细信息可以通过man ptrace命令在终端中查看。这个请求可以让一个进程附着到另一个不相关的进程,它只需要要跟踪的pid,其他参数不需要。

//#define PT_THUPDATE     13      /* signal for thread# */
ptrace(13, 3365, 7939, 0) from debugserver

至于13的PT_THUPDATE是和怎么控制进程相关的,在我们的例子里面就是debugserver;处理传递给被控制进程的UNIX信号和Mach消息,我们的例子里面就是,helloptrace。这个特殊的ptrace行为涉及到Mach核心怎么在内部实现ptrace处理的实现细节有关。

1.4 创建一个附着问题

进程实际上可以使用PT_DENY_ATTACH请求来拒绝被附着。这通常被用来作为一种反调试机制来保护我们的程序被逆向。

我们加上ptrace(PT_DENY_ATTACH, 0, nil, 0)来试一试。

ptrace(PT_DENY_ATTACH, 0, nil, 0)
while true {
  sleep(2)
  print("helloptrace")
}

//运行结果
Program ended with exit code: 45

这是因为Xcode启动时helloptrace会自动启动LLDB附着。如果你拒绝附着,那么LLDB就会提前退出,程序结束运行。

1.5 玩一玩PT_DENY_ATTACH

通常,开发者会在程序中加入ptrace(PT_DENY_ATTACH, 0, 0, 0),通常就在main函数里面。
LLDB有一个参数-w来等待一个进程启动。那么就可以在程序启动还没有执行到ptrace(PT_DENY_ATTACH, 0, 0, 0)之前进行附着,修改或忽略ptrace

~> sudo lldb -n "helloptrace" -w
Password:
(lldb) process attach --name "helloptrace" --waitfor

然后我们在终端的新tab中运行helloptrace,就会发现LLDB成功附着了。

Process 3575 stopped
* thread #1, stop reason = signal SIGSTOP
    frame #0: 0x00000001142cc34e dyld`getattrlist + 10
dyld`getattrlist:
->  0x1142cc34e <+10>: jae    0x1142cc358               ; <+20>
    0x1142cc350 <+12>: mov    rdi, rax
    0x1142cc353 <+15>: jmp    0x1142ca769               ; cerror_nocancel
    0x1142cc358 <+20>: ret
Target 0: (helloptrace) stopped.

我们在libsystem_kernel.dylib中下一个ptrace的断点,然后继续运行。

(lldb) rb ptrace -s libsystem_kernel.dylib
Breakpoint 1: no locations (pending).
WARNING:  Unable to resolve breakpoint to any actual locations.
(lldb) continue
Process 3575 resuming
1 location added to breakpoint 1
Process 3575 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x00007fff662caa44 libsystem_kernel.dylib`__ptrace
libsystem_kernel.dylib`__ptrace:
->  0x7fff662caa44 <+0>:  xor    rax, rax
    0x7fff662caa47 <+3>:  lea    r11, [rip + 0x29cd7eda]   ; errno
    0x7fff662caa4e <+10>: mov    dword ptr [r11], eax
    0x7fff662caa51 <+13>: mov    eax, 0x200001a
Target 0: (helloptrace) stopped.

我们断在了ptrace将要执行的时候,我们可以直接用LLDB提前返回,不执行这个函数。

(lldb) thread return 0
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x000000010e0d2a35 helloptrace`main at main.swift:31:1
   28
   29   import Foundation
   30
-> 31   ptrace(PT_DENY_ATTACH, 0, nil, 0)
   32
   33   while true {
   34     sleep(2)
(lldb) continue
Process 3575 resuming

我们可以看到,helloptrace正常打印了。

helloptrace

我们也可以修改寄存器的值,下面是前四个参数的值,可以看到RDI中是31(PT_DENY_ATTACH)。再把RDI中的值替换为0,再继续运行,可以达到同样的效果。

(lldb) p $rdi
(unsigned long) $1 = 31
(lldb) p $rsi
(unsigned long) $2 = 0
(lldb) p $rdx
(unsigned long) $3 = 0
(lldb) p $rcx
(unsigned long) $4 = 0
(lldb) p $rdi = 0
(unsigned long) $6 = 0
(lldb) register read rdi
     rdi = 0xffffffffffffffff
(lldb) continue
Process 3635 resuming

当然,如果你还会其他的方法也可以,比如利用fishhook替换ptrace的行为。

1.6 其他反调试技术

长久以来,iTunes都是用PT_DENY_ATTACH的方式来反调试的。iTunes v12.7.0的时候,开始用另一种方式来反调试了。

它使用sysctl函数来检测它是否在被反调试,如果是的话就关闭程序。sysctlptrace一样是另一个系统调用。iTunes在运行时利用一个NSTimer来反复调用sysctl执行检测。

下面是一个简单的Swift代码来展示iTunes做了什么:

let mib = UnsafeMutablePointer<Int32>.allocate(capacity: 4)
mib[0] = CTL_KERN
mib[1] = KERN_PROC
mib[2] = KERN_PROC_PID
mib[3] = getpid()
var size: Int = MemoryLayout<kinfo_proc>.size
var info: kinfo_proc? = nil
sysctl(mib, 4, &info, &size, nil, 0)
if (info.unsafelyUnwrapped.kp_proc.p_flag & P_TRACED) > 0 {
    exit(1)
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容