世上的牛人真是多,今天又见识了一位
技术文章写得如此幽默 易懂,真是太牛了(相比之下我太菜了) ring3下直接得到内核符号地址,这样rootkits就可以脱离LKM方式了, 可是我居然还没有学汇编 ,fuck这学校 这个冬天该好好把那几本kernel砖头捧读下,自学下x86汇编,我的水平太烂 原文 http://blog.youkuaiyun.com/varg_vikernes/archive/2008/11/08/3254821.aspx 作者:varg_vikernes rootkit for linux 2.寻找入口点 很多人都学汇编。什么是eip他背得倍儿熟。但是你问他怎么把eip的值传给eax,他会毫不犹豫的说“mov eax, eip”。 很多人都学操作系统。什么是内存管理他背得倍儿熟。但是你打开linux-2.6.18的文件夹,他会指着那个mm文件夹说“那个是啥,快打开,里面有mm照片么?” 于是,在填鸭式的学习中,我们习惯于湮没在老师的无数唾沫里,湮没在书本的无数概念里,湮没在课堂的无数瞌睡里,湮没在宿舍的无数盘dota里。直 到有一天,你发现用asp.net,c#,java,vb都无法写出你想要的shellcode时,你恍然大悟,众里寻她千百度,那人却在灯火阑珊处。你 所追随的她,是被你曾经抛弃的操作系统和汇编。
好了扯淡完毕。先回答上一节的问题。其实这个漏洞只用来做提权实在是大材小用了。作者写一个漏洞利用程序只是个示范而已,不是让骇客们真的拿去提权。而是让我们自己扩充它,实现自己的功能,实现自己的rootkit。
我们来到ring0下面后,那是手无寸铁啊。平常你写内核模块的时候,有啥函数直接拿来用就是了,但是现在不行。你身处一个如此荒凉的地方,你能获 得的只有当前进程的task_struct。而这个也不靠谱,因为各个版本的linux,各种各样的内核设置,导致这个结构里特定成员的偏移都有可能不一 样。所以我们就丢开这个不管了。 怎样获得内核函数地址?这是个问题。如果你不获得函数地址,就啥也做不了。就好比搞自杀式袭击的,到了目的地,发现炸弹不见了,那也只能喝杯咖啡,然后再返回基地组织。 在内核模块中,通过函数名字获取函数地址用的是kallsyms_lookup_name。但现在你连kallsyms_lookup_name这个函数的地址都不知道。我们先来看看这个函数的实现: kallsyms_lookup_name()
kallsyms_lookup_name() -> kallsyms_expand_symbol()
看清楚没? kallsyms_names 这个数组里的内容是 len0, idx0_0, idx0_1, idx0_2 ... len1, idx1_0, idx1_1 .... 得到一系列idx后, 把idx0_0带入kallsyms_token_table[ kallsyms_token_index[] ]里,找到第一个字符串。 把idx0_1带入,找到第二个字符串。 把idx0_n带入,其中n为len0-1,找到最后一个字符串。 把所有的字符串连起来,就是第一个内核符号的名字。 这样,把所有的内核符号名字按顺序都获取一次,与传入的参数比较,如果相等,就返回对应的地址。 这是用的一种压缩算法,可以减少内核符号表占用的空间。 编译内核的时候,源码树中script/kallsyms.c这个程序生成了内核符号表的汇编源码,链接完后,内核的镜像里就有了符号表。你可以在kernel/kallsyms.c中找到定义
但是你找不到kallsyms_addresses和kallsyms_names的定义在哪里。因为编译过程中,script/kallsyms.c生成的内核符号表的汇编源码放在/tmp目录下,用完就删了,你当然找不到。
上面分析的过程看不懂没关系,只要明白一个道理:写kallsyms.c的程序员是很欠抽的。 在当今1G硬盘不需要1块钱,1G内存只要几十块钱的时代,你为了节省那么点空间,写了这么欠抽的代码出来,内核符号表再大,有你硬盘里的松岛枫毛片大吗,有你硬盘里的陈冠希艳照多吗?你这样写,知不知道有什么后果?所以,我们不能通过“暴搜”的方法找到内核符号表。
其实,内核符号表在/proc/kallsyms中是可以看到的。所以,我们通过读/proc/kallsyms可以读出所有的内核符号和地址。你可能会说,那我们刚刚还看kallsyms_lookup_name干啥?不是浪费时间么? 不 是的,读/proc/kallsyms毕竟是有点低劣的方法,因为要读你也只能用系统调用去读,目前你还不能越过系统调用直接去读proc entry的。如果用系统调用去读/proc/kallsyms那就必定要经过那一套操作系统的检测流程。在vfs_read里有这样的代码:
你看看,你要经过两大关。 第一关是security_file_permission。这个函数看名字都知道它是干嘛的了。是rootkit最讨厌的东西。不过所幸内核的默认设置是允许读/proc/kallsyms的。而这个文件,ring3下的普通用户也有读的权限。 第 二关是fsnotify_access。这函数来自于文件系统的inotify 机制,这机制基于inode,一般都是在inode被读,被写等等时候给关注这个事件的人一个信号“这个inode被读/写了”,简单的说就是这样。最麻 烦的是,这个机制是给ring3下的进程用的。所以,如果有一个进程注册了inotify,并关注/proc/kallsyms。那你就露馅了。
这方法有一定的危险性。 不过我在google上搜了很久也没搜出来有没啥更好的方法,如果有好的方法,迫切希望有人能告诉我。
另外还有一个“偏方”能读到搞到内核符号表。 比如很多人都没删除“System.map-xxx”这个文件,其实这个文件就是内核符号表,与/proc/kallsyms不同的是,它不包括模块的符号表,如果找到了这个文件,确定它是与现在内核一起编译生成的(这样才配套),用它也成。 但这个偏方要你在ring3下操作,还挺不靠谱的。
所以啊,我们有时候不要追求得太高了。你喜欢喝牛奶,但没有牛奶的时候你还得和水。没有水的时候你还得喝。。算了不说了。
如果你在ring3下用过系统调用,那现在在ring0下读/proc/kallsyms的过程也是类似的,只不过要把ds设置为kernel_ds,这样sys_read函数就不检查参数的地址了,直接读。 代码如下:
这段代码有个bug,在比较字符串的地方。/proc/kallsyms输出的格式,对于模块里的符号,会在最后面加一个“[模块名]”。 所以不能用这段代码找模块里的函数。大家要用自己改吧。我也懒得改了,反正我一开始不用找内核里的函数。 好了,那现在,你就可以找到大部分函数了,少部分未导出的找不到,但也够你用的了。
你说现在干啥呢?
有人说“我想搞破坏!”。 好,那你就搜索panic函数。然后panic("hey, your system is fucked!! hacked by xxx/n"); 看系统被你panic了。靠,你太伟大了,我们搞了这么半天就是没让系统panic,你一下子就让系统panic了!那后面的文章你也不用看了,因为系统已经panic了,秘密行动失败了,你也知道有啥后果吧。
有人说“我想做rootkit” 好,那下一节的内容你可能会很感兴趣。 |
[zz]rootkit for linux 2.寻找入口点
最新推荐文章于 2023-08-25 17:12:30 发布
2008-12-06 16:22