搜索读取虚拟内核内存的隐藏模块?

时间:2014-01-04 23:37:35

标签: linux module linux-kernel virtual

我目前正在开发一个小型LKM,它会搜索隐藏在内核空间内的模块,就像之前的某些内核级rootkit一样。导致模块的内核空间通过vmalloc()find_module_list()分配,遍历vmap_area_list中的所有条目并调用check_module():

 void find_module_list(void) {
        count = 0;

        spin_lock(lock);
        list_for_each_entry(va,l, list) {
                if (!(va->flags & VM_VM_AREA))
                        continue;

                vm = va->vm;
                vaddr = (unsigned long) vm->addr;

                if((vaddr < VMALLOC_START) || (vaddr > VMALLOC_END))
                        break;

                size = vm->size;
                printk(KERN_INFO"ADDRESS: %lx\n",vaddr);
                printk(KERN_INFO"SIZE:  %lu\n",size);
                count++;
                printk(KERN_INFO"NUMBER: %lu\n",count);

                unsigned char *i =(unsigned char*)vm->addr;         
                unsigned char *max = (unsigned char*)(vaddr+size);      

                check_module(i,max-PAGE_SIZE);  
        }
        spin_unlock(lock);
}

int init_module(void) {
        lock = (struct spinlock*)0xc1aff8a6; // vmap_area_lock
        l = (struct list_head*)0xc18fd01c;  // vmap_area_list
        printk(KERN_INFO"VMALLOC_START: %lx\n",VMALLOC_START);
        printk(KERN_INFO"VMALLOC_END: %lx\n",VMALLOC_END);
        find_module_list();
        return 0;
}

check_module()获取两个参数imax-PAGE_SIZE,并调用其他几个函数,这些函数搜索标识由imax-PAGE_SIZE声明的内存区域内的模块的字节序列{1}}:

void check_module(unsigned char *start, unsigned char* end) {
        unsigned long  err;
        unsigned char *i = start;
        unsigned char *max = end;

        while(i < max){
                err = (unsigned long)check_text_section(i,max);
                if (err!=0) {
                        printk(KERN_INFO"FOUND FUNCTION-PROLOG AT: %lx\n",err);
                }
                i++;                    
        }
} 

check_text_section()检查分配的内存区域是否包含一个字节序列,该序列是函数prolog的一部分(push%ebp,mov%esp,%ebp):

unsigned char* check_text_section(unsigned char* startAddress, unsigned char* max) {
        unsigned char *i = startAddress;

        if ((i<max)&&((i+1)<max)&&((i+2)<max)) {
                if ((*i == 0x55)&&(*(i+1)==0x89)&&(*(i+2)==0xe5)) { 
                        return i;
                }
                else return 0;
        }
        else return 0;
}

不幸的是,我在某些虚拟地址阅读时遇到了一些问题:

