linux不同版本间驱动加载方法文档格式.docx

上传人:b****3 文档编号:7718651 上传时间:2023-05-09 格式:DOCX 页数:26 大小:23.80KB
下载 相关 举报
linux不同版本间驱动加载方法文档格式.docx_第1页
第1页 / 共26页
linux不同版本间驱动加载方法文档格式.docx_第2页
第2页 / 共26页
linux不同版本间驱动加载方法文档格式.docx_第3页
第3页 / 共26页
linux不同版本间驱动加载方法文档格式.docx_第4页
第4页 / 共26页
linux不同版本间驱动加载方法文档格式.docx_第5页
第5页 / 共26页
linux不同版本间驱动加载方法文档格式.docx_第6页
第6页 / 共26页
linux不同版本间驱动加载方法文档格式.docx_第7页
第7页 / 共26页
linux不同版本间驱动加载方法文档格式.docx_第8页
第8页 / 共26页
linux不同版本间驱动加载方法文档格式.docx_第9页
第9页 / 共26页
linux不同版本间驱动加载方法文档格式.docx_第10页
第10页 / 共26页
linux不同版本间驱动加载方法文档格式.docx_第11页
第11页 / 共26页
linux不同版本间驱动加载方法文档格式.docx_第12页
第12页 / 共26页
linux不同版本间驱动加载方法文档格式.docx_第13页
第13页 / 共26页
linux不同版本间驱动加载方法文档格式.docx_第14页
第14页 / 共26页
linux不同版本间驱动加载方法文档格式.docx_第15页
第15页 / 共26页
linux不同版本间驱动加载方法文档格式.docx_第16页
第16页 / 共26页
linux不同版本间驱动加载方法文档格式.docx_第17页
第17页 / 共26页
linux不同版本间驱动加载方法文档格式.docx_第18页
第18页 / 共26页
linux不同版本间驱动加载方法文档格式.docx_第19页
第19页 / 共26页
linux不同版本间驱动加载方法文档格式.docx_第20页
第20页 / 共26页
亲,该文档总共26页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

linux不同版本间驱动加载方法文档格式.docx

《linux不同版本间驱动加载方法文档格式.docx》由会员分享,可在线阅读,更多相关《linux不同版本间驱动加载方法文档格式.docx(26页珍藏版)》请在冰点文库上搜索。

linux不同版本间驱动加载方法文档格式.docx

MODULE_LICENSE("

GPL"

);

MODULE_AUTHOR("

wzt"

structmodule*m=&

__this_module;

intprint_module_test(void)

{

structmodule*mod;

list_for_each_entry(mod,&

m->

list,list){

printk("

%s\n"

mod->

name);

}

returnNULL;

}

staticintlist_print_init(void)

loadlist_printmodule.\n"

print_module_test();

return0;

staticvoidlist_print_exit(void)

unloadlist_printmodule.\n"

module_init(list_print_init);

module_exit(list_print_exit);

我们在centos5.3环境中编译一下:

[root@localhostlist]#uname-a

Linuxlocalhost.localdomain2.6.18-128.el5#1SMPWedJan2110:

44:

23EST2009i686i686i386GNU/Linux

然后拷贝到另一台主机centos5.1xen上:

[root@localhost~]#uname-a

Linuxlocalhost.localdomain2.6.18-53.el5xen#1SMPMonNov1203:

26:

12EST2007i686i686i386GNU/Linux

用insmod加载:

[root@localhost~]#insmodlist.ko

insmod:

errorinserting'

list.ko'

:

-1Invalidmoduleformat

报错了,在看下dmesg的信息:

[root@localhost~]#dmesg|tail-n1

list:

disagreesaboutversionofsymbolstruct_module

先不管这是什么,总之我们的模块在另一台2.6.18的主机中加载失败。

通常的做法是要在主机中对源代码进行编译,

然后才能加载成功,但是如果主机中缺少内核编译环境的话,我们的rootkit就不能编译,也不能安装在主机之中,

这是多么尴尬的事情:

)。

没错,这就是linuxkernel开发的特点,你别指望像windows驱动一样,编译一个驱动,

然后可以满世界去装^_^.一些rootkit开发者抛弃了lkm类型rk的开发,转而去打kmem,mem的注意,像sk,

moodnt这样的rk大家都喜欢,可以在用户层下动态patch内核,不需要编译环境,wget下来,install即可。

