亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

Chinaunix

標(biāo)題: 突破linux內(nèi)核模塊驗(yàn)證 [打印本頁]

作者: W.Z.T    時(shí)間: 2009-12-25 10:55
標(biāo)題: 突破linux內(nèi)核模塊驗(yàn)證
本篇文章是講內(nèi)核安全方面的, 不感興趣的同學(xué)可繞過, 文章寫的比較倉促, 有問題的話, 歡迎指出。

Bypassing Linux kernel module version check

By wzt

1、 為什么要突破模塊驗(yàn)證
2、 內(nèi)核是怎么實(shí)現(xiàn)的
3、 怎樣去突破
4、 總結(jié)
5、 參考
6、 附錄


1、 為什么要突破模塊驗(yàn)證
    Linux內(nèi)核版本很多,升級(jí)很快,2個(gè)小內(nèi)核版本中內(nèi)核函數(shù)的定義可能都不一樣,為了確保不一致的驅(qū)動(dòng)程序?qū)е耴ernel oops,
    開發(fā)者加入了模塊驗(yàn)證機(jī)制。它在加載內(nèi)核模塊的時(shí)候?qū)δK進(jìn)行校驗(yàn), 如果模塊與主機(jī)的一些環(huán)境不一致,就會(huì)加載不成功。
    看下面一個(gè)例子,它簡(jiǎn)單的輸出當(dāng)期系統(tǒng)中的模塊列表:

  1. #include <linux/kernel.h>
  2. #include <linux/module.h>
  3. #include <linux/init.h>
  4. #include <linux/version.h>
  5. #include <linux/string.h>
  6. #include <linux/list.h>

  7. MODULE_LICENSE("GPL");
  8. MODULE_AUTHOR("wzt");

  9. struct module *m = &__this_module;

  10. int print_module_test(void)
  11. {
  12.         struct module *mod;

  13.         list_for_each_entry(mod, &m->list, list) {
  14.                 printk("%s\n", mod->name);
  15.         }
  16.         return NULL;
  17. }

  18. static int list_print_init(void)
  19. {
  20.         printk("load list_print module.\n");

  21.         print_module_test();

  22.         return 0;
  23. }

  24. static void list_print_exit(void)
  25. {
  26.         printk("unload list_print module.\n");
  27. }

  28. module_init(list_print_init);
  29. module_exit(list_print_exit);
復(fù)制代碼

我們?cè)赾entos5.3環(huán)境中編譯一下:

  1. [root@localhost list]# uname -a
  2. Linux localhost.localdomain 2.6.18-128.el5 #1 SMP Wed Jan 21 10:44:23 EST 2009 i686 i686 i386 GNU/Linux
復(fù)制代碼

然后拷貝到另一臺(tái)主機(jī)centos5.1xen上:

  1. [root@localhost ~]# uname -a
  2. Linux localhost.localdomain 2.6.18-53.el5xen #1 SMP Mon Nov 12 03:26:12 EST 2007 i686 i686 i386 GNU/Linux
復(fù)制代碼

用insmod加載:

  1. [root@localhost ~]# insmod list.ko
  2. insmod: error inserting 'list.ko': -1 Invalid module format
復(fù)制代碼

報(bào)錯(cuò)了,在看下dmesg的信息:

  1. [root@localhost ~]# dmesg|tail -n 1
  2. list: disagrees about version of symbol struct_module
復(fù)制代碼

先不管這是什么, 總之我們的模塊在另一臺(tái)2.6.18的主機(jī)中加載失敗。 通常的做法是要在主機(jī)中對(duì)源代碼進(jìn)行編譯,
然后才能加載成功, 但是如果主機(jī)中缺少內(nèi)核編譯環(huán)境的話, 我們的rootkit就不能編譯, 也不能安裝在主機(jī)之中,
這是多么尷尬的事情。 沒錯(cuò), 這就是linux kernel開發(fā)的特點(diǎn), 你別指望像windows驅(qū)動(dòng)一樣,編譯一個(gè)驅(qū)動(dòng),
然后可以滿世界去裝^_^. 一些rootkit開發(fā)者拋棄了lkm類型rk的開發(fā), 轉(zhuǎn)而去打kmem, mem的注意,像sk,
moodnt這樣的rk大家都喜歡, 可以在用戶層下動(dòng)態(tài)patch內(nèi)核,不需要編譯環(huán)境, wget下來,install即可。
但是它也有很多缺點(diǎn),比如很不穩(wěn)定,而且在2.6.x后內(nèi)核已經(jīng)取消了kmem這個(gè)設(shè)備, mem文件也做了映射和讀寫的
限制。 rk開發(fā)者沒法繼續(xù)sk的神話了。反過來, 如果我們的lkm后門不需要編譯環(huán)境,也可以達(dá)到直接insmod的目的,
這是件多么美好的事情,而且lkm后門更加穩(wěn)定,還不用像sk在內(nèi)核中添加了很多自己的數(shù)據(jù)結(jié)構(gòu)。


2、內(nèi)核是怎么實(shí)現(xiàn)的
   我們?nèi)タ纯磧?nèi)核在加載模塊的時(shí)候都干了什么, 或許我們可以發(fā)現(xiàn)點(diǎn)bug, 然后做點(diǎn)手腳,欺騙過去:)
   grep下dmesg里的關(guān)鍵字, 看看它在哪個(gè)文件中:

  1. [root@localhost linux-2.6.18]# grep -r -i 'disagrees about' kernel/
  2. kernel/module.c:                printk("%s: disagrees about version of symbol %s\n",
復(fù)制代碼

2.6.18/kernel/module.c:
insmod調(diào)用了sys_init_module這個(gè)系統(tǒng)調(diào)用, 然后進(jìn)入load_module這個(gè)主函數(shù),它解析elf格式的ko文件,然后加載
到內(nèi)核中:

  1. /* Allocate and load the module: note that size of section 0 is always
  2.    zero, and we rely on this for optional sections. */
  3. static struct module *load_module(void __user *umod,
  4.                                   unsigned long len,
  5.                                   const char __user *uargs)
  6. {
  7. ...
  8.         if (!check_modstruct_version(sechdrs, versindex, mod)) {
  9.                 err = -ENOEXEC;
  10.                 goto free_hdr;
  11.         }

  12.         modmagic = get_modinfo(sechdrs, infoindex, "vermagic");
  13.         /* This is allowed: modprobe --force will invalidate it. */
  14.         if (!modmagic) {
  15.                 add_taint(TAINT_FORCED_MODULE);
  16.                 printk(KERN_WARNING "%s: no version magic, tainting kernel.\n",
  17.                        mod->name);
  18.         } else if (!same_magic(modmagic, vermagic)) {
  19.                 printk(KERN_ERR "%s: version magic '%s' should be '%s'\n",
  20.                        mod->name, modmagic, vermagic);
  21.                 err = -ENOEXEC;
  22.                 goto free_hdr;
  23.         }
  24. ...
  25. }
復(fù)制代碼

check_modstruct_version就是用來計(jì)算模塊符號(hào)的一些crc值,不相同就會(huì)出現(xiàn)我們?cè)赿mesg里看到的
“disagrees about version of symbol”信息。 get_modinfo取得了內(nèi)核本身的vermagic值,然后用same_magic
函數(shù)和內(nèi)核的vermagic去比較,不同也會(huì)使內(nèi)核加載失敗。 所以在這里,我們看到內(nèi)核對(duì)模塊驗(yàn)證的時(shí)候采用了
2層驗(yàn)證的方法:模塊crc值和vermagic檢查。

