前段时间需要写一个libc探针,用来监测libc函数的调用,在google和github上找了很久,Windows和Android平台的inline hook都有比较详细的教程,但是Linux平台的教程比较缺乏,所以决定自己写一篇,思路参考了一篇Windows的inline hook文章,链接放在最后。
简单地说,inline hook就是通过直接修改程序的汇编代码来实现hook,举个例子:
假设这是一个函数开头的几条汇编代码
通过inline hook我们可以将其改为这样:
那么,当执行流进入这个函数时,它就会跳转到0x7fffff898688这个地址,并执行这个地址上的代码,我们可以将jmp的地址指定为hook函数的地址,以达到hook的目的
流程
我们的目标是libc中的库函数,所以我们需要先得到libc的基地址
只需要将进程的pid作为参数传入函数就可以得到目标进程的libc基地址
得到libc基地址后,再加上libc函数的偏移地址就可以得到libc函数的实际地址
为什么要保存目标函数的前面几条指令?
如果不在hook函数中调用原函数,那么不保存也行,但是大部分情况下,我们还是需要调用原函数来完成任务的,在后面的步骤中,我们会修改目标函数的前几条指令,如果不保存,就无法再次调用原函数
所以保存几条指令合适呢?
保存几条指令取决于要插入什么指令,inline hook常见的插入指令有三种:
三种指令各有优缺点
||jmp offset|jmp reg|push & ret|
|:-:|:-:|:-:|:-:|
|优点|编码简单,不改变环境|编码相对简单,跳转距离长|跳转距离长,不改变环境
|缺点|跳转距离短|改变环境(寄存器)|编码复杂
|一般适用|32位|32位或64位|64位
我们的inline hook将选择第三种类型的跳转,其硬编码如下所示:
硬编码的长度为14字节,所以我们要将目标函数大于等于十四字节的最少条数指令保存下来(有点绕口,请仔细揣摩)
但是我们如何知道最少应该保存多少字节的机器码呢? 答案是使用capstone
capstone的安装请自行搜索资料,并不是很难安装
通过下面的函数,我们只需要传入一个地址,就能得到应该保存多少字节的机器码
得到函数的返回之后,再使用memcpy从函数开始的地址复制合适个数的字节就行,完整代码会在后面给出
func_hook函数的参数分别是:目标函数的名称,目标函数的hook函数,目标函数的跳板函数(相当与原来的目标函数)
func_hook函数中,我们首先获得了目标函数的地址,然后使用mprotect函数将目标函数所在页的权限改为可读可写可执行,接着获取需要保存的字节数,再分配一块空间来存放保存的指令,在保存指令的后面放一个push&ret跳转,使之回到目标函数保存的指令的后一条指令,这就是跳板函数,执行跳板函数就相当于执行原函数,最后将这个地址赋值给跳板函数
一不小心把第二步和第三步都讲了,不过不影响
这一步比较简单,我们只需要使用push&ret编码覆盖目标函数的开始几条指令,使之跳转到我们写好的hook函数
在第二步的代码后面加三行代码就行
在最后我定义了fopen和fclose的hook函数,并在main函数中安装了hook
编译并运行
输出如下:
开始的两个fopen是因为先安装了fopen的hook,然后在安装fclose的hook的时候调用了fopen,触发了fopen的hook
以上的代码实现了本进程的hook,如果我们想要跨进程hook,可以将代码稍作修改并编译成so,然后使用so注入工具将其注入到其他进程
修改后的代码:
将其编译为so文件
新建一个sample.c文件,文件内容:
编译并运行sample
去github找一个开源的so注入工具 linux_so_injector,按引导构建好项目
新开一个终端,使用ps获取sample的pid,然后使用injector注入so
显示注入成功后,sample的输出如下:
除去最前面的两次fopen,刚好hook了十次
让我们来看看malloc函数的开头几条指令:
mov rdx,QWORD PTR [rip+0x11c3c] 这条指令使用了rip偏移寻址,需要用到当前的rip寄存器的值,如果我们贸然将其保存到跳板函数,当程序执行到跳板函数时,rip已经变了
要想得到正确的执行结果,就必须修改这条指令的偏移
当我们将so注入某个进程时,有可能出现安装hook的同时,进程的其他线程正好执行到了目标函数,这是程序就有可能崩溃
以上两个问题的答案都可以在参考文章中找到答案,本文旨在介绍inline hook,就不针对这两个问题做代码实现了
Windows inline hook详解
push ebp
mov ebp, esp
sub esp,
0x20
push ebp
mov ebp, esp
sub esp,
0x20
jmp
0x7fffff898688
...
/
/
获取libc的基地址
intptr_t get_libc_base(pid_t pid)
{
intptr_t libcAddr;
char
*
buf;
char
*
end;
FILE
*
fd
=
fopen(
"/proc/self/maps"
,
"r"
);
if
(!fd)
{
printf(
"open maps error!"
);
exit(
1
);
}
buf
=
(char
*
) malloc(
0x100
);
do{
fgets(buf,
0x100
, fd);
}
while
(!strstr(buf,
"libc-"
));
end
=
strchr(buf,
'-'
);
libcAddr
=
strtol(buf, &end,
16
);
/
/
printf(
"The process %d's libcbase is: 0x%lx\n"
, pid, libcAddr);
fclose(fd);
return
libcAddr;
}
/
/
获取libc的基地址
intptr_t get_libc_base(pid_t pid)
{
intptr_t libcAddr;
char
*
buf;
char
*
end;
FILE
*
fd
=
fopen(
"/proc/self/maps"
,
"r"
);
if
(!fd)
{
printf(
"open maps error!"
);
exit(
1
);
}
buf
=
(char
*
) malloc(
0x100
);
do{
fgets(buf,
0x100
, fd);
}
while
(!strstr(buf,
"libc-"
));
end
=
strchr(buf,
'-'
);
libcAddr
=
strtol(buf, &end,
16
);
/
/
printf(
"The process %d's libcbase is: 0x%lx\n"
, pid, libcAddr);
fclose(fd);
return
libcAddr;
}
/
/
获取目标函数的地址
intptr_t get_target_addr(intptr_t libc_base, const char
*
func_name)
{
intptr_t funcAddr;
funcAddr
=
(size_t)dlsym(
0
, func_name);
funcAddr
-
=
get_libc_base(getpid());
funcAddr
+
=
libc_base;
/
/
printf(
"function %s address is: 0x%lx\n"
, func_name, funcAddr);
return
funcAddr;
}
/
/
获取目标函数的地址
intptr_t get_target_addr(intptr_t libc_base, const char
*
func_name)
{
intptr_t funcAddr;
funcAddr
=
(size_t)dlsym(
0
, func_name);
funcAddr
-
=
get_libc_base(getpid());
funcAddr
+
=
libc_base;
/
/
printf(
"function %s address is: 0x%lx\n"
, func_name, funcAddr);
return
funcAddr;
}
push Low_address ;
0x68
,
0
,
0
,
0
,
0
mov dword ptr ss:[rsp
+
4
], high_address ;
0xC7
,
0x44
,
0x24
,
0x04
,
0
,
0
,
0
,
0
ret ;
0xC3
push Low_address ;
0x68
,
0
,
0
,
0
,
0
mov dword ptr ss:[rsp
+
4
], high_address ;
0xC7
,
0x44
,
0x24
,
0x04
,
0
,
0
,
0
,
0
ret ;
0xC3
/
/
获取目标函数前几条指令的长度
int
get_asm_len(intptr_t target)
{
csh handle;
cs_insn
*
insn;
size_t count;
char code[
30
]
=
{
0
};
int
rv;
memcpy((void
*
)code, (void
*
)target,
30
);
if
(cs_open(CS_ARCH_X86, CS_MODE_64, &handle))
{
printf(
"Error: cs_open\n"
);
return
-
1
;
}
count
=
cs_disasm(handle, code,
30
,
0
,
0
, &insn);
if
(count)
{
for
(size_t i
=
0
; i < count; i
+
+
)
{
if
(insn[i].address >
=
14
)
{
rv
=
insn[i].address;
break
;
}
}
cs_free(insn, count);
}
else
{
printf(
"Error: cs_disasm\n"
);
return
-
1
;
}
cs_close(&handle);
return
rv;
}
/
/
获取目标函数前几条指令的长度
int
get_asm_len(intptr_t target)
{
csh handle;
cs_insn
*
insn;
size_t count;
char code[
30
]
=
{
0
};
int
rv;
memcpy((void
*
)code, (void
*
)target,
30
);
if
(cs_open(CS_ARCH_X86, CS_MODE_64, &handle))
{
printf(
"Error: cs_open\n"
);
return
-
1
;
}
count
=
cs_disasm(handle, code,
30
,
0
,
0
, &insn);
if
(count)
{
for
(size_t i
=
0
; i < count; i
+
+
)
{
if
(insn[i].address >
=
14
)
{
rv
=
insn[i].address;
break
;
}
}
cs_free(insn, count);
}
else
{
printf(
"Error: cs_disasm\n"
);
return
-
1
;
}
cs_close(&handle);
return
rv;
}
void func_hook(const char
*
funcname, void
*
hook_func, void
*
*
origin_func)
{
intptr_t libc_base
=
get_libc_base(getpid());
intptr_t target_addr
=
get_target_addr(libc_base, funcname);
/
/
根据目标函数的地址确定目标函数所在的页,并将该页的权限改为可读可写可执行
intptr_t page_start
=
target_addr &
0xfffffffff000
;
mprotect((void
*
)page_start,
0x1000
, PROT_READ|PROT_WRITE|PROT_EXEC);
int
asm_len
=
get_asm_len(target_addr);
if
(asm_len <
=
0
)
{
printf(
"Error: get_asm_len\n"
);
exit(
-
1
);
}
char
*
temp_func
=
(char
*
)mmap(NULL,
4096
, PROT_WRITE|PROT_EXEC|PROT_READ, MAP_ANON|MAP_PRIVATE,
-
1
,
0
);
memcpy((void
*
)temp_func, (void
*
)target_addr, asm_len);
intptr_t y
=
(intptr_t)target_addr
+
asm_len;
/
/
构造push&ret跳转,填入目标地址
char jmp_code[
14
]
=
{
0x68
,y&
0xff
,(y&
0xff00
)>>
8
,(y&
0xff0000
)>>
16
,(y&
0xff000000
)>>
24
,
0xC7
,
0x44
,
0x24
,
0x04
,(y&
0xff00000000
)>>
32
,(y&
0xff0000000000
)>>
40
,(y&
0xff000000000000
)>>
48
,
(y&
0xff00000000000000
)>>
56
,
0xC3
};
memcpy((void
*
)(temp_func
+
asm_len), (void
*
)jmp_code,
14
);
*
origin_func
=
(void
*
)temp_func;
}
void func_hook(const char
*
funcname, void
*
hook_func, void
*
*
origin_func)
{
intptr_t libc_base
=
get_libc_base(getpid());
intptr_t target_addr
=
get_target_addr(libc_base, funcname);
/
/
根据目标函数的地址确定目标函数所在的页,并将该页的权限改为可读可写可执行
intptr_t page_start
=
target_addr &
0xfffffffff000
;
mprotect((void
*
)page_start,
0x1000
, PROT_READ|PROT_WRITE|PROT_EXEC);
int
asm_len
=
get_asm_len(target_addr);
if
(asm_len <
=
0
)
{
printf(
"Error: get_asm_len\n"
);
exit(
-
1
);
}
char
*
temp_func
=
(char
*
)mmap(NULL,
4096
, PROT_WRITE|PROT_EXEC|PROT_READ, MAP_ANON|MAP_PRIVATE,
-
1
,
0
);
memcpy((void
*
)temp_func, (void
*
)target_addr, asm_len);
intptr_t y
=
(intptr_t)target_addr
+
asm_len;
/
/
构造push&ret跳转,填入目标地址
char jmp_code[
14
]
=
{
0x68
,y&
0xff
,(y&
0xff00
)>>
8
,(y&
0xff0000
)>>
16
,(y&
0xff000000
)>>
24
,
0xC7
,
0x44
,
0x24
,
0x04
,(y&
0xff00000000
)>>
32
,(y&
0xff0000000000
)>>
40
,(y&
0xff000000000000
)>>
48
,
(y&
0xff00000000000000
)>>
56
,
0xC3
};
memcpy((void
*
)(temp_func
+
asm_len), (void
*
)jmp_code,
14
);
*
origin_func
=
(void
*
)temp_func;
}
/
/
替换目标函数的前
len
个字节,使之跳转到hook函数
void change_bytes(intptr_t addr, const char code[],
int
len
)
{
memcpy((void
*
)addr, code,
len
);
}
void func_hook(const char
*
funcname, void
*
hook_func, void
*
*
origin_func)
{
intptr_t libc_base
=
get_libc_base(getpid());
intptr_t target_addr
=
get_target_addr(libc_base, funcname);
/
/
根据目标函数的地址确定目标函数所在的页,并将该页的权限改为可读可写可执行
intptr_t page_start
=
target_addr &
0xfffffffff000
;
mprotect((void
*
)page_start,
0x1000
, PROT_READ|PROT_WRITE|PROT_EXEC);
int
asm_len
=
get_asm_len(target_addr);
if
(asm_len <
=
0
)
{
printf(
"Error: get_asm_len\n"
);
exit(
-
1
);
}
char
*
temp_func
=
(char
*
)mmap(NULL,
4096
, PROT_WRITE|PROT_EXEC|PROT_READ, MAP_ANON|MAP_PRIVATE,
-
1
,
0
);
memcpy((void
*
)temp_func, (void
*
)target_addr, asm_len);
intptr_t y
=
(intptr_t)target_addr
+
asm_len;
/
/
构造push&ret跳转,填入目标地址
char jmp_code[
14
]
=
{
0x68
,y&
0xff
,(y&
0xff00
)>>
8
,(y&
0xff0000
)>>
16
,(y&
0xff000000
)>>
24
,
0xC7
,
0x44
,
0x24
,
0x04
,(y&
0xff00000000
)>>
32
,(y&
0xff0000000000
)>>
40
,(y&
0xff000000000000
)>>
48
,
(y&
0xff00000000000000
)>>
56
,
0xC3
};
memcpy((void
*
)(temp_func
+
asm_len), (void
*
)jmp_code,
14
);
*
origin_func
=
(void
*
)temp_func;
intptr_t x
=
(intptr_t)hook_func;
char hard_code[
14
]
=
{
0x68
,x&
0xff
,(x&
0xff00
)>>
8
,(x&
0xff0000
)>>
16
,(x&
0xff000000
)>>
24
,
0xC7
,
0x44
,
0x24
,
0x04
,(x&
0xff00000000
)>>
32
,(x&
0xff0000000000
)>>
40
,(x&
0xff000000000000
)>>
48
,
(x&
0xff00000000000000
)>>
56
,
0xC3
};
change_bytes(target_addr, hard_code,
14
);
}
/
/
替换目标函数的前
len
个字节,使之跳转到hook函数
void change_bytes(intptr_t addr, const char code[],
int
len
)
{
memcpy((void
*
)addr, code,
len
);
}
void func_hook(const char
*
funcname, void
*
hook_func, void
*
*
origin_func)
{
intptr_t libc_base
=
get_libc_base(getpid());
intptr_t target_addr
=
get_target_addr(libc_base, funcname);
/
/
根据目标函数的地址确定目标函数所在的页,并将该页的权限改为可读可写可执行
intptr_t page_start
=
target_addr &
0xfffffffff000
;
mprotect((void
*
)page_start,
0x1000
, PROT_READ|PROT_WRITE|PROT_EXEC);
int
asm_len
=
get_asm_len(target_addr);
if
(asm_len <
=
0
)
{
printf(
"Error: get_asm_len\n"
);
exit(
-
1
);
}
char
*
temp_func
=
(char
*
)mmap(NULL,
4096
, PROT_WRITE|PROT_EXEC|PROT_READ, MAP_ANON|MAP_PRIVATE,
-
1
,
0
);
memcpy((void
*
)temp_func, (void
*
)target_addr, asm_len);
intptr_t y
=
(intptr_t)target_addr
+
asm_len;
/
/
构造push&ret跳转,填入目标地址
char jmp_code[
14
]
=
{
0x68
,y&
0xff
,(y&
0xff00
)>>
8
,(y&
0xff0000
)>>
16
,(y&
0xff000000
)>>
24
,
0xC7
,
0x44
,
0x24
,
0x04
,(y&
0xff00000000
)>>
32
,(y&
0xff0000000000
)>>
40
,(y&
0xff000000000000
)>>
48
,
(y&
0xff00000000000000
)>>
56
,
0xC3
};
memcpy((void
*
)(temp_func
+
asm_len), (void
*
)jmp_code,
14
);
*
origin_func
=
(void
*
)temp_func;
intptr_t x
=
(intptr_t)hook_func;
char hard_code[
14
]
=
{
0x68
,x&
0xff
,(x&
0xff00
)>>
8
,(x&
0xff0000
)>>
16
,(x&
0xff000000
)>>
24
,
0xC7
,
0x44
,
0x24
,
0x04
,(x&
0xff00000000
)>>
32
,(x&
0xff0000000000
)>>
40
,(x&
0xff000000000000
)>>
48
,
(x&
0xff00000000000000
)>>
56
,
0xC3
};
change_bytes(target_addr, hard_code,
14
);
}
/
/
获取libc的基地址
intptr_t get_libc_base(pid_t pid)
{
intptr_t libcAddr;
char
*
buf;
char
*
end;
FILE
*
fd
=
fopen(
"/proc/self/maps"
,
"r"
);
if
(!fd)
{
printf(
"open maps error!"
);
exit(
1
);
}
buf
=
(char
*
) malloc(
0x100
);
do{
fgets(buf,
0x100
, fd);
}
while
(!strstr(buf,
"libc-"
));
end
=
strchr(buf,
'-'
);
libcAddr
=
strtol(buf, &end,
16
);
/
/
printf(
"The process %d's libcbase is: 0x%lx\n"
, pid, libcAddr);
fclose(fd);
return
libcAddr;
}
/
/
获取目标函数的地址
intptr_t get_target_addr(intptr_t libc_base, const char
*
func_name)
{
intptr_t funcAddr;
funcAddr
=
(size_t)dlsym(
0
, func_name);
funcAddr
-
=
get_libc_base(getpid());
funcAddr
+
=
libc_base;
/
/
printf(
"function %s address is: 0x%lx\n"
, func_name, funcAddr);
return
funcAddr;
}
/
/
获取目标函数前几条指令的长度
int
get_asm_len(intptr_t target)
{
csh handle;
cs_insn
*
insn;
size_t count;
char code[
30
]
=
{
0
};
int
rv;
memcpy((void
*
)code, (void
*
)target,
30
);
if
(cs_open(CS_ARCH_X86, CS_MODE_64, &handle))
{
printf(
"Error: cs_open\n"
);
return
-
1
;
}
count
=
cs_disasm(handle, code,
30
,
0
,
0
, &insn);
if
(count)
{
for
(size_t i
=
0
; i < count; i
+
+
)
{
if
(insn[i].address >
=
14
)
{
rv
=
insn[i].address;
break
;
}
}
cs_free(insn, count);
}
else
{
printf(
"Error: cs_disasm\n"
);
return
-
1
;
}
cs_close(&handle);
return
rv;
}
/
/
替换目标函数的前
len
个字节,使之跳转到hook函数
void change_bytes(intptr_t addr, const char code[],
int
len
)
{
memcpy((void
*
)addr, code,
len
);
}
void func_hook(const char
*
funcname, void
*
hook_func, void
*
*
origin_func)
{
intptr_t libc_base
=
get_libc_base(getpid());
intptr_t target_addr
=
get_target_addr(libc_base, funcname);
/
/
根据目标函数的地址确定目标函数所在的页,并将该页的权限改为可读可写可执行
intptr_t page_start
=
target_addr &
0xfffffffff000
;
mprotect((void
*
)page_start,
0x1000
, PROT_READ|PROT_WRITE|PROT_EXEC);
int
asm_len
=
get_asm_len(target_addr);
if
(asm_len <
=
0
)
{
printf(
"Error: get_asm_len\n"
);
exit(
-
1
);
}
char
*
temp_func
=
(char
*
)mmap(NULL,
4096
, PROT_WRITE|PROT_EXEC|PROT_READ, MAP_ANON|MAP_PRIVATE,
-
1
,
0
);
memcpy((void
*
)temp_func, (void
*
)target_addr, asm_len);
intptr_t y
=
(intptr_t)target_addr
+
asm_len;
/
/
构造push&ret跳转,填入目标地址
char jmp_code[
14
]
=
{
0x68
,y&
0xff
,(y&
0xff00
)>>
8
,(y&
0xff0000
)>>
16
,(y&
0xff000000
)>>
24
,
0xC7
,
0x44
,
0x24
,
0x04
,(y&
0xff00000000
)>>
32
,(y&
0xff0000000000
)>>
40
,(y&
0xff000000000000
)>>
48
,
(y&
0xff00000000000000
)>>
56
,
0xC3
};
memcpy((void
*
)(temp_func
+
asm_len), (void
*
)jmp_code,
14
);
*
origin_func
=
(void
*
)temp_func;
intptr_t x
=
(intptr_t)hook_func;
char hard_code[
14
]
=
{
0x68
,x&
0xff
,(x&
0xff00
)>>
8
,(x&
0xff0000
)>>
16
,(x&
0xff000000
)>>
24
,
0xC7
,
0x44
,
0x24
,
0x04
,(x&
0xff00000000
)>>
32
,(x&
0xff0000000000
)>>
40
,(x&
0xff000000000000
)>>
48
,
(x&
0xff00000000000000
)>>
56
,
0xC3
};
change_bytes(target_addr, hard_code,
14
);
}
static
FILE
*
(
*
origin_fopen)(const char
*
filename, const char
*
mod);
static
int
(
*
origin_fclose)(
FILE
*
fp);
static
FILE
*
fopen_hook(const char
*
filename, const char
*
mod)
{
FILE
*
rv
=
origin_fopen(filename, mod);
printf(
"fopen(\"%s\", \"%s\")\n\treturn: %p\n"
, filename, mod, rv);
return
rv;
}
static
int
fclose_hook(
FILE
*
fp)
{
int
rv
=
origin_fclose(fp);
printf(
"fclose(%p)\n\treturn: %d\n"
, fp, rv);
return
rv;
}
int
main()
{
func_hook(
"fopen"
, (void
*
)fopen_hook, (void
*
*
)&origin_fopen);
func_hook(
"fclose"
, (void
*
)fclose_hook, (void
*
*
)&origin_fclose);
FILE
*
file
=
fopen(
"sample.txt"
,
"r"
);
if
(
file
!
=
NULL)
{
fclose(
file
);
}
return
0
;
}
/
/
获取libc的基地址
intptr_t get_libc_base(pid_t pid)
{
intptr_t libcAddr;
char
*
buf;
char
*
end;
FILE
*
fd
=
fopen(
"/proc/self/maps"
,
"r"
);
if
(!fd)
{
printf(
"open maps error!"
);
exit(
1
);
}
buf
=
(char
*
) malloc(
0x100
);
do{
fgets(buf,
0x100
, fd);
}
while
(!strstr(buf,
"libc-"
));
end
=
strchr(buf,
'-'
);
libcAddr
=
strtol(buf, &end,
16
);
/
/
printf(
"The process %d's libcbase is: 0x%lx\n"
, pid, libcAddr);
fclose(fd);
return
libcAddr;
}
/
/
获取目标函数的地址
intptr_t get_target_addr(intptr_t libc_base, const char
*
func_name)
{
intptr_t funcAddr;
funcAddr
=
(size_t)dlsym(
0
, func_name);
funcAddr
-
=
get_libc_base(getpid());
funcAddr
+
=
libc_base;
/
/
printf(
"function %s address is: 0x%lx\n"
, func_name, funcAddr);
return
funcAddr;
}
/
/
获取目标函数前几条指令的长度
int
get_asm_len(intptr_t target)
{
csh handle;
cs_insn
*
insn;
size_t count;
char code[
30
]
=
{
0
};
int
rv;
memcpy((void
*
)code, (void
*
)target,
30
);
if
(cs_open(CS_ARCH_X86, CS_MODE_64, &handle))
{
printf(
"Error: cs_open\n"
);
return
-
1
;
}
count
=
cs_disasm(handle, code,
30
,
0
,
0
, &insn);
if
(count)
{
for
(size_t i
=
0
; i < count; i
+
+
)
{
if
(insn[i].address >
=
14
)
{
rv
=
insn[i].address;
break
;
}
}
cs_free(insn, count);
}
else
{
printf(
"Error: cs_disasm\n"
);
return
-
1
;
}
cs_close(&handle);
return
rv;
}
/
/
替换目标函数的前
len
个字节,使之跳转到hook函数
void change_bytes(intptr_t addr, const char code[],
int
len
)
{
memcpy((void
*
)addr, code,
len
);
}
void func_hook(const char
*
funcname, void
*
hook_func, void
*
*
origin_func)
{
intptr_t libc_base
=
get_libc_base(getpid());
intptr_t target_addr
=
get_target_addr(libc_base, funcname);
/
/
根据目标函数的地址确定目标函数所在的页,并将该页的权限改为可读可写可执行
intptr_t page_start
=
target_addr &
0xfffffffff000
;
mprotect((void
*
)page_start,
0x1000
, PROT_READ|PROT_WRITE|PROT_EXEC);
int
asm_len
=
get_asm_len(target_addr);
if
(asm_len <
=
0
)
{
printf(
"Error: get_asm_len\n"
);
exit(
-
1
);
}
char
*
temp_func
=
(char
*
)mmap(NULL,
4096
, PROT_WRITE|PROT_EXEC|PROT_READ, MAP_ANON|MAP_PRIVATE,
-
1
,
0
);
memcpy((void
*
)temp_func, (void
*
)target_addr, asm_len);
intptr_t y
=
(intptr_t)target_addr
+
asm_len;
/
/
构造push&ret跳转,填入目标地址
char jmp_code[
14
]
=
{
0x68
,y&
0xff
,(y&
0xff00
)>>
8
,(y&
0xff0000
)>>
16
,(y&
0xff000000
)>>
24
,
0xC7
,
0x44
,
0x24
,
0x04
,(y&
0xff00000000
)>>
32
,(y&
0xff0000000000
)>>
40
,(y&
0xff000000000000
)>>
48
,
(y&
0xff00000000000000
)>>
56
,
0xC3
};
memcpy((void
*
)(temp_func
+
asm_len), (void
*
)jmp_code,
14
);
*
origin_func
=
(void
*
)temp_func;
intptr_t x
=
(intptr_t)hook_func;
char hard_code[
14
]
=
{
0x68
,x&
0xff
,(x&
0xff00
)>>
8
,(x&
0xff0000
)>>
16
,(x&
0xff000000
)>>
24
,
0xC7
,
0x44
,
0x24
,
0x04
,(x&
0xff00000000
)>>
32
,(x&
0xff0000000000
)>>
40
,(x&
0xff000000000000
)>>
48
,
(x&
0xff00000000000000
)>>
56
,
0xC3
};
change_bytes(target_addr, hard_code,
14
);
}
static
FILE
*
(
*
origin_fopen)(const char
*
filename, const char
*
mod);
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)