但是它也有很多缺点,比如很不稳定,而且在2.6.x后内核已经取消了kmem这个设备,mem文件也做了映射和读写的

限制。

rk开发者没法继续sk的神话了。

反过来,如果我们的lkm后门不需要编译环境,也可以达到直接insmod的目的,

这是件多么美好的事情,而且lkm后门更加稳定,还不用像sk在内核中添加了很多自己的数据结构。

2、内核是怎么实现的

我们去看看内核在加载模块的时候都干了什么,或许我们可以发现点bug,然后做点手脚,欺骗过去:

grep下dmesg里的关键字,看看它在哪个文件中:

[root@localhostlinux-2.6.18]#grep-r-i'

disagreesabout'

kernel/

kernel/module.c:

%s:

disagreesaboutversionofsymbol%s\n"

2.6.18/kernel/module.c:

insmod调用了sys_init_module这个系统调用,然后进入load_module这个主函数,它解析elf格式的ko文件,然后加载

到内核中:

/*Allocateandloadthemodule:

notethatsizeofsection0isalways

zero,andwerelyonthisforoptionalsections.*/

staticstructmodule*load_module(void__user*umod,

unsignedlonglen,

constchar__user*uargs)

...

if(!

check_modstruct_version(sechdrs,versindex,mod)){

err=-ENOEXEC;

gotofree_hdr;

modmagic=get_modinfo(sechdrs,infoindex,"

vermagic"

/*Thisisallowed:

modprobe--forcewillinvalidateit.*/

modmagic){

add_taint(TAINT_FORCED_MODULE);

printk(KERN_WARNING"

noversionmagic,taintingkernel.\n"

mod->

}elseif(!

same_magic(modmagic,vermagic)){

printk(KERN_ERR"

versionmagic'

%s'

shouldbe'

\n"

name,modmagic,vermagic);

check_modstruct_version就是用来计算模块符号的一些crc值,不相同就会出现我们在dmesg里看到的

“disagreesaboutversionofsymbol”信息。

get_modinfo取得了内核本身的vermagic值,然后用same_magic

函数和内核的vermagic去比较,不同也会使内核加载失败。

所以在这里,我们看到内核对模块验证的时候采用了

2层验证的方法:

模块crc值和vermagic检查。

继续跟踪check_modstruct_version,现在的内核默认的都开启了CONFIG_MODVERSIONS,如果没有指定这个选项,

函数为空,我们的目的是要在As,Centos下安装模块,redhat不是吃干饭的,当然开了MODVERSIONS选项。

staticinlineintcheck_modstruct_version(Elf_Shdr*sechdrs,

unsignedintversindex,

structmodule*mod)

constunsignedlong*crc;

structmodule*owner;

__find_symbol("

struct_module"

&

owner,&

crc,1))

BUG();

returncheck_version(sechdrs,versindex,"

mod,

crc);

__find_symbol找到了struct_module这个符号的crc值,然后调用check_version去校验:

staticintcheck_version(Elf_Shdr*sechdrs,

constchar*symname,

structmodule*mod,

constunsignedlong*crc)

unsignedinti,num_versions;

structmodversion_info*versions;

/*Exportingmoduledidn'

tsupplycrcs?

OK,we'

realreadytainted.*/

crc)

return1;

versions=(void*)sechdrs[versindex].sh_addr;

num_versions=sechdrs[versindex].sh_size

/sizeof(structmodversion_info);

for(i=0;

i<

num_versions;

i++){

if(strcmp(versions[i].name,symname)!

=0)

continue;

if(versions[i].crc==*crc)

name,symname);

DEBUGP("

Foundchecksum%lXvsmodule%lX\n"

*crc,versions[i].crc);

/*Notinmodule'

sversiontable.OK,butthattaintsthekernel.*/

(tainted&

TAINT_FORCED_MODULE)){

noversionfor\"

%s\"

found:

kerneltainted.\n"

它搜寻elf的versions小节,循环遍历数组中的每个符号表,找到struct_module这个符号,然后去比较crc的值。

现在有个疑问,versions小节是怎么链接到模块的elf文件中去的呢?

在看下编译后的生成文件,有一个list.mod.c

[root@localhostlist]#catlist.mod.c

linux/vermagic.h>

linux/compiler.h>

MODULE_INFO(vermagic,VERMAGIC_STRING);

structmodule__this_module

__attribute__((section("

.gnu.linkonce.this_module"

)))={

.name=KBUILD_MODNAME,

.init=init_module,

#ifdefCONFIG_MODULE_UNLOAD

.exit=cleanup_module,

#endif

};

staticconststructmodversion_info____versions[]

__attribute_used__

__versions"

{0x89e24b9c,"

},

{0x1b7d4074,"

printk"

staticconstchar__module_depends[]

.modinfo"

)))=

"

depends="

;

MODULE_INFO(srcversion,"

26DB52D8A56205333D414B9"

这个文件是模块在编译的时候,调用了linux-2.6.18/scripts/modpost这个文件生成的。

里面增加了2个小节.gnu.linkonce.this_module和__versions。

__versions小节的内容就是

一些字符串和值组成的数组,check_version就是解析这个小节去做验证。

这里还有一个

MODULE_INFO宏用来生成模块的magic字符串,这个在以后的vermagic中要做验证。

先看下vermagic的格式:

[root@localhostlist]#modinfolist.ko

filename:

list.ko

author:

wzt

license:

GPL

srcversion:

26DB52D8A56205333D414B9

depends:

vermagic:

2.6.18-128.el5SMPmod_unload686REGPARM4KSTACKSgcc-4.1

这里可以看到vermagic跟内核版本,smp,gcc版本,内核堆栈大小都有关。

/*Firstpartiskernelversion,whichweignore.*/

staticinlineintsame_magic(constchar*amagic,constchar*bmagic)

amagic+=strcspn(amagic,"

"

bmagic+=strcspn(bmagic,"

returnstrcmp(amagic,bmagic)==0;

same_magic忽略了对内核版本的判断,直接比较后面的值。

3、怎样去突破

知道了内核是怎么实现的了,下面开始想办法绕过这些验证:

3.1怎么突破crc验证:

在仔细看下代码:

check_version在循环中只是在寻找struct_module符号,如果没找到呢?

它会直接返回1!

没错,这是一个

逻辑bug,在正常情况下,module必会有一个struct_module的符号,这是modpost生成的。

如果我们修改elf文件,

把struct_module这个符号改名,岂不是就可以绕过crc验证了吗?

先做个实验看下:

.mod.c是由modpost这个工具生成的,它在linux-2.6.18/scripts/Makefile.modpost文件中被调用,去看下:

PHONY+=__modpost

__modpost:

$(wildcardvmlinux)$(modules:

.ko=.o)FORCE

$(callcmd,modpost)

我们用一个很土的方法,就是在编译模块的时候,modpost生成.mod.c文件后,暂停下编译,sleep30秒吧,我们用

这个时间去改写下.mod.c,把struct_module换个名字。

@sleep30

随便将struct_module改个名:

stauct_module"

我们是在centos5.3下编译的,然后拷贝到centos5.1下,在执行下insmod看下:

[root@localhost~]#dmesg|tail

ata_piix

libata

sd_mod

scsi_mod

ext3

jbd

ehci_hcd

ohci_hcd

uhci_hcd

成功了!

这跟我们预期的一样,我们用这个逻辑bug绕过了模块的crc验证!

这个bug直到2.6.31版本中

才得到修正。

我们可以用这种方法在redhat主机中任意安装模块了。

那么怎样绕过在2.6.31以后的内核呢?

看下它是怎么修补的:

if(strcmp(versions[i].name,symname)!

continue;

if(versions[i].crc==*crc)

return1;

DEBUGP("

*crc,versions[i].crc);

gotobad_version;

nosymbolversionfor%s\n"

bad_version:

如果没找到struct_module也会返回0,这样我们就必须将struct_module的值改为正确后,才能继续安装。

如何找到模块符号的crc值呢?

我们可以去找目标主机中那些已被系统加载的模块的crc值,如ext3文件系统

的模块,自己写个程序去解析elf文件,就可以得到某些符号的crc值了。

还有没有更简单的方法呢?

去/boot目录下看看,symvers-2.6.18-128.el5.gz貌似和crc有关,gunzip解压后看看:

[root@localhostboot]#grep'

struct_module'

symvers-2.6.18-128.el5

0x89e24b9cstruct_modulevmlinuxEXPORT_SYMBOL

原来内核中所有符号的crc值都保存在这个文件中。

如何改写struct_module的值呢,可以用上面那个土方法,

或者自己写程序去解析elf文件,然后改写其值。

本文

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > IT计算机 > 电脑基础知识

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2