繼續(xù)跟蹤check_modstruct_version, 現(xiàn)在的內(nèi)核默認(rèn)的都開啟了CONFIG_MODVERSIONS, 如果沒有指定這個(gè)選項(xiàng),
函數(shù)為空,我們的目的是要在As, Centos下安裝模塊,redhat不是吃干飯的, 當(dāng)然開了MODVERSIONS選項(xiàng)。

  1. static inline int check_modstruct_version(Elf_Shdr *sechdrs,
  2.                                           unsigned int versindex,
  3.                                           struct module *mod)
  4. {
  5.         const unsigned long *crc;
  6.         struct module *owner;

  7.         if (!__find_symbol("struct_module", &owner, &crc, 1))
  8.                 BUG();
  9.         return check_version(sechdrs, versindex, "struct_module", mod,
  10.                              crc);
  11. }
復(fù)制代碼

__find_symbol找到了struct_module這個(gè)符號(hào)的crc值,然后調(diào)用check_version去校驗(yàn):

  1. static int check_version(Elf_Shdr *sechdrs,
  2.                          unsigned int versindex,
  3.                          const char *symname,
  4.                          struct module *mod,
  5.                          const unsigned long *crc)
  6. {
  7.         unsigned int i, num_versions;
  8.         struct modversion_info *versions;

  9.         /* Exporting module didn't supply crcs?  OK, we're already tainted. */
  10.         if (!crc)
  11.                 return 1;

  12.         versions = (void *) sechdrs[versindex].sh_addr;
  13.         num_versions = sechdrs[versindex].sh_size
  14.                 / sizeof(struct modversion_info);

  15.         for (i = 0; i < num_versions; i++) {
  16.                 if (strcmp(versions[i].name, symname) != 0)
  17.                         continue;

  18.                 if (versions[i].crc == *crc)
  19.                         return 1;
  20.                 printk("%s: disagrees about version of symbol %s\n",
  21.                        mod->name, symname);
  22.                 DEBUGP("Found checksum %lX vs module %lX\n",
  23.                        *crc, versions[i].crc);
  24.                 return 0;
  25.         }
  26.         /* Not in module's version table.  OK, but that taints the kernel. */
  27.         if (!(tainted & TAINT_FORCED_MODULE)) {
  28.                 printk("%s: no version for \"%s\" found: kernel tainted.\n",
  29.                        mod->name, symname);
  30.                 add_taint(TAINT_FORCED_MODULE);
  31.         }
  32.         return 1;
  33. }
復(fù)制代碼

它搜尋elf的versions小節(jié), 循環(huán)遍歷數(shù)組中的每個(gè)符號(hào)表,找到struct_module這個(gè)符號(hào),然后去比較crc的值。
現(xiàn)在有個(gè)疑問, versions小節(jié)是怎么鏈接到模塊的elf文件中去的呢?  在看下編譯后的生成文件, 有一個(gè)list.mod.c

  1. [root@localhost list]# cat list.mod.c
  2. #include <linux/module.h>
  3. #include <linux/vermagic.h>
  4. #include <linux/compiler.h>

  5. MODULE_INFO(vermagic, VERMAGIC_STRING);

  6. struct module __this_module
  7. __attribute__((section(".gnu.linkonce.this_module"))) = {
  8. .name = KBUILD_MODNAME,
  9. .init = init_module,
  10. #ifdef CONFIG_MODULE_UNLOAD
  11. .exit = cleanup_module,
  12. #endif
  13. };

  14. static const struct modversion_info ____versions[]
  15. __attribute_used__
  16. __attribute__((section("__versions"))) = {
  17.         { 0x89e24b9c, "struct_module" },
  18.         { 0x1b7d4074, "printk" },
  19. };

  20. static const char __module_depends[]
  21. __attribute_used__
  22. __attribute__((section(".modinfo"))) =
  23. "depends=";


  24. MODULE_INFO(srcversion, "26DB52D8A56205333D414B9");
復(fù)制代碼

這個(gè)文件是模塊在編譯的時(shí)候,調(diào)用了linux-2.6.18/scripts/modpost這個(gè)文件生成的。
里面增加了2個(gè)小節(jié).gnu.linkonce.this_module和__versions。 __versions小節(jié)的內(nèi)容就是
一些字符串和值組成的數(shù)組,check_version就是解析這個(gè)小節(jié)去做驗(yàn)證。 這里還有一個(gè)
MODULE_INFO宏用來生成模塊的magic字符串,這個(gè)在以后的vermagic中要做驗(yàn)證。

先看下vermagic的格式:

  1. [root@localhost list]# modinfo list.ko
  2. filename:       list.ko
  3. author:         wzt
  4. license:        GPL
  5. srcversion:     26DB52D8A56205333D414B9
  6. depends:        
  7. vermagic:       2.6.18-128.el5 SMP mod_unload 686 REGPARM 4KSTACKS gcc-4.1
復(fù)制代碼

這里可以看到vermagic跟內(nèi)核版本,smp,gcc版本,內(nèi)核堆棧大小都有關(guān)。

  1. /* First part is kernel version, which we ignore. */
  2. static inline int same_magic(const char *amagic, const char *bmagic)
  3. {
  4.         amagic += strcspn(amagic, " ");
  5.         bmagic += strcspn(bmagic, " ");
  6.         return strcmp(amagic, bmagic) == 0;
  7. }
復(fù)制代碼

same_magic忽略了對(duì)內(nèi)核版本的判斷, 直接比較后面的值。

3、怎樣去突破

  知道了內(nèi)核是怎么實(shí)現(xiàn)的了, 下面開始想辦法繞過這些驗(yàn)證:)

  3.1 怎么突破crc驗(yàn)證:
  
  在仔細(xì)看下代碼:

  1.         for (i = 0; i < num_versions; i++) {
  2.                 if (strcmp(versions[i].name, symname) != 0)
  3.                         continue;

  4.                 if (versions[i].crc == *crc)
  5.                         return 1;
  6.                 printk("%s: disagrees about version of symbol %s\n",
  7.                        mod->name, symname);
  8.                 DEBUGP("Found checksum %lX vs module %lX\n",
  9.                        *crc, versions[i].crc);
  10.                 return 0;
  11.         }
  12.         /* Not in module's version table.  OK, but that taints the kernel. */
  13.         if (!(tainted & TAINT_FORCED_MODULE)) {
  14.                 printk("%s: no version for \"%s\" found: kernel tainted.\n",
  15.                        mod->name, symname);
  16.                 add_taint(TAINT_FORCED_MODULE);
  17.         }
  18.         return 1;
復(fù)制代碼

check_version在循環(huán)中只是在尋找struct_module符號(hào), 如果沒找到呢? 它會(huì)直接返回1!  沒錯(cuò), 這是一個(gè)
邏輯bug,在正常情況下,module必會(huì)有一個(gè)struct_module的符號(hào), 這是modpost生成的。如果我們修改elf文件,
把struct_module這個(gè)符號(hào)改名,豈不是就可以繞過crc驗(yàn)證了嗎? 先做個(gè)實(shí)驗(yàn)看下:
.mod.c是由modpost這個(gè)工具生成的, 它在linux-2.6.18/scripts/Makefile.modpost文件中被調(diào)用, 去看下:

  1. PHONY += __modpost
  2. __modpost: $(wildcard vmlinux) $(modules:.ko=.o) FORCE
  3.         $(call cmd,modpost)
復(fù)制代碼

我們用一個(gè)很土的方法, 就是在編譯模塊的時(shí)候,modpost生成.mod.c文件后, 暫停下編譯,sleep 30秒吧,我們用
這個(gè)時(shí)間去改寫下.mod.c, 把struct_module換個(gè)名字。

  1. PHONY += __modpost
  2. __modpost: $(wildcard vmlinux) $(modules:.ko=.o) FORCE
  3.         $(call cmd,modpost)
  4.         @sleep 30
復(fù)制代碼

隨便將struct_module改個(gè)名:

  1. [root@localhost list]# cat list.mod.c
  2. #include <linux/module.h>
  3. #include <linux/vermagic.h>
  4. #include <linux/compiler.h>

  5. MODULE_INFO(vermagic, VERMAGIC_STRING);

  6. struct module __this_module
  7. __attribute__((section(".gnu.linkonce.this_module"))) = {
  8. .name = KBUILD_MODNAME,
  9. .init = init_module,
  10. #ifdef CONFIG_MODULE_UNLOAD
  11. .exit = cleanup_module,
  12. #endif
  13. };

  14. static const struct modversion_info ____versions[]
  15. __attribute_used__
  16. __attribute__((section("__versions"))) = {
  17.         { 0x89e24b9c, "stauct_module" },
  18.         { 0x1b7d4074, "printk" },
  19. };

  20. static const char __module_depends[]
  21. __attribute_used__
  22. __attribute__((section(".modinfo"))) =
  23. "depends=";

  24. MODULE_INFO(srcversion, "26DB52D8A56205333D414B9");
復(fù)制代碼

我們是在centos5.3下編譯的, 然后拷貝到centos5.1下, 在執(zhí)行下insmod看下:

  1. [root@localhost ~]# insmod list.ko
  2. [root@localhost ~]# dmesg|tail
  3. ata_piix
  4. libata
  5. sd_mod
  6. scsi_mod
  7. ext3
  8. jbd
  9. ehci_hcd
  10. ohci_hcd
  11. uhci_hcd
復(fù)制代碼

成功了! 這跟我們預(yù)期的一樣, 我們用這個(gè)邏輯bug繞過了模塊的crc驗(yàn)證! 這個(gè)bug直到2.6.31版本中
才得到修正。 我們可以用這種方法在redhat主機(jī)中任意安裝模塊了。 那么怎樣繞過在2.6.31以后的內(nèi)核呢?
看下它是怎么修補(bǔ)的:

  1.         for (i = 0; i < num_versions; i++) {
  2.                 if (strcmp(versions[i].name, symname) != 0)
  3.                         continue;

  4.                 if (versions[i].crc == *crc)
  5.                         return 1;
  6.                 DEBUGP("Found checksum %lX vs module %lX\n",
  7.                        *crc, versions[i].crc);
  8.                 goto bad_version;
  9.         }

  10.         printk(KERN_WARNING "%s: no symbol version for %s\n",
  11.                mod->name, symname);
  12.         return 0;

  13. bad_version:
  14.         printk("%s: disagrees about version of symbol %s\n",
  15.                mod->name, symname);

  16.         return 0;
復(fù)制代碼

如果沒找到struct_module也會(huì)返回0, 這樣我們就必須將struct_module的值改為正確后, 才能繼續(xù)安裝。
如何找到模塊符號(hào)的crc值呢? 我們可以去找目標(biāo)主機(jī)中那些已被系統(tǒng)加載的模塊的crc值,如ext3文件系統(tǒng)
的模塊, 自己寫個(gè)程序去解析elf文件, 就可以得到某些符號(hào)的crc值了。
還有沒有更簡(jiǎn)單的方法呢?去/boot目錄下看看,symvers-2.6.18-128.el5.gz貌似和crc有關(guān),gunzip解壓后看看:

  1. [root@localhost boot]# grep 'struct_module' symvers-2.6.18-128.el5
  2. 0x89e24b9c      struct_module   vmlinux EXPORT_SYMBOL
復(fù)制代碼

原來內(nèi)核中所有符號(hào)的crc值都保存在這個(gè)文件中。如何改寫struct_module的值呢,可以用上面那個(gè)土方法,
或者自己寫程序去解析elf文件, 然后改寫其值。本文最后附上一個(gè)小程序用來修改elf的符號(hào)和crc值。

3.2 如何突破vermagic驗(yàn)證:
   如果我們用list.mod.c中的做法, 用MODULE_INFO宏來生成一個(gè)與目標(biāo)主機(jī)相同的vermagic呢? 答案是
否定的,gcc鏈接的時(shí)候會(huì)把modinfo小節(jié)鏈接在最后,加載模塊的時(shí)候還是會(huì)讀取第一個(gè).modinfo小節(jié)。
我們可以用上面那種很土的方法, 先用modinfo命令得到目標(biāo)主機(jī)中某個(gè)模塊的信息:

  1. [root@localhost list]# modinfo /lib/modules/2.6.18-128.el5/kernel/fs/ext3/ext3.ko
  2. filename:       /lib/modules/2.6.18-128.el5/kernel/fs/ext3/ext3.ko
  3. license:        GPL
  4. description:    Second Extended Filesystem with journaling extensions
  5. author:         Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others
  6. srcversion:     B048AC103E5034604A721C5
  7. depends:        jbd
  8. vermagic:       2.6.18-128.el5 SMP mod_unload 686 REGPARM 4KSTACKS gcc-4.1
  9. module_sig:     883f3504977495e4f3f897cd3dced211288209f551cc1da557f96ea18d9a4efd6cfb0fc2612e009c8845fd776c825d586f492ceab19e17b2319da8f
復(fù)制代碼

然后在用那個(gè)很土的方面, 將.mod.c中vermagic值進(jìn)行修改。還有一種直接修改elf文件的方法,附錄在本文后面。

4、總結(jié)
  前面有一點(diǎn)沒有提到, 就是某些內(nèi)核版本的相同接口的函數(shù)代碼可能已經(jīng)變化, 這樣在使用這項(xiàng)技術(shù)的時(shí)候,
  最好在同一個(gè)大內(nèi)核版本使用。你也可能感覺要想跨平臺(tái)安裝模塊有些麻煩, 這里還有2個(gè)方法, 作為一個(gè)專業(yè)
  搞滲透的人來說,他會(huì)自己在本地裝很多發(fā)行版本的linux,特別是root掉一臺(tái)主機(jī)后,會(huì)在本地裝一個(gè)一模一樣
  的發(fā)行版本,smp、kernel stack size、gcc version都一樣。在本地機(jī)器裝上開發(fā)環(huán)境,這樣編譯出來的模塊
  也是可以直接裝到目標(biāo)主機(jī)上的,但這很麻煩,因?yàn)閘inux有太多的發(fā)行版本了:), 另一個(gè)方法就是自己
  裝一個(gè)linux,編譯下內(nèi)核,然后將build后的開發(fā)包集成到自己的后門里, 壓縮后大概幾m。 然后傳到主機(jī)
  去解壓,編譯。慶幸的是,現(xiàn)在大多數(shù)主機(jī)中都有內(nèi)核開發(fā)環(huán)境, 直接去主機(jī)編譯就ok了。

5、參考
【1】 linux kernel source code
       http://www.kernel.org
【2】 module injection in 2.6 kernel - Coolq
       http://www.nsfocus.net/index.php ... o=view&mid=2533

[ 本帖最后由 W.Z.T 于 2009-12-25 11:00 編輯 ]
作者: W.Z.T    時(shí)間: 2009-12-25 10:56
6、附錄


  1. /*
  2. * Linux kernel module fucker
  3. *
  4. * by wzt       <[email]wzt.wzt@gmail.com[/email]>
  5. *
  6. */

  7. #include <stdio.h>
  8. #include <string.h>
  9. #include <stdlib.h>
  10. #include <unistd.h>
  11. #include <fcntl.h>
  12. #include <elf.h>
  13. #include <sys/stat.h>
  14. #include <sys/mman.h>

  15. #define MODULE_NAME_LEN         (64 - sizeof(unsigned long))

  16. struct modversion_info
  17. {
  18.         unsigned long crc;
  19.         char name[MODULE_NAME_LEN];
  20. };

  21. Elf32_Ehdr *ehdr = NULL;
  22. Elf32_Phdr *phdr = NULL;
  23. Elf32_Shdr *shdr = NULL;
  24. Elf32_Shdr *shstrtab = NULL;
  25. Elf32_Sym *dynsym_ptr = NULL;
  26. Elf32_Sym *symtab_ptr = NULL;
  27. Elf32_Sym *dynstr_ptr = NULL;

  28. char *Real_strtab = NULL;
  29. char *dynstr = NULL;
  30. char *strtab_ptr = NULL;
  31. char dynstr_buffer[2048];   
  32. char strtab_buffer[4096];
  33. char *real_strtab = NULL;

  34. unsigned int shstrtab_off, shstrtab_len, shstrtab_num;
  35. unsigned int strtab_off, strtab_size;

  36. int elf_fd;
  37. struct stat f_stat;
  38.    
  39. void usage(char *pro)
  40. {
  41.         fprintf(stderr, "usage: %s <options> <module>\n\n", pro);
  42.         fprintf(stderr, "-w -v\tCheck vermgaic in module.\n");
  43.         fprintf(stderr, "-w -c\tCheck crc value in module.\n");
  44.         fprintf(stderr, "-s -v <new_vermagic>\tSet vermagic in module.\n");
  45.         fprintf(stderr, "-s -c\tSet crc value in module.\n");

  46.         exit(0);
  47. }

  48. int init_load_elf(char *elf_file)
  49. {
  50.         char buff[1024];

  51.         elf_fd = open(elf_file, O_RDWR);
  52.         if (elf_fd == -1) {
  53.                 perror("open");
  54.                 return 0;
  55.         }
  56.         fprintf(stderr, "[+] Open %s ok.\n", elf_file);

  57.         if (fstat(elf_fd, &f_stat) == -1) {
  58.                 perror("fstat");
  59.                 return 0;
  60.         }

  61.         ehdr = (Elf32_Ehdr *)mmap(NULL, f_stat.st_size, PROT_WRITE|PROT_READ, MAP_SHARED, elf_fd, 0);
  62.         if(ehdr == MAP_FAILED) {
  63.                 perror("mmap");
  64.                 return 0;
  65.         }

  66.         phdr = (Elf32_Phdr *)((unsigned long)ehdr + ehdr->e_phoff);
  67.         shdr = (Elf32_Shdr *)((unsigned long)ehdr + ehdr->e_shoff);

  68.         shstrtab = &shdr[ehdr->e_shstrndx];
  69.         shstrtab_off = (unsigned int)shstrtab->sh_offset;
  70.         shstrtab_len = shstrtab->sh_size;

  71.         real_strtab = (char *)( (unsigned long)ehdr + shstrtab_off );

  72.         printf("[+] .Shstrtab Size :0x%x,%d\n", shstrtab->sh_size, shstrtab->sh_name);
  73.         printf("[+] .Shstrtab Off: 0x%x\n", shstrtab_off);

  74.         return 1;
  75. }

  76. int display_module_crc_info(void)
  77. {
  78.         struct modversion_info *versions;
  79.         char *buff = NULL;
  80.         unsigned int version_off, version_size, num_versions;
  81.         int i, j;

  82.         buff = (char *)malloc(shstrtab_len + 2);
  83.         if (!buff) {
  84.                 fprintf(stderr, "[-] Malloc failed.\n");
  85.                 return 0;
  86.         }

  87.         memcpy(buff, real_strtab, shstrtab_len + 1);
  88.         for (i = 0 ; i < (int)ehdr->e_shnum ; i++){
  89.                 if (!strcmp(buff + shdr[i].sh_name,"__versions")){
  90.                         printf("[+] found section %s.\n", buff + shdr[i].sh_name);
  91.                         version_off = (unsigned int)shdr[i].sh_offset;
  92.                         version_size = (unsigned int)shdr[i].sh_size;
  93.                         printf("[+] version off: 0x%x\n", version_off);
  94.                         printf("[+] version size: 0x%x\n", version_size);
  95.                         break;
  96.                 }
  97.         }

  98.         printf("[+] %x,%x\n", (unsigned long)ehdr + version_off, shdr[i].sh_addr);
  99.         versions = (void *)((unsigned long)ehdr + version_off);
  100.         num_versions = version_size / sizeof(struct modversion_info);
  101.         printf("[+] num_versions: %d\n", num_versions);

  102.         for (j = 0; j < num_versions; j++) {
  103.                 printf("[+] %s:0x%08x.\n", versions[j].name, versions[j].crc);
  104.         }

  105.         free(buff);
  106.         return 1;
  107. }

  108. int set_module_crc_info(void)
  109. {
  110.         struct modversion_info *versions;
  111.         char *buff = NULL;
  112.         unsigned int version_off, version_size, num_versions;
  113.         int i, j;

  114.         buff = (char *)malloc(shstrtab_len + 2);
  115.         if (!buff) {
  116.                 fprintf(stderr, "[-] Malloc failed.\n");
  117.                 return 0;
  118.         }

  119.         memcpy(buff, real_strtab, shstrtab_len + 1);
  120.         for (i = 0 ; i < (int)ehdr->e_shnum ; i++){
  121.                 if (!strcmp(buff + shdr[i].sh_name,"__versions")){
  122.                         printf("[+] found section %s.\n", buff + shdr[i].sh_name);
  123.                         version_off = (unsigned int)shdr[i].sh_offset;
  124.                         version_size = (unsigned int)shdr[i].sh_size;
  125.                         printf("[+] version off: 0x%x\n", version_off);
  126.                         printf("[+] version size: 0x%x\n", version_size);
  127.                         break;
  128.                 }
  129.         }

  130.         printf("[+] %x,%x\n", (unsigned long)ehdr + version_off, shdr[i].sh_addr);
  131.         versions = (void *)((unsigned long)ehdr + version_off);
  132.         num_versions = version_size / sizeof(struct modversion_info);
  133.         printf("[+] num_versions: %d\n", num_versions);

  134.         for (j = 0; j < num_versions; j++) {
  135.                 printf("[+] %s:0x%08x.\n", versions[j].name, versions[j].crc);
  136.                 if (!strcmp(versions[j].name, "struct_module")) {
  137.                         fprintf(stderr, "[+] Found symbol struct_module.\n");
  138.                         versions[j].name[0] = 'T';
  139.                         break;
  140.                 }
  141.         }

  142.         for (j = 0; j < num_versions; j++) {
  143.                 printf("[+] %s:0x%08x.\n", versions[j].name, versions[j].crc);
  144.         }

  145.         free(buff);
  146.         return 1;
  147. }

  148. static char *next_string(char *string, unsigned long *secsize)
  149. {
  150.         /* Skip non-zero chars */
  151.         while (string[0]) {
  152.                 string++;
  153.                 if ((*secsize)-- <= 1)
  154.                         return NULL;
  155.         }

  156.         /* Skip any zero padding. */
  157.         while (!string[0]) {
  158.                 string++;
  159.                 if ((*secsize)-- <= 1)
  160.                         return NULL;
  161.         }
  162.         return string;
  163. }

  164. static char *get_modinfo(Elf32_Shdr *sechdrs, unsigned int info, const char *tag)
  165. {
  166.         char *p;
  167.         unsigned int taglen = strlen(tag);
  168.         unsigned long size = sechdrs[info].sh_size;

  169.         for (p = (char *)(ehdr +sechdrs[info].sh_offset); p; p = next_string(p, &size)) {
  170.                 if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
  171.                         return p + taglen + 1;
  172.         }
  173.         return NULL;
  174. }

  175. int display_module_vermagic_info(void)
  176. {
  177.         char *buff, *p;
  178.         char *ver = "vermagic";
  179.         unsigned int taglen = strlen(ver);
  180.         int size, i;

  181.         buff = (char *)malloc(shstrtab_len + 2);
  182.         if (!buff) {
  183.                 fprintf(stderr, "[-] Malloc failed.\n");
  184.                 return 0;
  185.         }

  186.         memcpy(buff, real_strtab, shstrtab_len + 1);
  187.         for (i = 0 ; i < (int)ehdr->e_shnum ; i++){
  188.                 if (!strcmp(buff + shdr[i].sh_name,".modinfo")){
  189.                         printf("[+] found section %s.\n", buff + shdr[i].sh_name);
  190.                         break;
  191.                 }
  192.         }

  193.         size = shdr[i].sh_size;
  194.         printf("[+] size: 0x%x.\n", size);

  195.         p = (char *)((unsigned long)ehdr + shdr[i].sh_offset);
  196.         printf("[+] 0x%08x\n", p);

  197.         for (; p; p = next_string(p, &size)) {
  198.                 printf("[+] %s\n", p);
  199.                 if (strncmp(p, "vermagic", taglen) == 0 && p[taglen] == '=') {
  200.                         printf("[+] %s\n", p + taglen + 1);
  201.                         //memset(p + taglen + 1, 'A', 30);
  202.                 }
  203.         }

  204.         return 1;
  205. }

  206. int set_module_vermagic_info(char *new_vermagic)
  207. {
  208.         char *buff, *p;
  209.         char *ver = "vermagic";
  210.         unsigned int taglen = strlen(ver);
  211.         int size, i;

  212.         buff = (char *)malloc(shstrtab_len + 2);
  213.         if (!buff) {
  214.                 fprintf(stderr, "[-] Malloc failed.\n");
  215.                 return 0;
  216.         }

  217.         memcpy(buff, real_strtab, shstrtab_len + 1);
  218.         for (i = 0 ; i < (int)ehdr->e_shnum ; i++){
  219.                 if (!strcmp(buff + shdr[i].sh_name,".modinfo")){
  220.                         printf("[+] found section %s.\n", buff + shdr[i].sh_name);
  221.                         break;
  222.                 }
  223.         }

  224.         size = shdr[i].sh_size;
  225.         printf("[+] size: 0x%x.\n", size);

  226.         p = (char *)((unsigned long)ehdr + shdr[i].sh_offset);
  227.         printf("[+] 0x%08x\n", p);

  228.         for (; p; p = next_string(p, &size)) {
  229.                 printf("[+] %s\n", p);
  230.                 if (strncmp(p, "vermagic", taglen) == 0 && p[taglen] == '=') {
  231.                         printf("[+] %s\n", p + taglen + 1);
  232.                         if (strlen(p + taglen + 1) < strlen(new_vermagic)) {
  233.                                 printf("[-] New vermagic len must < current magic len.\n");
  234.                                 return 0;
  235.                         }
  236.                         memset(p + taglen + 1, '\0', strlen(new_vermagic));
  237.                         memcpy(p + taglen + 1, new_vermagic, strlen(new_vermagic));
  238.                 }
  239.         }

  240.         return 1;
  241. }

  242. int exit_elf_load(void)
  243. {
  244.         close(elf_fd);
  245.         if (munmap(ehdr, f_stat.st_size) == -1) {
  246.                 return 0;
  247.         }

  248.         return 1;
  249. }

  250. int main(int argc, char **argv)
  251. {
  252.         if (argc == 1) {
  253.                 usage(argv[0]);
  254.         }

  255.         if (!strcmp(argv[1], "-w") && !strcmp(argv[2], "-c")) {
  256.                 fprintf(stderr, "[+] Display %s module crc value.\n", argv[3]);
  257.                 if (!init_load_elf(argv[3])) {
  258.                         fprintf(stderr, "[-] Init elf load failed.\n");
  259.                         return 0;
  260.                 }
  261.                 display_module_crc_info();
  262.                 exit_elf_load();
  263.         }
  264.         else if (!strcmp(argv[1], "-s") && !strcmp(argv[2], "-c")) {
  265.                 fprintf(stderr, "[+] Set %s module crc value.\n", argv[3]);
  266.                 if (!init_load_elf(argv[3])) {
  267.                         fprintf(stderr, "[-] Init elf load failed.\n");
  268.                         return 0;
  269.                 }
  270.                 set_module_crc_info();
  271.                 exit_elf_load();
  272.         }
  273.         if (!strcmp(argv[1], "-w") && !strcmp(argv[2], "-v")) {
  274.                 fprintf(stderr, "[+] Display %s module crc value.\n", argv[3]);
  275.                 if (!init_load_elf(argv[3])) {
  276.                         fprintf(stderr, "[-] Init elf load failed.\n");
  277.                         return 0;
  278.                 }
  279.                 display_module_vermagic_info();
  280.                 exit_elf_load();
  281.         }
  282.         if (!strcmp(argv[1], "-s") && !strcmp(argv[2], "-v")) {
  283.                 fprintf(stderr, "[+] Display %s module crc value.\n", argv[4]);
  284.                 if (!init_load_elf(argv[4])) {
  285.                         fprintf(stderr, "[-] Init elf load failed.\n");
  286.                         return 0;
  287.                 }
  288.                 set_module_vermagic_info(argv[3]);
  289.                 exit_elf_load();
  290.         }
  291.         else {
  292.                 return 0;
  293.         }

  294. }
