出于应用安全防护的目的,安全开发人员为防止函数被HOOK(inlinehook/fishhook),一般会对敏感函数做SVC调用,如access/stat/open等函数。做SVC调用的方式明显由于直接调用和动态dlsym调用,隐蔽性得到增强,且Hook难度增加。具体实施形式可分为为裸函数或内联汇编。裸函数方式,即为一个独立函数,其他函数通过传递系统调用号和参数调用该函数内联汇编方式,会将SVC内联到每个调用函数中。这两者相比较,各有优势。裸函数方式,如果攻击者对此函数进行hook,可以很方便的通过内存校验检测出问题(如果直接用变量访问这段内存,也是很容易逆向分析,因此实际操作时可以使用一些间接引用技巧)。但无论如何,因为iOS上非越狱环境无法动态创建并执行代码,因此SVC这条汇编指令一定是存在于内存中,最常见的就是svc 0x80
和svc 0x50
(注意这个指令的立即数是默认忽略的,因此svc 0
或者svc 0xffff
效果都是一样的),对应机器码为01 10 00 D4
,通常在逆向分析时,直接搜此二进制即可直达检测的关键处。为了对抗svc指令的检测和修改,缓解的方式也很多,比如:
本文提出一种方式,可以更好的隐藏svc调用。libsystem_kernel.dylib
是具体实现系统调用的动态库,通过逆向可以发现其包含大量的svc指令,那取巧的办法就是获取到这里svc的地址,并包装成函数进行调用,即可神不知鬼不觉达到隐藏svc并进行系统调用的目的。
arm64上具体实现代码如下,此代码通过获取libsystem_kernel模块地址,并爆搜指令的方式获取svc,并实现裸函数和内联函数两种调用方式,通过逆向可以发现,程序中并没有svc指令,完美达到目的!:
需要注意的是上述代码没有进行错误处理,这个实现是通过BCC指令,具体可以参照libsystem_kernel的反汇编。
__text:
00000002382DA4AC
EXPORT ___gettimeofday
__text:
00000002382DA4AC
___gettimeofday ; CODE XREF: _prepare_times_array_and_attrs
+
74
↑p
__text:
00000002382DA4AC
__text:
00000002382DA4AC
var_10
=
-
0x10
__text:
00000002382DA4AC
__text:
00000002382DA4AC
02
00
80
D2 MOV X2,
__text:
00000002382DA4B0
90
0E
80
D2 MOV X16,
__text:
00000002382DA4B4
01
10
00
D4 SVC
0x80
__text:
00000002382DA4B8
C3
00
00
54
B.CC locret_2382DA4D0
__text:
00000002382DA4BC
FD
7B
BF A9 STP X29, X30, [SP,
__text:
00000002382DA4C0
FD
03
00
91
MOV X29, SP
__text:
00000002382DA4C4
5E
D9 FF
97
BL _cerror_nocancel
__text:
00000002382DA4C8
BF
03
00
91
MOV SP, X29
__text:
00000002382DA4CC
FD
7B
C1 A8 LDP X29, X30, [SP
+
0x10
+
var_10],
__text:
00000002382DA4D0
__text:
00000002382DA4D0
locret_2382DA4D0 ; CODE XREF: ___gettimeofday
+
C↑j
__text:
00000002382DA4D0
C0
03
5F
D6 RET
__text:
00000002382DA4AC
EXPORT ___gettimeofday
__text:
00000002382DA4AC
___gettimeofday ; CODE XREF: _prepare_times_array_and_attrs
+
74
↑p
__text:
00000002382DA4AC
__text:
00000002382DA4AC
var_10
=
-
0x10
__text:
00000002382DA4AC
__text:
00000002382DA4AC
02
00
80
D2 MOV X2,
__text:
00000002382DA4B0
90
0E
80
D2 MOV X16,
__text:
00000002382DA4B4
01
10
00
D4 SVC
0x80
__text:
00000002382DA4B8
C3
00
00
54
B.CC locret_2382DA4D0
__text:
00000002382DA4BC
FD
7B
BF A9 STP X29, X30, [SP,
__text:
00000002382DA4C0
FD
03
00
91
MOV X29, SP
__text:
00000002382DA4C4
5E
D9 FF
97
BL _cerror_nocancel
__text:
00000002382DA4C8
BF
03
00
91
MOV SP, X29
__text:
00000002382DA4CC
FD
7B
C1 A8 LDP X29, X30, [SP
+
0x10
+
var_10],
__text:
00000002382DA4D0
__text:
00000002382DA4D0
locret_2382DA4D0 ; CODE XREF: ___gettimeofday
+
C↑j
__text:
00000002382DA4D0
C0
03
5F
D6 RET
intptr_t get_text_range(void
*
base, intptr_t off, uint32_t
*
psize) {
mach_header_t
*
pmh
=
(mach_header_t
*
)base;
load_command
*
plc
=
(load_command
*
)(pmh
+
1
);
for
(
int
i
=
0
; i < pmh
-
>ncmds; i
+
+
) {
if
(plc
-
>cmd !
=
LC_SEGMENT_CURARCH) {
plc
=
(struct load_command
*
)((unsigned char
*
)plc
+
plc
-
>cmdsize);
continue
;
}
segment_command_t
*
psc
=
(segment_command_t
*
)plc;
if
(
0
=
=
strcmp(psc
-
>segname,
"__TEXT"
)) {
if
(psize)
*
psize
=
(uint32_t)psc
-
>vmsize;
return
(intptr_t)(psc
-
>vmaddr
+
off);
}
plc
=
(struct load_command
*
)((unsigned char
*
)plc
+
plc
-
>cmdsize);
}
return
-
1
;
}
static void
*
find_svc() {
for
(
int
i
=
0
; i < _dyld_image_count(); i
+
+
) {
const char
*
path
=
_dyld_get_image_name(i);
void
*
base
=
(void
*
)_dyld_get_image_header(i);
intptr_t slide
=
_dyld_get_image_vmaddr_slide(i);
if
(
0
!
=
strcmp(path,
"/usr/lib/system/libsystem_kernel.dylib"
)) {
continue
;
}
NSLog(@
"%s"
, path);
intptr_t text_base
=
0
;
uint32_t text_size
=
0
;
text_base
=
get_text_range(base, slide, &text_size);
for
(
int
i
=
0
; i < text_size
/
4
; i
+
=
4
) {
uint32_t
*
addr
=
(uint32_t
*
)(text_base
+
i
*
4
);
if
(
*
addr
=
=
0xd4001001
) {
/
/
for
arm64
return
(void
*
)addr;
}
}
}
return
0
;
}
static void
*
svc_addr
=
0
;
naked
int
asm_getpid1() {
__asm(
"mov x16, 0x14 \n"
"mov x8, %[svc_addr] \n"
"br x8 \n"
::[svc_addr]
"r"
(svc_addr):
);
}
finline
int
asm_getpid2() {
int
ret
=
0
;
__asm(
"mov x16, 0x14 \n"
"mov x8, %[svc_addr] \n"
"blr x8 \n"
"mov %[ret], x0 \n"
:[ret]
"=r"
(ret):[svc_addr]
"r"
(svc_addr):
);
return
ret;
}
int
main(
int
argc, char
*
argv[]) {
svc_addr
=
find_svc();
NSLog(@
"asm_pid1=%d, asm_pid2=%d, real_pid=%d"
, asm_getpid1(), asm_getpid2(), getpid());
NSString
*
appDelegateClassName;
@autoreleasepool
{
appDelegateClassName
=
NSStringFromClass([AppDelegate
class
]);
}
return
UIApplicationMain(argc, argv, nil, appDelegateClassName);
}
intptr_t get_text_range(void
*
base, intptr_t off, uint32_t
*
psize) {
mach_header_t
*
pmh
=
(mach_header_t
*
)base;
load_command
*
plc
=
(load_command
*
)(pmh
+
1
);
for
(
int
i
=
0
; i < pmh
-
>ncmds; i
+
+
) {
if
(plc
-
>cmd !
=
LC_SEGMENT_CURARCH) {
plc
=
(struct load_command
*
)((unsigned char
*
)plc
+
plc
-
>cmdsize);
continue
;
}
segment_command_t
*
psc
=
(segment_command_t
*
)plc;
if
(
0
=
=
strcmp(psc
-
>segname,
"__TEXT"
)) {
if
(psize)
*
psize
=
(uint32_t)psc
-
>vmsize;
return
(intptr_t)(psc
-
>vmaddr
+
off);
}
plc
=
(struct load_command
*
)((unsigned char
*
)plc
+
plc
-
>cmdsize);
}
return
-
1
;
}
static void
*
find_svc() {
for
(
int
i
=
0
; i < _dyld_image_count(); i
+
+
) {
const char
*
path
=
_dyld_get_image_name(i);
void
*
base
=
(void
*
)_dyld_get_image_header(i);
intptr_t slide
=
_dyld_get_image_vmaddr_slide(i);
if
(
0
!
=
strcmp(path,
"/usr/lib/system/libsystem_kernel.dylib"
)) {
continue
;
}
NSLog(@
"%s"
, path);
intptr_t text_base
=
0
;
uint32_t text_size
=
0
;
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2022-7-5 19:07
被lichaolich编辑
,原因: