В настоящее время я работаю над небольшим LKM, который ищет модули, которые прячутся внутри пространства ядра, как это делали некоторые руткиты на уровне ядра. Поскольку пространство ядра для модуля выделяется с помощью 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
:
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()
проверяет, содержит ли выделенная область памяти последовательность байтов, которая является частью пролога функции `(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.
Заранее спасибо.