復(fù)制代碼

作者: ubuntuer    時(shí)間: 2009-12-25 11:19
不錯(cuò)
作者: Godbach    時(shí)間: 2009-12-25 12:19
多謝LZ的好文。
作者: platinum    時(shí)間: 2009-12-25 15:34
不同內(nèi)核版本的公用結(jié)構(gòu)卻不能加載的確很煩
但是這樣突破的話,一點(diǎn)基本防護(hù)都沒有了,很容易 oops
個(gè)人建議,如果確實(shí)有必要的話可以 modprobe -f 加載
作者: Godbach    時(shí)間: 2009-12-25 15:59
個(gè)人建議,如果確實(shí)有必要的話可以 modprobe -f 加載

白金兄的意思是強(qiáng)制加載嗎
作者: emmoblin    時(shí)間: 2009-12-25 16:41
終于知道m(xù)odpost是干嘛用的了
作者: platinum    時(shí)間: 2009-12-25 17:17
原帖由 Godbach 于 2009-12-25 15:59 發(fā)表

白金兄的意思是強(qiáng)制加載嗎

對(duì)呀,既然可以突破沖突檢測(cè)而讓系統(tǒng)很自然的加載而未告知用戶可能有隱患,不如用戶直接強(qiáng)制加載
作者: W.Z.T    時(shí)間: 2009-12-25 17:52
原帖由 platinum 于 2009-12-25 15:34 發(fā)表
不同內(nèi)核版本的公用結(jié)構(gòu)卻不能加載的確很煩
但是這樣突破的話,一點(diǎn)基本防護(hù)都沒有了,很容易 oops
個(gè)人建議,如果確實(shí)有必要的話可以 modprobe -f 加載


如果modprobe -f能這么容易的加載的話,  我不就用費(fèi)這么大勁來做內(nèi)核校驗(yàn)技術(shù)的研究了~ 不知道兄弟試過沒, 呵呵。
作者: W.Z.T    時(shí)間: 2009-12-25 17:59
原帖由 platinum 于 2009-12-25 15:34 發(fā)表
不同內(nèi)核版本的公用結(jié)構(gòu)卻不能加載的確很煩
但是這樣突破的話,一點(diǎn)基本防護(hù)都沒有了,很容易 oops
個(gè)人建議,如果確實(shí)有必要的話可以 modprobe -f 加載


