高级Linux Kernel Inline Hook技术分析与实现
- 2024-02-15 05:30:05
- 来源:本站整理
- 在手机上看
扫一扫立即进入手机端
一、简述
目前流行和成熟的kernel inline hook技术就是修改内核函数的opcode,通过写入jmp或push ret等指令跳转到新的内核函数中,从而达到修改或过滤的功能。这些技术的共同点就是都会覆盖原有的指令,这样很容易在函数中通过查找jmp,push ret等指令来查出来,因此这种inline hook方式不够隐蔽。本文将使用一种高级inline hook技术来实现更隐蔽的inline hook技术。
二、更改offset实现跳转
如何不给函数添加或覆盖新指令,就能跳转到我们新的内核函数中去呢?我们知道实现一个系统调用的函数中不可能把所有功能都在这个函数中全部实现,它必定要调用它的下层函数。如果这个下层函数也可以得到我们想要的过滤信息等内容的话,就可以把下层函数在上层函数中的offset替换成我们新的函数的offset,这样上层函数调用下层函数时,就会跳到我们新的函数中,在新的函数中做过滤和劫持内容的工作。原理是这样的,具体来分析它该怎么实现, 我们去看看sys_read的具体实现:
linux-2.6.18/fs/read_write.c
asmlinkage ssize_t sys_read(unsigned int fd, char __user * buf, size_t count)
{
struct file *file;
ssize_t ret = -EBADF;
int fput_needed;
file = fget_light(fd, &fput_needed);
if (file) {
loff_t pos = file_pos_read(file);
ret = vfs_read(file, buf, count, &pos);
file_pos_write(file, pos);
fput_light(file, fput_needed);
}
return ret;
}
EXPORT_SYMBOL_GPL(sys_read);
我们看到sys_read最终是要调用下层函数vfs_read来完成读取数据的操作,所以我们不需要给sys_read添加或覆盖指令, 而是要更改vfs_read在sys_read代码中的offset就可以跳
转到我们新的new_vfs_read中去。如何修改vfs_read的offset呢?先反汇编下sys_read看看:
[root@xsec linux-2.6.18]# gdb -q vmlinux
Using host libthread_db library “/lib/libthread_db.so.1“.
(gdb) disass sys_read
Dump of assembler code for function sys_read:
0xc106dc5a:push %ebp
0xc106dc5b:mov%esp,%ebp
0xc106dc5d:push %esi
0xc106dc5e:mov$0xfffffff7,%esi
0xc106dc63:push %ebx
0xc106dc64: sub$0xc,%esp
0xc106dc67: mov0x8(%ebp),%eax
0xc106dc6a: lea0xfffffff4(%ebp),%edx
0xc106dc6d: call 0xc106e16c
0xc106dc72: test %eax,%eax
0xc106dc74: mov%eax,%ebx
0xc106dc76: je 0xc106dcb1
0xc106dc78: mov0x24(%ebx),%edx
0xc106dc7b: mov0x20(%eax),%eax
0xc106dc7e: mov0x10(%ebp),%ecx
0xc106dc81: mov%edx,0xfffffff0(%ebp)
0xc106dc84: mov0xc(%ebp),%edx
0xc106dc87: mov%eax,0xffffffec(%ebp)
0xc106dc8a: lea0xffffffec(%ebp),%eax
0xc106dc8d: push %eax
0xc106dc8e: mov%ebx,%eax
0xc106dc90: call 0xc106d75c
0xc106dc95: mov0xfffffff0(%ebp),%edx
0xc106dc98: mov%eax,%esi
0xc106dc9a: mov0xffffffec(%ebp),%eax
0xc106dc9d: mov%edx,0x24(%ebx)
0xc106dca0: mov%eax,0x20(%ebx)
0xc106dca3: cmpl $0x0,0xfffffff4(%ebp)
0xc106dca7: pop%eax
0xc106dca8: je 0xc106dcb1
0xc106dcaa: mov%ebx,%eax
0xc106dcac: call 0xc106e107
0xc106dcb1: lea0xfffffff8(%ebp),%esp
0xc106dcb4: mov%esi,%eax
0xc106dcb6: pop%ebx
0xc106dcb7: pop%esi
0xc106dcb8: pop%ebp
0xc106dcb9: ret
End of assembler dump.
(gdb)
0xc106dc90: call 0xc106d75c
通过call指令来跳转到vfs_read中去。0xc106d75c是vfs_read的内存地址。所以只要把这个地址替换成我们的新函数地址,当sys_read执行这块的时候,就会跳转到我们的函数来了。
下面给出我写的一个hook引擎,来完成查找和替换offset的功能。原理就是搜索sys_read的opcode,如果发现是call指令,根据call后面的offset重新计算要跳转的地址是不是我们要hook的函数地址,如果是就重新计算新函数的offset,用新的offset替换原来的offset。从而完成跳转功能。
参数handler是上层函数的地址,这里就是sys_read的地址,old_func是要替换的函数地址,这里就是vfs_read, new_func是新函数的地址,这里就是new_vfs_read的地址。
unsigned int patch_kernel_func(unsigned int handler, unsigned int old_func,
&n
目前流行和成熟的kernel inline hook技术就是修改内核函数的opcode,通过写入jmp或push ret等指令跳转到新的内核函数中,从而达到修改或过滤的功能。这些技术的共同点就是都会覆盖原有的指令,这样很容易在函数中通过查找jmp,push ret等指令来查出来,因此这种inline hook方式不够隐蔽。本文将使用一种高级inline hook技术来实现更隐蔽的inline hook技术。
二、更改offset实现跳转
如何不给函数添加或覆盖新指令,就能跳转到我们新的内核函数中去呢?我们知道实现一个系统调用的函数中不可能把所有功能都在这个函数中全部实现,它必定要调用它的下层函数。如果这个下层函数也可以得到我们想要的过滤信息等内容的话,就可以把下层函数在上层函数中的offset替换成我们新的函数的offset,这样上层函数调用下层函数时,就会跳到我们新的函数中,在新的函数中做过滤和劫持内容的工作。原理是这样的,具体来分析它该怎么实现, 我们去看看sys_read的具体实现:
linux-2.6.18/fs/read_write.c
asmlinkage ssize_t sys_read(unsigned int fd, char __user * buf, size_t count)
{
struct file *file;
ssize_t ret = -EBADF;
int fput_needed;
file = fget_light(fd, &fput_needed);
if (file) {
loff_t pos = file_pos_read(file);
ret = vfs_read(file, buf, count, &pos);
file_pos_write(file, pos);
fput_light(file, fput_needed);
}
return ret;
}
EXPORT_SYMBOL_GPL(sys_read);
我们看到sys_read最终是要调用下层函数vfs_read来完成读取数据的操作,所以我们不需要给sys_read添加或覆盖指令, 而是要更改vfs_read在sys_read代码中的offset就可以跳
转到我们新的new_vfs_read中去。如何修改vfs_read的offset呢?先反汇编下sys_read看看:
[root@xsec linux-2.6.18]# gdb -q vmlinux
Using host libthread_db library “/lib/libthread_db.so.1“.
(gdb) disass sys_read
Dump of assembler code for function sys_read:
0xc106dc5a
0xc106dc5b
0xc106dc5d
0xc106dc5e
0xc106dc63
0xc106dc64
0xc106dc67
0xc106dc6a
0xc106dc6d
0xc106dc72
0xc106dc74
0xc106dc76
0xc106dc78
0xc106dc7b
0xc106dc7e
0xc106dc81
0xc106dc84
0xc106dc87
0xc106dc8a
0xc106dc8d
0xc106dc8e
0xc106dc90
0xc106dc95
0xc106dc98
0xc106dc9a
0xc106dc9d
0xc106dca0
0xc106dca3
0xc106dca7
0xc106dca8
0xc106dcaa
0xc106dcac
0xc106dcb1
0xc106dcb4
0xc106dcb6
0xc106dcb7
0xc106dcb8
0xc106dcb9
End of assembler dump.
(gdb)
0xc106dc90
通过call指令来跳转到vfs_read中去。0xc106d75c是vfs_read的内存地址。所以只要把这个地址替换成我们的新函数地址,当sys_read执行这块的时候,就会跳转到我们的函数来了。
下面给出我写的一个hook引擎,来完成查找和替换offset的功能。原理就是搜索sys_read的opcode,如果发现是call指令,根据call后面的offset重新计算要跳转的地址是不是我们要hook的函数地址,如果是就重新计算新函数的offset,用新的offset替换原来的offset。从而完成跳转功能。
参数handler是上层函数的地址,这里就是sys_read的地址,old_func是要替换的函数地址,这里就是vfs_read, new_func是新函数的地址,这里就是new_vfs_read的地址。
unsigned int patch_kernel_func(unsigned int handler, unsigned int old_func,
&n
相关资讯
更多-
LINUX与UNIX SHELL编程指南
中文|19.1M
-
检疫镇手机版
中文|72.5M
-
国人健康馆
中文|102.4M
-
来趣拼购物app
中文|26.2M
-
决战平安京海外加速服
中文|1.92G
-
射击骑士团h5手游
中文|3.4M
-
TFit手环app
中文|56.8M