之前因为有某些需求想找一个arm平台的inline hook框架,但是没能找到一个既精简、又支持修改多参数、修改返回值、支持用自定义函数替换掉原函数的框架。所以就决定花点时间自己实现一个,写了几天以后被告知不用做了,于是便有了这个烂尾项目。今天整理文件的时候看到了,与其留着发霉不如分享给坛友作为学习的例子。此代码为没用的草稿,不合规范的地方就不用对其提意见了。
2.1 精简
使用一个结构体和一段shellcode维护一个hook
2.2 支持多线程hook
每个hook维护一段只属于自己的shellcode
2.3 支持修改参数
参数数量小于4的修改r0-r3寄存器,大于4的再修改栈空间
2.4 支持修改返回值
覆盖r0寄存器的值
2.5 支持函数替换
hook函数执行完以后加载原函数下一条指令地址到lr寄存器
总体设计为,每个hook维持一个结构体与一段自己的shellcode,初始化hook时直接修改shellcode中的变量值,备份并修改原函数的起始汇编代码,使其直接跳到shellcode执行,完成其余的工作。所有的hook保存在一个链表中进行统一管理。
以下为维护hook的结构体:
在初始化hook时,首先获取shellcode中变量的内存地址,分配一块内存空间给结构体中的shellcode_code字段,并记录长度,记录原始函数的地址与hook函数的地址,存储原函数的前几条指令作为备份代码,并记录备份代码的长度,param_list中存储有想要修改的参数值,ret_value中存储有想要修改成的返回值。
初始化hook的代码如下:
在备份原函数前几条指令时需要对指令类型进行判断,如果是thumb指令,则需要对地址减1再进行保存。
判断指令类型的代码如下:
备份指令的函数如下:
指令地址为奇数是thumb指令
在shellcode开始执行之前,需要先对其中的变量进行初始化,以下为需要初始化的值:
shellcode在执行时,需要先保存原始上下文,由于r13,r14,r15寄存器比较特殊,在跳转到保存上下文代码块时,寄存器的值已经发生变化,因此需要单独对其进行保存
再进行上下文环境保存,代码如下:
与保存上下文相对应的,以下是恢复上下文的代码块:
执行hook的代码:
以上代码中,callback_modify_param被填充为以下函数:
callback_modify_return的值被填充为以下函数的地址:
指令修复部分还没完成。
最后附上Makefile:
总体来讲arm上的inline hook框架要比x86难实现一点,传参方式使用寄存器加栈顶空间,还需要对两种不同类型的指令进行判断和修复。目前的代码只能说是写了一个开头,要想做一个完整的框架,还是需要一点工作量的。
typedef struct inline_item{
void
*
shell_code;
/
/
shelcode的内存起始地址
int32_t shell_code_len;
/
/
shellcode的长度
address_t old_fun;
/
/
原始函数的起始地址
address_t new_fun;
/
/
hook函数的起始地址
void
*
back_code;
/
/
备份的代码
int32_t back_code_len;
/
/
备份代码的长度
void
*
reg;
/
/
保存寄存器空间
void
*
stack;
/
/
保存栈空间
list_node_t
*
param_list;
/
/
参数链表
void
*
ret_value;
/
/
返回值
} inline_item_t;
typedef struct inline_item{
void
*
shell_code;
/
/
shelcode的内存起始地址
int32_t shell_code_len;
/
/
shellcode的长度
address_t old_fun;
/
/
原始函数的起始地址
address_t new_fun;
/
/
hook函数的起始地址
void
*
back_code;
/
/
备份的代码
int32_t back_code_len;
/
/
备份代码的长度
void
*
reg;
/
/
保存寄存器空间
void
*
stack;
/
/
保存栈空间
list_node_t
*
param_list;
/
/
参数链表
void
*
ret_value;
/
/
返回值
} inline_item_t;
inline_item_t
*
init_item(address_t
*
target_fun, address_t
*
hook_fun, list_node_t
*
param_list,address_t ret_value)
{
inline_item_t
*
p_item
=
0
;
address_t temp
=
0
;
p_item
=
(inline_item_t
*
)malloc( sizeof(inline_item_t) );
p_item
-
>shell_code_len
=
(int8_t
*
)&asm_shellcode_end
-
(int8_t
*
)&asm_shellcode_begin;
p_item
-
>shell_code
=
(int8_t
*
)malloc( p_item
-
>shell_code_len);
/
/
分配shellcode空间
p_item
-
>old_fun
=
target_fun;
/
/
保存原始函数地址
p_item
-
>new_fun
=
hook_fun;
/
/
存储hook函数地址
p_item
-
>back_code_len
=
12
;
/
/
备份
12
字节指令
p_item
-
>back_code
=
malloc(p_item
-
>back_code_len);
p_item
-
>reg
=
malloc(
0x10
*
sizeof(address_t));
/
/
分配备份寄存器的空间
p_item
-
>stack
=
malloc(
0x10
*
sizeof(address_t));
/
/
分配备份栈的空间
p_item
-
>param_list
=
0
;
p_item
-
>ret_value
=
0
;
if
( param_list !
=
0
){
p_item
-
>param_list
=
param_list;
/
/
初始化要修改的参数列表
}
if
( ret_value!
=
0
){
p_item
-
>ret_value
=
(address_t
*
)malloc( sizeof(address_t) );
/
/
初始化要修改的返回值
ret_value
=
10
;
memcpy( p_item
-
>ret_value, &ret_value, sizeof(address_t));
}
return
p_item;
}
inline_item_t
*
init_item(address_t
*
target_fun, address_t
*
hook_fun, list_node_t
*
param_list,address_t ret_value)
{
inline_item_t
*
p_item
=
0
;
address_t temp
=
0
;
p_item
=
(inline_item_t
*
)malloc( sizeof(inline_item_t) );
p_item
-
>shell_code_len
=
(int8_t
*
)&asm_shellcode_end
-
(int8_t
*
)&asm_shellcode_begin;
p_item
-
>shell_code
=
(int8_t
*
)malloc( p_item
-
>shell_code_len);
/
/
分配shellcode空间
p_item
-
>old_fun
=
target_fun;
/
/
保存原始函数地址
p_item
-
>new_fun
=
hook_fun;
/
/
存储hook函数地址
p_item
-
>back_code_len
=
12
;
/
/
备份
12
字节指令
p_item
-
>back_code
=
malloc(p_item
-
>back_code_len);
p_item
-
>reg
=
malloc(
0x10
*
sizeof(address_t));
/
/
分配备份寄存器的空间
p_item
-
>stack
=
malloc(
0x10
*
sizeof(address_t));
/
/
分配备份栈的空间
p_item
-
>param_list
=
0
;
p_item
-
>ret_value
=
0
;
if
( param_list !
=
0
){
p_item
-
>param_list
=
param_list;
/
/
初始化要修改的参数列表
}
if
( ret_value!
=
0
){
p_item
-
>ret_value
=
(address_t
*
)malloc( sizeof(address_t) );
/
/
初始化要修改的返回值
ret_value
=
10
;
memcpy( p_item
-
>ret_value, &ret_value, sizeof(address_t));
}
return
p_item;
}
bool
get_type(address_t addr)
{
return
((int64_t)addr &
0x1
);
return
((int32_t)addr &
0x1
);
}
bool
get_type(address_t addr)
{
return
((int64_t)addr &
0x1
);
return
((int32_t)addr &
0x1
);
}
void back_target(inline_item_t
*
p_item){
p_item
-
>back_code_len
=
BACKLEN;
/
/
保存old_fun前几条指令
p_item
-
>back_code
=
(int8_t
*
)malloc(p_item
-
>back_code_len);
memcpy(p_item
-
>back_code, (address_t
*
)p_item
-
>old_fun, p_item
-
>back_code_len);
memcpy(p_item
-
>shell_code
+
asm_pos.back_code_pos, p_item
-
>back_code, p_item
-
>back_code_len);
/
/
修改old_fun前几条指令
if
( !set_mem_permission(p_item
-
>old_fun,RWX) ){
/
/
修改内存属性为可读可写可执行
return
;
}
memcpy((address_t
*
)p_item
-
>old_fun, p_item
-
>shell_code
+
asm_pos.load_pc_pos,sizeof(address_t));
memcpy((address_t
*
)p_item
-
>old_fun
+
1
, &p_item
-
>shell_code, sizeof(address_t));
memcpy(p_item
-
>shell_code
+
asm_pos.load_pc_pos, p_item
-
>back_code, sizeof(address_t)
*
3
);
}
void back_target(inline_item_t
*
p_item){
p_item
-
>back_code_len
=
BACKLEN;
/
/
保存old_fun前几条指令
p_item
-
>back_code
=
(int8_t
*
)malloc(p_item
-
>back_code_len);
memcpy(p_item
-
>back_code, (address_t
*
)p_item
-
>old_fun, p_item
-
>back_code_len);
memcpy(p_item
-
>shell_code
+
asm_pos.back_code_pos, p_item
-
>back_code, p_item
-
>back_code_len);
/
/
修改old_fun前几条指令
if
( !set_mem_permission(p_item
-
>old_fun,RWX) ){
/
/
修改内存属性为可读可写可执行
return
;
}
memcpy((address_t
*
)p_item
-
>old_fun, p_item
-
>shell_code
+
asm_pos.load_pc_pos,sizeof(address_t));
memcpy((address_t
*
)p_item
-
>old_fun
+
1
, &p_item
-
>shell_code, sizeof(address_t));
memcpy(p_item
-
>shell_code
+
asm_pos.load_pc_pos, p_item
-
>back_code, sizeof(address_t)
*
3
);
}
asm_old_fun_continue:
/
/
原函数的地址
.word
0x12345678
asm_new_fun:
/
/
hook函数的地址
.word
0x12345678
asm_param_num:
/
/
参数的个数
.word
0x00000010
asm_reg_sp:
/
/
栈顶值
.word
0x12345678
asm_reg_lr:
/
/
返回地址
.word
0x12345678
callback_modify_param:
/
/
callback_modify_param函数的地址
.word
0x00000000
callback_modify_return:
/
/
callback_modify_return函数的地址
.word
0x00000000
asm_item_addr:
/
/
当前hook结构体地址
.word
0x12345678
asm_reg_addr:
.word
0x12345678
asm_stack_addr:
.word
0x12345678
asm_back_code:
/
/
备份的原始函数代码块
.word
0x12345678
.word
0x12345678
.word
0x12345678
ldr r15,asm_old_fun_continue
/
/
跳转到备份代码的下一条指令继续执行
asm_old_fun_continue:
/
/
原函数的地址
.word
0x12345678
asm_new_fun:
/
/
hook函数的地址
.word
0x12345678
asm_param_num:
/
/
参数的个数
.word
0x00000010
asm_reg_sp:
/
/
栈顶值
.word
0x12345678
asm_reg_lr:
/
/
返回地址
.word
0x12345678
callback_modify_param:
/
/
callback_modify_param函数的地址
.word
0x00000000
callback_modify_return:
/
/
callback_modify_return函数的地址
.word
0x00000000
asm_item_addr:
/
/
当前hook结构体地址
.word
0x12345678
asm_reg_addr:
.word
0x12345678
asm_stack_addr:
.word
0x12345678
asm_back_code:
/
/
备份的原始函数代码块
.word
0x12345678
.word
0x12345678
.word
0x12345678
ldr r15,asm_old_fun_continue
/
/
跳转到备份代码的下一条指令继续执行
str
r13,asm_reg_sp
str
r14,asm_reg_lr
/
/
stmfd sp!,{r0}
/
/
这个需要注意,保存的pc应当是old_fun的下一条指令地址,
/
/
sub r0,r15,
0x
/
/
所以执行到这里以后要保存当前pc减去已经执行的指令步数
*
4
/
/
ldmfd sp!,{r0}
bl fun_save_context
str
r13,asm_reg_sp
str
r14,asm_reg_lr
/
/
stmfd sp!,{r0}
/
/
这个需要注意,保存的pc应当是old_fun的下一条指令地址,
/
/
sub r0,r15,
0x
/
/
所以执行到这里以后要保存当前pc减去已经执行的指令步数
*
4
/
/
ldmfd sp!,{r0}
bl fun_save_context
fun_save_context:
stmfd sp!,{r12}
/
/
-
-
-
-
-
-
-
开始保存寄存器
ldr r12,asm_reg_addr
stmea r12!,{r0
-
r11}
/
/
保存r0
-
-
r11
mov r0,r12
ldmfd sp!,{r12}
/
/
取出r12
stmea r0!,{r12}
/
/
保存r12
mrs r1,cpsr
/
/
保存CPSR寄存器
stmea r0!,{r1}
/
/
mov r1,sp
/
/
不能直接操作sp
/
/
stmea r0!,{r1}
/
/
-
-
-
-
-
-
-
寄存器保存完成
ldr r0,asm_stack_addr
/
/
-
-
开始保存栈空间
mov r2,
0x10
/
/
需要保存的栈空间大小
mov r1,sp
_loop_save_stack:
cmp
r2,
0x00
ble _loop_save_context_end
ldr r3,[r1]
str
r3,[r0],
0x04
add r1,r1,
0x04
sub r2,r2,
0x01
b _loop_save_stack
_loop_save_context_end:
/
/
-
-
栈空间保存完成
bx r14
fun_save_context_end:
fun_save_context:
stmfd sp!,{r12}
/
/
-
-
-
-
-
-
-
开始保存寄存器
ldr r12,asm_reg_addr
stmea r12!,{r0
-
r11}
/
/
保存r0
-
-
r11
mov r0,r12
ldmfd sp!,{r12}
/
/
取出r12
stmea r0!,{r12}
/
/
保存r12
mrs r1,cpsr
/
/
保存CPSR寄存器
stmea r0!,{r1}
/
/
mov r1,sp
/
/
不能直接操作sp
/
/
stmea r0!,{r1}
/
/
-
-
-
-
-
-
-
寄存器保存完成
ldr r0,asm_stack_addr
/
/
-
-
开始保存栈空间
mov r2,
0x10
/
/
需要保存的栈空间大小
mov r1,sp
_loop_save_stack:
cmp
r2,
0x00
ble _loop_save_context_end
ldr r3,[r1]
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2021-5-23 14:53
被某警官编辑
,原因: