天天看点

linux劫持进程函数,Linux系统内核劫持方法分析(3)

call *sys_call_table(0, %eax, 4)    //Calling sys_call_table[eax]

movl %eax,PT_EAX(%esp)    //Storing of return value

系统调用例程核心。eax寄存器存放系统调用号,即sys_call_table数组索引值,指向

某个特定系统调用函数。函数返回值将存放到栈中的eax寄存器中,返回给用户空间。尽管

系统调用例程核心很适合劫持,但我们不利用此位置,因为系统调用表指针是当前各种扫描

工具首要的检测点。

cli                                   //Clear Interrupts

movl TI_flags(%ebp), %ecx              //Copy process flags in ecx

testw $_TIF_ALLWORK_MASK, %cx     //Is needed extra work?

jne syscallexitwork                   //If so, do extra work

当系统调用函数返回时,系统会屏蔽所有中断,进程测试是否有额外的工作(确信不丢

失需要调度或发信号挂起的中断)。上面的代码片段提供了另一个劫持机会。movl和testw

指令共8字节大小,足以存放JMP指令,而且这两条指令完全独立不在任一标签体内,可复制。

RESTORE_REGS     //CPU’s registers restoration

addl $4, %esp       //Clearing up system call number from stack

iret           //Return from interrupt

调用例程实现体尾部即准备从系统态切回到用户态。用暂存在栈上的值恢复所有CPU寄

存器值,清除系统调用号,触发iret指令。尾部指令也可作为劫持位置,但问题是当进程被

跟踪时,并不会使用这些代码片段。

3.2 改变系统调用例程中的程序控制流

通过3.1 小节分析,我们已经在系统调用例程中确定了两个合适位置可劫持系统控制流

程。在 2.6内核的所有版本都兼容这种方式的更改,具备很好的兼容性和可用性。我们的目

的是修改系统调用函数的返回值,即在原函数调用后,再劫持转入到 hack 函数执行。故,

我们将确定选择第二个位置实现劫持,如图2 所示。否则,若在函数还未调用之前,转入攻

击者设置的hack函数时,执行完hack 函数后,再调用原函数,则无法实现hack函数目的,

如隐藏文件效果等,而且若不再调用原函数,显然也不合乎逻辑,否则上层应用程序明明是

调用 fork 函数创建一个子进程,却没有实现此功能,很容易被用户感觉到存在内核钩子程

序。

我们重写了movl TI_flags(%ebp), %ecx 和testw $_TIF_ALLWORK_MASK, %cx

两条指令,并跳转到trampoline()函数中重新执行,但在重新执行上面两条指令之前,事先

保存了栈顶地址值,以确保能准确访问到系统调用结果,而后调用hack函数,修改原系统调

用的结果信息,如过滤待隐藏的木马文件、恶意进程等。执行完此函数后,再对此函数的栈

痕迹进行清理,最后重新jmp到原位置继续执行。

实验

为了验证前面提出的劫持方法,笔者基于此方法开发了两款rootkits,分别为MoleKit

和 Powerkit。MoleKit能够借助/dev/mem文件有效渗透到系统。Molekit可提供一些基本的

服务,如进程、目录隐藏等。因为这种攻击方式涉及到很多启发式搜索,如在内存中寻找代

码片段特征值等,但这也是一种很好的思路,可以在不借助可加载模块支持前提下,实现系

统渗透;Powerkit则是使用内核模块渗透到内核,其主要好处是可方便访问内核API,并实

现 keylogging或权限提升等。

小结

本文给出了劫持Linux内核的一个新方法,此类攻击在2.6内核的所有版本上均验证可

行,并给出了两款基于此技术的Rootkit,且当前并没有很好的Anti-Rootkit或扫描器等工

具能够检测此类攻击。