之前有写过针对iOS反调试的及其绕过的分析文章,动态绕过iOS内联svc反调试,本篇主要分享一下自己集成的一款方便绕过反调试的工具。
反调试与绕过的奇淫技巧
关于反调试&反反调试那些事
MochO文件结构
dyld链接加载流程
iOS inline Hook
Preferenceloader,applist模块集成
之前对反调试的绕过一般都是采用针对对应APP编写Hook插件来绕过反调试,或者是启动调试定位反调试点,修改寄存器nop汇编指令进行绕过,
前几天在使用RevealLoader的过程中,看到其下图界面,突发奇想是否可以开发一个通用的插件,选中某个APP即可绕过其反调试,不再需要逐个分析APP的反调试的反调试点,于是通过之前对反调试的一些积累集成了本工具。
通过阅读RevealLoader源码,发现想要实现在设置中添加每个APP的开关选项,需要依赖PreferenceLoader和AppList两个模块。
PreferenceLoader 是一个 MobileSubstrate 提供的模块,它可以让开发者在系统设置界面添加应用程序入口。 AppList 是一个让开发者获取系统中已安装应用信息的库。这两个模块相结合即可实现RevealLoader中呈现的效果。
插件开发使用MonKeyDev,新建Logos Tweak项目,在/Package/Library目录下新建PreferenceLoader/Preferences文件夹,文件夹中存放ProjectName.plist配置文件以及插件所需图标图片文件。
下图为ProjectName.plist文件的详细内容, ALSettingsPath指定插件设置对应的存储路径,ALSettingsKeyPrefix则是每个应用配置的前缀。
在control中的Depends字段添加AppList和PreferenceLoader两个依赖
代码中首先需要读取前面plist文件中保存的配置信息,通过前缀连接APP的bundleid来判断对应APP是否在设置中打开开关,如果打开,就进行下面的AntiDebug_Hook来绕过反调试。
反调试及其绕过的相关知识我在动态绕过iOS内联svc反调试中已经有过分享,本篇主要详细分析一下对svc 0x80进行Hook的流程。
这种方式主要是通过内嵌汇编的方式对ptrace等反调试函数进行调用,之前对其绕过的处理方式一般都是讲该段汇编代码以NOP进行代替,这种方式在定位到反调试调用地址的前提下很好用,在本工具中由于无法定位反调试地址,因此我们只能在text段中搜索svc 0x80指令,APP有时在正常逻辑中同样使用svc 0x80进行调用,如果统一NOP可能会造成崩溃的情况出现,因此我们需要在找到svc 0x80指令之后,对其进行Hook判断其传参,对反调试做出应对。
以下是hook_svc0x80的详细代码,代码Hook基于Hookzz目前升级为Dobby框架,以代码注释进行说明,想要深入理解svc 0x80指令获取流程,需要对MachO结构有一定了解。
目前测试多款APP均绕过其反调试检测,各位看官在使用过程中如遇到无法绕过的情况,请在评论区留言,先提前感谢大家帮我完善工具。
在测试一部iOS12.1.1中遇到在勾选对应APP之后,调试显示debugserver无法找到程序进程,在启动时进行挂载即可解决该问题,具体问题出现还在定位当中。
项目的github地址:https://github.com/yunnigu/AntiAntiDebug
本文仅用来学习交流,违法犯罪禁止使用,否则后果自付!如有侵权,请联系作者删除,本项目具体使用指南请参照网络安全法
NSDictionary
*
pref
=
[NSDictionary dictionaryWithContentsOfFile:@
"/var/mobile/Library/Preferences/com.yunnigu.AntiAntiDebug.plist"
];
NSString
*
keyPath
=
[NSString stringWithFormat:@
"AntiAntiDebugEnabled-%@"
, [[NSBundle mainBundle] bundleIdentifier]];
if
([[pref objectForKey:keyPath] boolValue]) {
NSLog(@
"-------AntiAntiDebug----------Start-------------"
);
/
/
ptrace
MSHookFunction((void
*
)MSFindSymbol(NULL,
"_ptrace"
),(void
*
)my_ptrace,(void
*
*
)&orig_ptrace);
/
/
dlsym
MSHookFunction((void
*
)dlsym,(void
*
)my_dlsym (void
*
*
)&orig_dlsym);
/
/
sysctl
MSHookFunction((void
*
)sysctl,(void
*
)my_sysctl,(void
*
*
)&orig_sysctl);
/
/
syscall
MSHookFunction((void
*
)syscall,(void
*
)my_syscall,(void
*
*
)&orig_syscall);
/
/
svc
0x80
hook_svc_x80();
NSLog(@
"[AntiAntiDebug] Module loaded!!!"
);
NSLog(@
"-------AntiAntiDebug----------End-------------"
);
}
NSDictionary
*
pref
=
[NSDictionary dictionaryWithContentsOfFile:@
"/var/mobile/Library/Preferences/com.yunnigu.AntiAntiDebug.plist"
];
NSString
*
keyPath
=
[NSString stringWithFormat:@
"AntiAntiDebugEnabled-%@"
, [[NSBundle mainBundle] bundleIdentifier]];
if
([[pref objectForKey:keyPath] boolValue]) {
NSLog(@
"-------AntiAntiDebug----------Start-------------"
);
/
/
ptrace
MSHookFunction((void
*
)MSFindSymbol(NULL,
"_ptrace"
),(void
*
)my_ptrace,(void
*
*
)&orig_ptrace);
/
/
dlsym
MSHookFunction((void
*
)dlsym,(void
*
)my_dlsym (void
*
*
)&orig_dlsym);
/
/
sysctl
MSHookFunction((void
*
)sysctl,(void
*
)my_sysctl,(void
*
*
)&orig_sysctl);
/
/
syscall
MSHookFunction((void
*
)syscall,(void
*
)my_syscall,(void
*
*
)&orig_syscall);
/
/
svc
0x80
hook_svc_x80();
NSLog(@
"[AntiAntiDebug] Module loaded!!!"
);
NSLog(@
"-------AntiAntiDebug----------End-------------"
);
}
void hook_svc_x80() {
zaddr svc_x80_addr;
zaddr curr_addr, text_start_addr, text_end_addr;
uint32_t svc_x80_byte
=
0xd4001001
;
/
/
首先通过dyld中的_dyld_get_image_header获取主程序的macho_header
const struct mach_header
*
header
=
_dyld_get_image_header(
0
);
/
/
获取__TEXT segment结构体
struct segment_command_64
*
seg_cmd_64
=
zz_macho_get_segment_64_via_name((struct mach_header_64
*
)header, (char
*
)
"__TEXT"
);
/
/
计算Macho内存中基地址到__TEXT偏移
zsize slide
=
(zaddr)header
-
(zaddr)seg_cmd_64
-
>vmaddr;
/
/
获取__text section结构体
struct section_64
*
sect_64
=
zz_macho_get_section_64_via_name((struct mach_header_64
*
)header, (char
*
)
"__text"
);
/
/
计算出__text实际地址
text_start_addr
=
slide
+
(zaddr)sect_64
-
>addr;
text_end_addr
=
text_start_addr
+
sect_64
-
>size;
curr_addr
=
text_start_addr;
/
/
循环查找svc
0x80
指令,进行Hook操作
while
(curr_addr < text_end_addr) {
svc_x80_addr
=
(zaddr)zz_vm_search_data((zpointer)curr_addr, (zpointer)text_end_addr, (zbyte
*
)&svc_x80_byte,
4
);
if
(svc_x80_addr) {
NSLog(@
"hook svc #0x80 at %p with aslr (%p without aslr)"
,
(void
*
)svc_x80_addr, (void
*
)(svc_x80_addr
-
slide));
ZzBuildHookAddress((void
*
)svc_x80_addr, (void
*
)(svc_x80_addr
+
4
),
hook_svc_pre_call, hook_svc_half_call, TRUE);
ZzEnableHook((void
*
)svc_x80_addr);
curr_addr
=
svc_x80_addr
+
4
;
}
else
{
break
;
}
}
}
struct section_64
*
zz_macho_get_section_64_via_name(sstruct segment_command_64
*
seg_cmd_64,
char
*
sect_name) {
struct section_64
*
sect_64;
sect_64
=
(struct section_64
*
)((zaddr)seg_cmd_64
+
sizeof(struct segment_command_64));
/
/
在__TEXT中循环查找section,返回__text section
for
(zsize j
=
0
; j < seg_cmd_64
-
>nsects;
j
+
+
, sect_64
=
(struct section_64
*
)((zaddr)sect_64
+
sizeof(struct section_64))) {
if
(!strcmp(sect_64
-
>sectname, sect_name)) {
return
sect_64;
}
}
}
zpointer zz_vm_search_data(const zpointer start_addr, zpointer end_addr, zbyte
*
data,
zsize data_len)
{
zpointer curr_addr;
if
(start_addr <
=
(zpointer)
0
)
printf(
"search address start_addr(%p) < 0"
, (zpointer)start_addr);
if
(start_addr > end_addr)
printf(
"search start_add(%p) < end_addr(%p)"
, (zpointer)start_addr, (zpointer)end_addr);
curr_addr
=
start_addr;
while
(end_addr > curr_addr)
{
if
(!memcmp(curr_addr, data, data_len))
{
return
curr_addr;
}
curr_addr
=
(zpointer)((zaddr)curr_addr
+
data_len);
}
return
0
;
}
struct segment_command_64
*
zz_macho_get_segment_64_via_name(struct mach_header_64
*
header,
char
*
segment_name) {
struct load_command
*
load_cmd;
struct segment_command_64
*
seg_cmd_64;
struct section_64
*
sect_64;
/
/
确定load_cmd地址
load_cmd
=
(struct load_command
*
)((zaddr)header
+
sizeof(struct mach_header_64));
/
/
循环load_cmd中的segment,返回__TEXT segment
for
(zsize i
=
0
; i < header
-
>ncmds;
i
+
+
, load_cmd
=
(struct load_command
*
)((zaddr)load_cmd
+
load_cmd
-
>cmdsize)) {
if
(load_cmd
-
>cmd
=
=
LC_SEGMENT_64) {
seg_cmd_64
=
(struct segment_command_64
*
)load_cmd;
if
(!strcmp(seg_cmd_64
-
>segname, segment_name)) {
return
seg_cmd_64;
}
}
}
return
NULL;
}
void hook_svc_pre_call(RegState
*
rs, ThreadStack
*
threadstack, CallStack
*
callstack) {
int
num_syscall;
int
request;
num_syscall
=
(
int
)(uint64_t)(rs
-
>general.regs.x16);
request
=
(
int
)(uint64_t)(rs
-
>general.regs.x0);
if
(num_syscall
=
=
SYS_syscall) {
int
arg1
=
(
int
)(uint64_t)(rs
-
>general.regs.x1);
if
(request
=
=
SYS_ptrace && arg1
=
=
PT_DENY_ATTACH) {
*
(unsigned
long
*
)(&rs
-
>general.regs.x1)
=
0
;
NSLog(@
"[AntiAntiDebug] catch 'SVC #0x80; syscall(ptrace)' and bypass"
);
}
}
else
if
(num_syscall
=
=
SYS_ptrace) {
request
=
(
int
)(uint64_t)(rs
-
>general.regs.x0);
if
(request
=
=
PT_DENY_ATTACH) {
*
(unsigned
long
*
)(&rs
-
>general.regs.x0)
=
0
;
NSLog(@
"[AntiAntiDebug] catch 'SVC-0x80; ptrace' and bypass"
);
}
}
else
if
(num_syscall
=
=
SYS_sysctl) {
STACK_SET(callstack, (char
*
)
"num_syscall"
, num_syscall,
int
);
STACK_SET(callstack, (char
*
)
"info_ptr"
, rs
-
>general.regs.x2, zpointer);
}
}
void hook_svc_half_call(RegState
*
rs, ThreadStack
*
threadstack, CallStack
*
callstack) {
if
(STACK_CHECK_KEY(callstack, (char
*
)
"num_syscall"
)) {
int
num_syscall
=
STACK_GET(callstack, (char
*
)
"num_syscall"
,
int
);
struct kinfo_proc
*
info
=
STACK_GET(callstack, (char
*
)
"info_ptr"
, struct kinfo_proc
*
);
if
(num_syscall
=
=
SYS_sysctl)
{
NSLog(@
"[AntiAntiDebug] catch 'SVC-0x80; sysctl' and bypass"
);
info
-
>kp_proc.p_flag &
=
~(P_TRACED);
}
}
}
void hook_svc_x80() {
zaddr svc_x80_addr;
zaddr curr_addr, text_start_addr, text_end_addr;
uint32_t svc_x80_byte
=
0xd4001001
;
/
/
首先通过dyld中的_dyld_get_image_header获取主程序的macho_header
const struct mach_header
*
header
=
_dyld_get_image_header(
0
);
/
/
获取__TEXT segment结构体
struct segment_command_64
*
seg_cmd_64
=
zz_macho_get_segment_64_via_name((struct mach_header_64
*
)header, (char
*
)
"__TEXT"
);
/
/
计算Macho内存中基地址到__TEXT偏移
zsize slide
=
(zaddr)header
-
(zaddr)seg_cmd_64
-
>vmaddr;
/
/
获取__text section结构体
struct section_64
*
sect_64
=
zz_macho_get_section_64_via_name((struct mach_header_64
*
)header, (char
*
)
"__text"
);
/
/
计算出__text实际地址
text_start_addr
=
slide
+
(zaddr)sect_64
-
>addr;
text_end_addr
=
text_start_addr
+
sect_64
-
>size;
curr_addr
=
text_start_addr;
/
/
循环查找svc
0x80
指令,进行Hook操作
while
(curr_addr < text_end_addr) {
svc_x80_addr
=
(zaddr)zz_vm_search_data((zpointer)curr_addr, (zpointer)text_end_addr, (zbyte
*
)&svc_x80_byte,
4
);
if
(svc_x80_addr) {
NSLog(@
"hook svc #0x80 at %p with aslr (%p without aslr)"
,
(void
*
)svc_x80_addr, (void
*
)(svc_x80_addr
-
slide));
ZzBuildHookAddress((void
*
)svc_x80_addr, (void
*
)(svc_x80_addr
+
4
),
hook_svc_pre_call, hook_svc_half_call, TRUE);
ZzEnableHook((void
*
)svc_x80_addr);
curr_addr
=
svc_x80_addr
+
4
;
}
else
{
break
;
}
}
}
struct section_64
*
zz_macho_get_section_64_via_name(sstruct segment_command_64
*
seg_cmd_64,
char
*
sect_name) {
struct section_64
*
sect_64;
sect_64
=
(struct section_64
*
)((zaddr)seg_cmd_64
+
sizeof(struct segment_command_64));
/
/
在__TEXT中循环查找section,返回__text section
for
(zsize j
=
0
; j < seg_cmd_64
-
>nsects;
j
+
+
, sect_64
=
(struct section_64
*
)((zaddr)sect_64
+
sizeof(struct section_64))) {
if
(!strcmp(sect_64
-
>sectname, sect_name)) {
return
sect_64;
}
}
}
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2021-6-29 11:55
被Night_elf编辑
,原因: