我目前正在开发一个小型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()
获取两个参数i
和max-PAGE_SIZE
,并调用其他几个函数,这些函数搜索标识由i
和max-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_START
和VMALLOC_END
之间)吗?
我正在使用debian 7.2和内核3.10.9。
提前致谢。
答案 0 :(得分:1)
您的实施中存在一个明显的问题。即使我假设你采取了正确的行动 当您扫描vmap_area_list时,vmap_area_lock仍然存在竞争条件,至少使用vmalloc本身可能会遇到页面错误。也就是说,您可以访问已分配和插入但尚未在vmalloc中映射的虚拟机区域。在这种情况下,典型的数据中止 - 页面错误将如上所述发生。