动态绕过iOS内联svc反调试

之前在jmpews大神的反调试与绕过的奇淫技巧以及AloneMonkey大神的关于反调试&反反调试那些事这两篇文章中学习到不少关于iOS反调试绕过的姿势技巧,本篇主要记录一下自己在实际逆向过程中遇到的关于svc内联反调试的绕过过程。

iOS反调试简介

iOS的反调试目前常见只有几种,主要是ptrace、sysctl、syscall几种,这里我就不照本宣科的去介绍这几种反调试的原理了,我上面提到的两位大神的文章中有十分详细的说明。

由于以上三种方式的反调试相对比较容易绕过,一般通过Tweak编写hook插件就可以解决了,下面贴上AloneMonkey的一个脚本,足以绕过这些反调试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#import <substrate.h>
#import <sys/sysctl.h>
static int (*orig_ptrace) (int request, pid_t pid, caddr_t addr, int data);
static int my_ptrace (int request, pid_t pid, caddr_t addr, int data){
if(request == 31){
NSLog(@"[AntiAntiDebug] - ptrace request is PT_DENY_ATTACH");
return 0;
}
return orig_ptrace(request,pid,addr,data);
}
static void* (*orig_dlsym)(void* handle, const char* symbol);
static void* my_dlsym(void* handle, const char* symbol){
if(strcmp(symbol, "ptrace") == 0){
NSLog(@"[AntiAntiDebug] - dlsym get ptrace symbol");
return (void*)my_ptrace;
}
return orig_dlsym(handle, symbol);
}
static int (*orig_sysctl)(int * name, u_int namelen, void * info, size_t * infosize, void * newinfo, size_t newinfosize);
static int my_sysctl(int * name, u_int namelen, void * info, size_t * infosize, void * newinfo, size_t newinfosize){
int ret = orig_sysctl(name,namelen,info,infosize,newinfo,newinfosize);
if(namelen == 4 && name[0] == 1 && name[1] == 14 && name[2] == 1){
struct kinfo_proc *info_ptr = (struct kinfo_proc *)info;
if(info_ptr && (info_ptr->kp_proc.p_flag & P_TRACED) != 0){
NSLog(@"[AntiAntiDebug] - sysctl query trace status.");
info_ptr->kp_proc.p_flag ^= P_TRACED;
if((info_ptr->kp_proc.p_flag & P_TRACED) == 0){
NSLog(@"[AntiAntiDebug] trace status reomve success!");
}
}
}
return ret;
}
static void* (*orig_syscall)(int code, va_list args);
static void* my_syscall(int code, va_list args){
int request;
va_list newArgs;
va_copy(newArgs, args);
if(code == 26){
request = (long)args;
if(request == 31){
NSLog(@"[AntiAntiDebug] - syscall call ptrace, and request is PT_DENY_ATTACH");
return nil;
}
}
return (void*)orig_syscall(code, newArgs);
}
%ctor{
MSHookFunction((void *)MSFindSymbol(NULL,"_ptrace"),(void*)my_ptrace,(void**)&orig_ptrace);
MSHookFunction((void *)dlsym,(void*)my_dlsym,(void**)&orig_dlsym);
MSHookFunction((void *)sysctl,(void*)my_sysctl,(void**)&orig_sysctl);
MSHookFunction((void *)syscall,(void*)my_syscall,(void**)&orig_syscall);
NSLog(@"[AntiAntiDebug] Module loaded!!!");
}

svc内联反调试

所谓svc内联其实就是通过svc汇编实现对ptrace、syscall的调用,防止攻击者直接通过hook函数绕过反调试,增加反调试绕过难度。

如何确定iOS应用是否采用svc内联反调试

调用svc实现ptrace的汇编如下:

1
2
3
4
5
6
"mov X0, #31"
"mov X1, #0"
"mov X2, #0"
"mov X3, #0"
"mov w16, #26"
"svc #0x80"

调用svc通过syscall实现ptrace的汇编如下:

1
2
3
4
5
6
7
"mov X0, #26"
"mov X1, #31"
"mov X2, #0"
"mov X3, #0"
"mov X4, #0"
"mov w16, #0"
"svc #0x80"

在动态调试iOS过程中如果遇到下面情况:

二话不说先祭出上文的那个hook插件,如果插件不好使,直接通过IDA分析主程序在全局搜索SVC 0x80,当然也有可能不在主程序中,dylib中也是有可能的。不巧的是我在主程序中搜到了。

绕过svc反调试

在找的这两段代码之后,想起大佬们说过遇到SVC 0x80无脑nop就好了,但是在静态情况下nop之后放入运行时程序中或者重打包安装都并不好使怎么办,不要慌,经过本人多次尝试百试百灵的办法来了。

反调试检测必然是在程序启动初始化的过程中,这里采取一个取巧的办法,在手机点开应用的瞬间,通过debugserver挂载该APP

之后在上面找到的地址下断点,通过memory write address 0x1f 0x20 0x03 0xd5将svc指令修改为nop,将SYS_ptrace和SYS_syscall都修改完成后,删除断点,c运行发现反调试以及绕过了。

有钱的捧个钱场
0%