- 论坛徽章:
- 0
|
个人认为武断地清除和设置 cr0 的权限位也不合理,更合理的是,保存原来的 cr0,干完坏事之后再恢复回去。
多嘴说点题内话,用 kprobe 这类``官方''提供的方法来插入自己的逻辑很不美,受制于人。要做到真正意义的劫持, fork/vfork/clone/execve 这一系列的系统调用,唯一的方法是:RTFC,搞懂了 entry.S,解决方案就呼之欲出。
首先要明确,fork/vfork/clone/execve 这一系列系统调用比较特殊,系统调用表里的对应项不像其它系统调用那样是 C 函数地址,而是汇编代码的地址 (stub_XXXX),在这些 stub_XXXX 前头一段注释这么说:
/*
* Certain special system calls that need to save a complete full stack frame.
*/ |
对 execve,看内核怎么玩的:
ENTRY(stub_execve)
CFI_STARTPROC
popq %r11
CFI_ADJUST_CFA_OFFSET -8
CFI_REGISTER rip, r11
SAVE_REST
FIXUP_TOP_OF_STACK %r11
movq %rsp, %rcx
call sys_execve
RESTORE_TOP_OF_STACK %r11
movq %rax,RAX(%rsp)
RESTORE_REST
jmp int_ret_from_sys_call
CFI_ENDPROC
END(stub_execve) |
如果像劫持其它系统调用那样把系统调用表对应 __NR_execve 的那项改成了自己实现的 C 函数地址,并且在该 C 函数内妄图调用原始的系统调用例程 (oops, 是 stub_execve),必死无疑,因为寄存器全乱了 (所以所谓的栈要调平衡一说并不准确,而是内核汇编代码将要放入栈的寄存器值被破坏了)。要么:
1. 整明白内核那段汇编是干什么的,要保存/恢复那些寄存器,自己照样做,多挂几次机,就想明白了 有些宏在 calling.h 中定义。要么:
2. 要是实在不想和底层机制玩命,有一个投机取巧的方法,看到那句可爱的:``call sys_execve'' 了没有,找到它 (它的 opcode 是 0xe9 .. .. .. .. ),把后面的操作数,也就是一个 C 函数, sys_execve 地址的偏移,换成自己实现的一个 asmlinkage 的 C 函数的偏移值即可,这样在自己的 C 函数里就可以在调用 sys_execve 之前之后为所欲为,因为 sys_execve 是 asmlinkage 的,编译器替我们保证参数正确。
要劫持 fork/vfork/clone 也只需要那么一点点技巧,看内核代码:
.macro PTREGSCALL label,func,arg
.globl \label
\label:
leaq \func(%rip),%rax
leaq -ARGOFFSET+8(%rsp),\arg /* 8 for return address */
jmp ptregscall_common
END(\label)
.endm
...
PTREGSCALL stub_clone, sys_clone, %r8
...
ENTRY(ptregscall_common)
popq %r11
CFI_ADJUST_CFA_OFFSET -8
CFI_REGISTER rip, r11
SAVE_REST
movq %r11, %r15
CFI_REGISTER rip, r15
FIXUP_TOP_OF_STACK %r11
call *%rax
RESTORE_TOP_OF_STACK %r11
movq %r15, %r11
CFI_REGISTER rip, r11
RESTORE_REST
pushq %r11
CFI_ADJUST_CFA_OFFSET 8
CFI_REL_OFFSET rip, 0
ret
CFI_ENDPROC
END(ptregscall_common) |
看看,又是 jmp 又是 call 的,应该清楚要做什么了。
注意:2.6.29开始,PTREGSCALL 宏的定义变了,于是 hack 的方式要跟着变。
[ 本帖最后由 vupiggy 于 2010-1-20 18:50 编辑 ] |
|