很容易o(hù)ops?   呵呵, 不見得, 文章已經(jīng)說的很清楚了, 大內(nèi)核版本, 函數(shù)接口都不會(huì)變很多,尤其向AS5-92, AS5-128之類的版本。
作者: platinum    時(shí)間: 2009-12-25 19:41
原帖由 W.Z.T 于 2009-12-25 17:59 發(fā)表


很容易o(hù)ops?   呵呵, 不見得, 文章已經(jīng)說的很清楚了, 大內(nèi)核版本, 函數(shù)接口都不會(huì)變很多,尤其向AS5-92, AS5-128之類的版本。

我說很容易 oops,是說在接口不同的情況下會(huì)報(bào)錯(cuò),不會(huì)在你自己不知情的情況下被強(qiáng)行加載
當(dāng)然,如果你一定要 modprobe -f xxxx.ko 的話當(dāng)然也很容易 oops
但對(duì)于沒有任何提示的內(nèi)核來說,沒有提示自動(dòng)加載比有提示卻強(qiáng)行加載的情況下更容易 oops

另外恕我無知,我還真沒見過不能 modprobe -f 而用兄弟的方法卻可以加載的模塊,兄弟能否提供一個(gè)讓我測(cè)試一下?
作者: W.Z.T    時(shí)間: 2009-12-25 21:15

  1. #include <linux/kernel.h>
  2. #include <linux/module.h>
  3. #include <linux/init.h>
  4. #include <linux/version.h>
  5. #include <linux/string.h>
  6. #include <linux/list.h>

  7. MODULE_LICENSE("GPL");
  8. MODULE_AUTHOR("wzt");

  9. struct module *m = &__this_module;

  10. int print_module_test(void)
  11. {
  12.         struct module *mod;

  13.         list_for_each_entry(mod, &m->list, list) {
  14.                 printk("%s\n", mod->name);
  15.         }
  16.         return NULL;
  17. }

  18. static int list_print_init(void)
  19. {
  20.         printk("load list_print module.\n");

  21.         print_module_test();

  22.         return 0;
  23. }

  24. static void list_print_exit(void)
  25. {
  26.         printk("unload list_print module.\n");
  27. }

  28. module_init(list_print_init);
  29. module_exit(list_print_exit);
復(fù)制代碼


你可以在as5.2下編譯, 然后到as5.4或到as4.7上看看能直接安裝不? 前提是要開啟CONFIG_MODVERSIONS選項(xiàng)。
作者: platinum    時(shí)間: 2009-12-25 22:23
是編譯的環(huán)境需要開啟 CONFIG_MODVERSIONS,還是加載模塊的內(nèi)核需要開啟 CONFIG_MODVERSIONS?
作者: W.Z.T    時(shí)間: 2009-12-26 07:40
原帖由 platinum 于 2009-12-25 22:23 發(fā)表
是編譯的環(huán)境需要開啟 CONFIG_MODVERSIONS,還是加載模塊的內(nèi)核需要開啟 CONFIG_MODVERSIONS?


加載模塊的內(nèi)核需要開啟 CONFIG_MODVERSIONS。 默認(rèn)的AS系列內(nèi)核都已經(jīng)打開這個(gè)選項(xiàng)了。
作者: platinum    時(shí)間: 2009-12-27 08:34
又仔細(xì)看了一次文章,真不好意思是我之前沒有完全理解你的意圖
這個(gè)方法可是夠危險(xiǎn)的啊,不知道 2.6.31 以后的內(nèi)核會(huì)不會(huì)再次有針對(duì)性的修正……
作者: smalloc    時(shí)間: 2009-12-29 18:35
這個(gè)高版本ko到低版本好使嗎?2.6.26到2.6.25 PCI的網(wǎng)卡驅(qū)動(dòng),PC上做試驗(yàn)麻煩死了.
作者: li32768    時(shí)間: 2009-12-30 11:04
這個(gè)很好很強(qiáng)大,應(yīng)該多看看理解一下,但是我怎么收藏呢
作者: playmud    時(shí)間: 2010-01-06 15:12
樓主最好可以再開篇醒目的位置描述一下這種繞過機(jī)制的場(chǎng)景,免得誤導(dǎo)讀者。
linux內(nèi)核模塊的這種驗(yàn)證機(jī)制本意是好的,保證其健壯性,但其實(shí)現(xiàn)機(jī)制是比較差的,
作者: W.Z.T    時(shí)間: 2010-01-06 15:21
I AM BLACKHAT.
作者: swanrobin    時(shí)間: 2010-01-11 00:33
好東西,收藏一下!
作者: accessory    時(shí)間: 2010-01-16 14:29
從頭到尾看完了。支持下。
作者: mzj1984cs    時(shí)間: 2010-01-25 16:51
很好很強(qiáng)大
作者: zonian    時(shí)間: 2010-02-03 12:27
回復(fù) 1# W.Z.T

雖然不會(huì)這樣去用,但學(xué)習(xí)了,多謝樓主
作者: jjinl    時(shí)間: 2010-03-16 10:45
強(qiáng)悍!學(xué)習(xí)!
作者: mxzwish    時(shí)間: 2011-11-12 14:11
本帖最后由 mxzwish 于 2011-11-12 14:13 編輯

linux這樣設(shè)計(jì)還有一個(gè)目的就是強(qiáng)制所有內(nèi)核模塊開發(fā)者開源

否則根本沒有通用性!這就是赤裸裸的強(qiáng)制開源精神

我目前在研究vmx,在物理機(jī)上不能調(diào)試只能靠猜,在bochs上可以調(diào)試vmx