[ 1853.954993] FOUND FUNCTION-PROLOG AT: f99dc300
[ 1853.954998] FOUND FUNCTION-PROLOG AT: f99dc5b0
[ 1853.954999] FOUND FUNCTION-PROLOG AT: f99dc610
[ 1853.955118] ADDRESS: ffb8e000
[ 1853.955124] SIZE:  458752
[ 1853.955129] NUMBER: 159
[ 1853.955162] BUG: unable to handle kernel paging request at ffb8f000
[ 1853.955202] IP: [<f8abb01a>] check_text_section+0x1a/0x40 [mod]
[ 1853.955233] *pdpt = 0000000001a3d001 *pde = 000000003020d067 *pte = 0000000000000000 
[ 1853.955271] Oops: 0000 [#1] SMP 
[ 1853.955291] Modules linked in: mod(OF+) pci_stub vboxpci(OF) vboxnetadp(OF) vboxnetflt(OF) vboxdrv(OF) vmnet(OF) vmw_vsock_vmci_transport vsock vmw_vmci vmmon(OF) snd_hda_codec_hdmi snd_hda_codec_idt uvcvideo intel_powerclamp videobuf2_vmalloc videobuf2_memops coretemp videobuf2_core snd_hda_intel videodev snd_hda_codec arc4 snd_hwdep kvm_intel snd_pcm kvm iwldvm mac80211 snd_page_alloc snd_seq_midi snd_seq_midi_event snd_rawmidi i915 crc32_pclmul joydev bnep aesni_intel snd_seq snd_seq_device aes_i586 snd_timer xts lrw gf128mul rfcomm drm_kms_helper ablk_helper cryptd snd drm iwlwifi psmouse hp_accel hp_wmi lis3lv02d tpm_infineon ppdev input_polldev sparse_keymap serio_raw i2c_algo_bit lpc_ich wmi soundcore bluetooth cfg80211 mei_me video mei microcode tpm_tis parport_pc mac_hid lp parport binfmt_misc hid_generic usbhid hid firewire_ohci e1000e ahci firewire_core libahci sdhci_pci ptp crc_itu_t sdhci pps_core
[ 1853.955823] CPU: 1 PID: 3813 Comm: insmod Tainted: GF          O 3.10.9-031009-generic #201308201935
[ 1853.955863] Hardware name: Hewlett-Packard HP ProBook 6460b/161D, BIOS 68SCE Ver. F.04 05/10/2011
[ 1853.955903] task: ec095a20 ti: ec386000 task.ti: ec386000
[ 1853.955928] EIP: 0060:[<f8abb01a>] EFLAGS: 00010212 CPU: 1
[ 1853.955952] EIP is at check_text_section+0x1a/0x40 [mod]
[ 1853.955975] EAX: ffb8f000 EBX: ffb8f000 ECX: ffb8f002 EDX: ffbfd000
[ 1853.956001] ESI: ffbfd000 EDI: 00000000 EBP: ec387e90 ESP: ec387e90
[ 1853.956027]  DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
[ 1853.956050] CR0: 80050033 CR2: ffb8f000 CR3: 2ad08000 CR4: 000407f0
[ 1853.956076] DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
[ 1853.956104] DR6: ffff0ff0 DR7: 00000400
[ 1853.956126] Stack:
[ 1853.956139]  ec387ea8 f8abb0e1 00000000 00000000 00000000 000004b3 ec387eb8 f8abb200
[ 1853.956187]  f8abc063 0000009f ec387ec8 f8abb316 f8abc09c ffbfe000 ec387ef8 c1002051
[ 1853.956231]  00000000 00000000 00000000 00000000 f843d000 ec387ef8 f8abb290 f8abd000
[ 1853.956274] Call Trace:
[ 1853.956290]  [<f8abb0e1>] check_module+0x21/0x50 [mod]
[ 1853.956313]  [<f8abb200>] find_module_list+0xf0/0x120 [mod]
[ 1853.956343]  [<f8abb316>] init_module+0x86/0x90 [mod]
[ 1853.956369]  [<c1002051>] do_one_initcall+0x31/0x150
[ 1853.956394]  [<f8abb290>] ? find_module_plain+0x20/0x20 [mod]
[ 1853.956422]  [<c1622aeb>] do_init_module+0x80/0x1c6
[ 1853.956445]  [<c10aca1d>] load_module+0x33d/0x4e0
[ 1853.956466]  [<c10aa990>] ? add_kallsyms+0x1e0/0x1e0
[ 1853.956490]  [<c10acc56>] SyS_init_module+0x96/0xb0
[ 1853.956516]  [<c163d80d>] sysenter_do_call+0x12/0x28
[ 1853.957898] Code: <80> 38 55 75 11 80 78 01 89 75 0b 80 78 02 e5 75 05 5d c3 8d 76 00
[ 1853.959348] EIP: [<f8abb01a>] check_text_section+0x1a/0x40 [mod] SS:ESP 0068:ec387e90
[ 1853.960810] CR2: 00000000ffb8f000
[ 1853.969435] ---[ end trace 055fd4e5ddc5998f ]---

我想如果vmap_area_list中列出了内存区域,那么其中的所有虚拟地址都应该被映射并可访问/可读。是否有可能检查是否映射了虚拟地址?或者我得到了完全错误的东西?还有其他可能性来阅读内核记忆(在VMALLOC_STARTVMALLOC_END之间)吗? 我正在使用debian 7.2和内核3.10.9。

提前致谢。

1 个答案:

答案 0 :(得分:1)

您的实施中存在一个明显的问题。即使我假设你采取了正确的行动 当您扫描vmap_area_list时,vmap_area_lock仍然存在竞争条件,至少使用vmalloc本身可能会遇到页面错误。也就是说,您可以访问已分配和插入但尚未在vmalloc中映射的虚拟机区域。在这种情况下,典型的数据中止 - 页面错误将如上所述发生。