免费教程_免费网赚教程_破解版软件-寂涯网络学习基地

当前位置: 主页 > 系统综合 > linux > 使用kprobes进行内核修改(2)

使用kprobes进行内核修改(2)

时间:2012-02-20 21:01来源:未知 整理:寂涯网络 点击:


};
int init_module(void) {
mprotect_kretprobe.kp. addr = (kprobe_opcode_t
* )kallsyms_lo okup_name(?? sys_mprotect??); register_kretprobe(&mprotect_kretprobe);
}
上述为kretprobes 示例。
可见,我们使用了 kallsyms_lookup_name(),但是事实上probe可以被虚拟地用 于内核中的任何指令,即任何你知道的地址如通金system.map。给出的代码十分很简单。 当sys_mprotect返回时,桟顶的摊址(返回地址)被修改成kretpribe_trampoline()函数的地址,该函数进一步调用我们自己的mprotect_ret_handler()函数,此时我们就可以修改内核中的数据了。2. 4,_我们将详细地较少kretprobe_trampoline函数。
Kprobes 实现
1. Kprobe 实现
本节将首先大概地介绍kprobe的实现,下面的内容来自内核源码中的kprobes. txt: 当我们注册了一个Kprobe之后,kprobes就会拷贝一份指令并将该指令的头一个字节 或几个字节改为断点指令如1386八86_64上的int3。
当CPU运行到该断点指令时,将产生一个trap,保存CPU寄存器同时通过 notifier_call_chain机制将控制权转给kprobeSoKprobes执行其预处理函数,并将kprobe 结构和保存的寄存器传给该处理函数。在处理函数结束时,如果我们还设置了后处理函数, 那么该函数将被调用。
需要注意的是,当注册一个kpr0be时,我们需要指定一个预处理从而使得用户可以查 看或修改内核数据。而后处理函数是可有可无的。
由于本文主要使用kprobe接口的扩展 jprobes和kretprobes,本文将主要讨论jprobes 和kretprobes的实现而非纯kprobe。读者现在只需要知道注册一个基本的kprobe将在指 定位置插入一个断点指令,并执行指定的处理函数。在jprobes和kretprobes的实现中我们将可以看到处理函数的例子,这些处理函数指向特殊的内核函数 [/usr/src/1 inux/arch/x86/kernel/kprobes. c]。这些特殊函数类似于真正的处理函数的 prologue和 epilogue。
2. Jprobe 实现
如果我们能够了解jprobes和kretprobes的内部实现,那么我们将能够更好地使用它 们并使其完成比预期的更多的功能。
首先我们来看下下面这个结构:
structjprobe {
struct kprobe kp;
void *entry; /* probe将要跳到的处理函数*/
图 3. Jprobes 结构。
当我们调用 register_jprobe ()时,该函数将进一步调用 register_jprobes (&jp, 1)。 Register_jprobes ()函数的功能是设置jprobe的处理函数。如图4所示:
jp->kp .pre_handler = sstjmp_pre_handler; jp->kp.break_handler = longjmp_break_handler; ret = register_kprobe(&jp->kp);
图 4.register_jprobes()片段,位于/usr/src/linux/kernel/kprobes. c。 预处理函数在真正的化理函数之前被调用,并负责^栈令‘^容,寄存器及设置£1卩。 在正常情况下,用户是无法控制jprobes的预处理函数和后处理函数的,因为其不指向用户 自定义的函数。 V J
你可能会想象jprobe的执行过程如下:、^\ 1
1. [jprobe预处理函数]-保存栈和寄存器状态。
2. [jprobe处理函数]-执行用户的需求
3. [jprobe后处理器]-恢复原始的栈和寄存器。
我们来看下预处理器的实现代磉:VV/I  
int _kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) { structjprobe *jp = container_ofl^p, structjprobe, kp); unsigned long addr;
struct kprobe_ctlbUc *kcb = get_kprobe_ctlblk(); kcb->jprobe_saved_regs = *regs; kcb->jprobe_saved_sp = stack_addr(regs); addr = (unsigned long)(kcb->jprobe_saved_sp);
/*
* Linus指出,gcc假定被调用函数拥有其参数并可以覆写其参数。
*因此为了绝对保证安全,我们会保存足够多的栈中数据来保证 *覆盖参数区。
*/
memcpy(kcb->jprobes_stack, (kprobe_opcode_t *)addr,
MW_STACK_SEE(addr)); ~ ~ ~
regs->flags &=?X86_EFLAGS_ff; trace_hardirqs_off(); regs->ip = (unsigned long)0'p->entry); return 1;
图5. Jprobe预处理函数代码。 特别注意代码中的注释,既然这是匕化^说的,那么就一定是正确的。
PROGRAMMING ANALYSE
从代码中可以看到,该函数首先使用81&4一34如()宏得到当前栈的位置,然后使用 memcpy将其复制到kcb_>jprobes_stack中,该地址用于保存和恢复原始栈。在jprobe处 理函数运行结束后,』口10^后处理函数将被调用,代码如下:
int _kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) { struct kprobe_ctlbUc *kcb = get_kprobe_ctlbUc(); u8 *addr = (u8 *) (regs->ip - 1); structjprobe *jp = container_ofl^p, structjprobe, kp); if ((addr > (u8 *) jprobe_retum) && (addr < (u8 *) jprobe_retum_end)) { if (stack_addr(regs) != kcb->jprobe_saved_sp) {

本页地址 http://www.jybase.net/linux/20120220779.html

百度搜索更多

谷歌搜索更多

顶一下
(0)
0%
踩一下
(1)
100%
------分隔线----------------------------

评价:
昵称: 验证码:点击我更换图片
推荐内容
赞助商
赞助商


关于本站免责声明视频更新google百度地图视频地图RRS订阅

如有什么问题请在本站留言,或发邮件到 hxt167#foxmail.com