想用bochs調(diào)試卻發(fā)現(xiàn)所有發(fā)行版都沒辦法在bochs上安裝或使用(有些能安裝上的卻用不了!bochs太慢了。

想用ttylinux之類小型linux卻沒有kernel頭文件沒辦法編譯內(nèi)核模塊!

樓主這篇文章好!我可以編譯在ttylinux上運(yùn)行的內(nèi)核模塊了
作者: jhl19880722    時(shí)間: 2012-10-02 11:18
我想問一下,你這個(gè)方法一個(gè)核心的解決方法是不是分析文件格式,修改要加載的ko文件里面要檢查的參數(shù),我以前也試過直接修改編譯的內(nèi)核參數(shù),讓模塊加載。
作者: mousexqshe    時(shí)間: 2014-08-28 15:10
最近正好遇到這個(gè)問題,先學(xué)習(xí)一下,不懂在問。
作者: Jacob_linux    時(shí)間: 2015-10-20 19:56
樓主 能發(fā)下Makefile嗎, 我想實(shí)現(xiàn)這個(gè)跨版本加載的功能,怎么生成module.mod.c之后sleep30秒呢, 求具體操作方法。
作者: mordorwww    時(shí)間: 2016-02-19 14:47
留 爪, 收藏
作者: custjcy    時(shí)間: 2019-12-20 16:05
本帖最后由 custjcy 于 2019-12-21 13:56 編輯

樓主后面發(fā)的工具代碼,只是把struct_module改名的。如果需要修改某個(gè)symbol的crc值,可以參考下面的代碼(把樓主的工具修改了一下)。直接存成文件比如module_fucker.c,然后gcc -o module_fucker.bin module_fucker.c 生成可執(zhí)行文件,然后執(zhí)行命令修改,例如: ./module_fucker.bin -s -c sample.ko struct_module 0x76656456

如果要修改的地方比較多,可以參考 https://blog.csdn.net/mr_pang_1991/article/details/50014211 帖子生成Module.symvers文件后編譯驅(qū)動(dòng)

  1. /*
  2. * Linux kernel module fucker
  3. *
  4. * by wzt       <[email]wzt.wzt@gmail.com[/email]>
  5. *
  6. */

  7. #include <stdio.h>
  8. #include <string.h>
  9. #include <stdlib.h>
  10. #include <unistd.h>
  11. #include <fcntl.h>
  12. #include <elf.h>
  13. #include <sys/stat.h>
  14. #include <sys/mman.h>

  15. #define MODULE_NAME_LEN         (64 - sizeof(unsigned long))

  16. struct modversion_info
  17. {
  18.         unsigned long crc;
  19.         char name[MODULE_NAME_LEN];
  20. };

  21. Elf32_Ehdr *ehdr = NULL;
  22. Elf32_Phdr *phdr = NULL;
  23. Elf32_Shdr *shdr = NULL;
  24. Elf32_Shdr *shstrtab = NULL;
  25. Elf32_Sym *dynsym_ptr = NULL;
  26. Elf32_Sym *symtab_ptr = NULL;
  27. Elf32_Sym *dynstr_ptr = NULL;

  28. char *Real_strtab = NULL;
  29. char *dynstr = NULL;
  30. char *strtab_ptr = NULL;
  31. char dynstr_buffer[2048];   
  32. char strtab_buffer[4096];
  33. char *real_strtab = NULL;

  34. unsigned int shstrtab_off, shstrtab_len, shstrtab_num;
  35. unsigned int strtab_off, strtab_size;

  36. int elf_fd;
  37. struct stat f_stat;
  38.    
  39. void usage(char *pro)
  40. {
  41.         fprintf(stderr, "usage: %s <options> <module>\n\n", pro);
  42.         fprintf(stderr, "-w -v\tCheck vermgaic in module.\n");
  43.         fprintf(stderr, "-w -c\tCheck crc value in module.\n");
  44.         fprintf(stderr, "-s -v <new_vermagic>\tSet vermagic in module.\n");
  45.         fprintf(stderr, "-s -c\tSet crc value in module. please append two more arguments after <module>: <symbol> <crc>. i.e. %s -s -c sample.ko module_layout 0xa925871a\n", pro);

  46.         exit(0);
  47. }

  48. int init_load_elf(char *elf_file)
  49. {
  50.         char buff[1024];

  51.         elf_fd = open(elf_file, O_RDWR);
  52.         if (elf_fd == -1) {
  53.                 perror("open");
  54.                 return 0;
  55.         }
  56.         fprintf(stderr, "[+] Open %s ok.\n", elf_file);

  57.         if (fstat(elf_fd, &f_stat) == -1) {
  58.                 perror("fstat");
  59.                 return 0;
  60.         }

  61.         ehdr = (Elf32_Ehdr *)mmap(NULL, f_stat.st_size, PROT_WRITE|PROT_READ, MAP_SHARED, elf_fd, 0);
  62.         if(ehdr == MAP_FAILED) {
  63.                 perror("mmap");
  64.                 return 0;
  65.         }

  66.         phdr = (Elf32_Phdr *)((unsigned long)ehdr + ehdr->e_phoff);
  67.         shdr = (Elf32_Shdr *)((unsigned long)ehdr + ehdr->e_shoff);

  68.         shstrtab = &shdr[ehdr->e_shstrndx];
  69.         shstrtab_off = (unsigned int)shstrtab->sh_offset;
  70.         shstrtab_len = shstrtab->sh_size;

  71.         real_strtab = (char *)( (unsigned long)ehdr + shstrtab_off );

  72.         printf("[+] .Shstrtab Size :0x%x,%d\n", shstrtab->sh_size, shstrtab->sh_name);
  73.         printf("[+] .Shstrtab Off: 0x%x\n", shstrtab_off);

  74.         return 1;
  75. }

  76. int display_module_crc_info(void)
  77. {
  78.         struct modversion_info *versions;
  79.         char *buff = NULL;
  80.         unsigned int version_off, version_size, num_versions;
  81.         int i, j;

  82.         buff = (char *)malloc(shstrtab_len + 2);
  83.         if (!buff) {
  84.                 fprintf(stderr, "[-] Malloc failed.\n");
  85.                 return 0;
  86.         }

  87.         memcpy(buff, real_strtab, shstrtab_len + 1);
  88.         for (i = 0 ; i < (int)ehdr->e_shnum ; i++){
  89.                 if (!strcmp(buff + shdr[i].sh_name,"__versions")){
  90.                         printf("[+] found section %s.\n", buff + shdr[i].sh_name);
  91.                         version_off = (unsigned int)shdr[i].sh_offset;
  92.                         version_size = (unsigned int)shdr[i].sh_size;
  93.                         printf("[+] version off: 0x%x\n", version_off);
  94.                         printf("[+] version size: 0x%x\n", version_size);
  95.                         break;
  96.                 }
  97.         }

  98.         printf("[+] %x,%x\n", (unsigned long)ehdr + version_off, shdr[i].sh_addr);
  99.         versions = (void *)((unsigned long)ehdr + version_off);
  100.         num_versions = version_size / sizeof(struct modversion_info);
  101.         printf("[+] num_versions: %d\n", num_versions);

  102.         for (j = 0; j < num_versions; j++) {
  103.                 printf("[+] %s:0x%08x.\n", versions[j].name, versions[j].crc);
  104.         }

  105.         free(buff);
  106.         return 1;
  107. }

  108. int set_module_crc_info(char* moduleName, char* moduleCrc)
  109. {
  110.         struct modversion_info *versions;
  111.         char *buff = NULL;
  112.         unsigned int version_off, version_size, num_versions;
  113.         int i, j;

  114.         buff = (char *)malloc(shstrtab_len + 2);
  115.         if (!buff) {
  116.                 fprintf(stderr, "[-] Malloc failed.\n");
  117.                 return 0;
  118.         }

  119.         memcpy(buff, real_strtab, shstrtab_len + 1);
  120.         for (i = 0 ; i < (int)ehdr->e_shnum ; i++){
  121.                 if (!strcmp(buff + shdr[i].sh_name,"__versions")){
  122.                         printf("[+] found section %s.\n", buff + shdr[i].sh_name);
  123.                         version_off = (unsigned int)shdr[i].sh_offset;
  124.                         version_size = (unsigned int)shdr[i].sh_size;
  125.                         printf("[+] version off: 0x%x\n", version_off);
  126.                         printf("[+] version size: 0x%x\n", version_size);
  127.                         break;
  128.                 }
  129.         }

  130.         printf("[+] %x,%x\n", (unsigned long)ehdr + version_off, shdr[i].sh_addr);
  131.         versions = (void *)((unsigned long)ehdr + version_off);
  132.         num_versions = version_size / sizeof(struct modversion_info);
  133.         printf("[+] num_versions: %d\n", num_versions);

  134.         for (j = 0; j < num_versions; j++) {
  135.                 printf("[+] %s:0x%08x.\n", versions[j].name, versions[j].crc);
  136.                 if (moduleName != NULL && !strcmp(versions[j].name, moduleName)) {
  137.                         if (moduleCrc != NULL) {
  138.                                 fprintf(stderr, "[+] Found symbol %s, and will set crc code to %s\n", moduleName, moduleCrc);
  139.                                 sscanf(moduleCrc, "0x%08x", &versions[j].crc);
  140.                                 
  141.                         } else {
  142.                                 fprintf(stderr, "[+] Found symbol %s, please input the crc code (like format: 0xa925871a):\n", moduleName);
  143.                                 scanf("0x%08x", &versions[j].crc);
  144.                         }
  145.                         break;
  146.                 }
  147.         }

  148.         printf("[+] after set moduel crc:\n");
  149.         for (j = 0; j < num_versions; j++) {
  150.                 printf("[+] %s:0x%08x.\n", versions[j].name, versions[j].crc);
  151.         }

  152.         free(buff);
  153.         return 1;
  154. }

  155. static char *next_string(char *string, unsigned long *secsize)
  156. {
  157.         /* Skip non-zero chars */
  158.         while (string[0]) {
  159.                 string++;
  160.                 if ((*secsize)-- <= 1)
  161.                         return NULL;
  162.         }

  163.         /* Skip any zero padding. */
  164.         while (!string[0]) {
  165.                 string++;
  166.                 if ((*secsize)-- <= 1)
  167.                         return NULL;
  168.         }
  169.         return string;
  170. }

  171. static char *get_modinfo(Elf32_Shdr *sechdrs, unsigned int info, const char *tag)
  172. {
  173.         char *p;
  174.         unsigned int taglen = strlen(tag);
  175.         unsigned long size = sechdrs[info].sh_size;

  176.         for (p = (char *)(ehdr +sechdrs[info].sh_offset); p; p = next_string(p, &size)) {
  177.                 if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
  178.                         return p + taglen + 1;
  179.         }
  180.         return NULL;
  181. }

  182. int display_module_vermagic_info(void)
  183. {
  184.         char *buff, *p;
  185.         char *ver = "vermagic";
  186.         unsigned int taglen = strlen(ver);
  187.         int size, i;

  188.         buff = (char *)malloc(shstrtab_len + 2);
  189.         if (!buff) {
  190.                 fprintf(stderr, "[-] Malloc failed.\n");
  191.                 return 0;
  192.         }

  193.         memcpy(buff, real_strtab, shstrtab_len + 1);
  194.         for (i = 0 ; i < (int)ehdr->e_shnum ; i++){
  195.                 if (!strcmp(buff + shdr[i].sh_name,".modinfo")){
  196.                         printf("[+] found section %s.\n", buff + shdr[i].sh_name);
  197.                         break;
  198.                 }
  199.         }

  200.         size = shdr[i].sh_size;
  201.         printf("[+] size: 0x%x.\n", size);

  202.         p = (char *)((unsigned long)ehdr + shdr[i].sh_offset);
  203.         printf("[+] 0x%08x\n", p);

  204.         for (; p; p = next_string(p, &size)) {
  205.                 printf("[+] %s\n", p);
  206.                 if (strncmp(p, "vermagic", taglen) == 0 && p[taglen] == '=') {
  207.                         printf("[+] %s\n", p + taglen + 1);
  208.                         //memset(p + taglen + 1, 'A', 30);
  209.                 }
  210.         }

  211.         return 1;
  212. }

  213. int set_module_vermagic_info(char *new_vermagic)
  214. {
  215.         char *buff, *p;
  216.         char *ver = "vermagic";
  217.         unsigned int taglen = strlen(ver);
  218.         int size, i;

  219.         buff = (char *)malloc(shstrtab_len + 2);
  220.         if (!buff) {
  221.                 fprintf(stderr, "[-] Malloc failed.\n");
  222.                 return 0;
  223.         }

  224.         memcpy(buff, real_strtab, shstrtab_len + 1);
  225.         for (i = 0 ; i < (int)ehdr->e_shnum ; i++){
  226.                 if (!strcmp(buff + shdr[i].sh_name,".modinfo")){
  227.                         printf("[+] found section %s.\n", buff + shdr[i].sh_name);
  228.                         break;
  229.                 }
  230.         }

  231.         size = shdr[i].sh_size;
  232.         printf("[+] size: 0x%x.\n", size);

  233.         p = (char *)((unsigned long)ehdr + shdr[i].sh_offset);
  234.         printf("[+] 0x%08x\n", p);

  235.         for (; p; p = next_string(p, &size)) {
  236.                 printf("[+] %s\n", p);
  237.                 if (strncmp(p, "vermagic", taglen) == 0 && p[taglen] == '=') {
  238.                         printf("[+] %s\n", p + taglen + 1);
  239.                         if (strlen(p + taglen + 1) < strlen(new_vermagic)) {
  240.                                 printf("[-] New vermagic len must < current magic len.\n");
  241.                                 return 0;
  242.                         }
  243.                         memset(p + taglen + 1, '\0', strlen(new_vermagic));
  244.                         memcpy(p + taglen + 1, new_vermagic, strlen(new_vermagic));
  245.                 }
  246.         }

  247.         return 1;
  248. }

  249. int exit_elf_load(void)
  250. {
  251.         close(elf_fd);
  252.         if (munmap(ehdr, f_stat.st_size) == -1) {
  253.                 return 0;
  254.         }

  255.         return 1;
  256. }

  257. int main(int argc, char **argv)
  258. {
  259.         if (argc == 1) {
  260.                 usage(argv[0]);
  261.         }

  262.         if (!strcmp(argv[1], "-w") && !strcmp(argv[2], "-c")) {
  263.                 fprintf(stderr, "[+] Display %s module crc value.\n", argv[3]);
  264.                 if (!init_load_elf(argv[3])) {
  265.                         fprintf(stderr, "[-] Init elf load failed.\n");
  266.                         return 0;
  267.                 }
  268.                 display_module_crc_info();
  269.                 exit_elf_load();
  270.         }
  271.         else if (!strcmp(argv[1], "-s") && !strcmp(argv[2], "-c")) {
  272.                 fprintf(stderr, "[+] Set %s module crc value.\n", argv[3]);
  273.                 if (!init_load_elf(argv[3])) {
  274.                         fprintf(stderr, "[-] Init elf load failed.\n");
  275.                         return 0;
  276.                 }
  277.                 set_module_crc_info( argc >= 4 ? argv[4] : NULL, argc >= 5 ? argv[5] : NULL);
  278.                 exit_elf_load();
  279.         }
  280.         if (!strcmp(argv[1], "-w") && !strcmp(argv[2], "-v")) {
  281.                 fprintf(stderr, "[+] Display %s module crc value.\n", argv[3]);
  282.                 if (!init_load_elf(argv[3])) {
  283.                         fprintf(stderr, "[-] Init elf load failed.\n");
  284.                         return 0;
  285.                 }
  286.                 display_module_vermagic_info();
  287.                 exit_elf_load();
  288.         }
  289.         if (!strcmp(argv[1], "-s") && !strcmp(argv[2], "-v")) {
  290.                 fprintf(stderr, "[+] Display %s module crc value.\n", argv[4]);
  291.                 if (!init_load_elf(argv[4])) {
  292.                         fprintf(stderr, "[-] Init elf load failed.\n");
  293.                         return 0;
  294.                 }
  295.                 set_module_vermagic_info(argv[3]);
  296.                 exit_elf_load();
  297.         }
  298.         else {
  299.                 return 0;
  300.         }

  301. }
復(fù)制代碼

作者: custjcy    時(shí)間: 2019-12-20 16:08
其它參考帖子:繞過CONFIG_MODVERSIONS
https://blog.csdn.net/mr_pang_1991/article/details/50014211
作者: custjcy    時(shí)間: 2019-12-20 16:19
如果crc 不一致多的話,可以參考這個(gè)帖子 https://blog.csdn.net/mr_pang_1991/article/details/50014211
作者: custjcy    時(shí)間: 2019-12-20 16:21
如果要修改的地方比較多,可以參考這個(gè)帖子:
繞過CONFIG_MODVERSIONS




歡迎光臨 Chinaunix (http://72891.cn/) Powered by Discuz! X3.2