linux 进程 inline hook,高级Linux Kernel Inline Hook技术分析与实现

高级Linux Kernel Inline Hook技术分析与实现

时间:2015/6/28作者:网管联盟

一、简述

目前流行和成熟的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 : mov    0x8(%ebp),%eax

0xc106dc6a : lea    0xfffffff4(%ebp),%edx

0xc106dc6d : call   0xc106e16c

0xc106dc72 : test   %eax,%eax

0xc106dc74 : mov    %eax,%ebx

0xc106dc76 : je     0xc106dcb1

0xc106dc78 : mov    0x24(%ebx),%edx

0xc106dc7b : mov    0x20(%eax),%eax

0xc106dc7e : mov    0x10(%ebp),%ecx

0xc106dc81 : mov    %edx,0xfffffff0(%ebp)

0xc106dc84 : mov    0xc(%ebp),%edx

0xc106dc87 : mov    %eax,0xffffffec(%ebp)

0xc106dc8a : lea    0xffffffec(%ebp),%eax

0xc106dc8d : push   %eax

0xc106dc8e : mov    %ebx,%eax

0xc106dc90 : call   0xc106d75c

0xc106dc95 : mov    0xfffffff0(%ebp),%edx

0xc106dc98 : mov    %eax,%esi

0xc106dc9a : mov    0xffffffec(%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 : lea    0xfffffff8(%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 关键词标签:Linux

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值