Programming
x86 linux idt hooking
daehee87
2013. 1. 24. 21:52
리눅스에서 LKM 을 올려서 IDT 를 후킹하는 실습을 했다
먼저 SIDT 명령으로 IDTR 레지스터의 6바이트 내용을 메모리로 가져온다
하위 4바이트에 IDT 의 가상주소가 들어있다.
테스트 환경(VBox Ubuntu 2.6) 에서는 0xc0763000 이었다.
간단하게 IDT 의 첫번째 엔트리(divide by zero exception) 을 후킹해보기 위해서
IDT 엔트리의 주소를 덮어썻다.
IDT 엔트리는 8바이트로 이루어져 있는데 다음과 같은 구조다
// Took these structures from Bran's Kernel Dev Tutorial |
008 | typedef struct _idt_entry |
009 | { |
010 | USHORT base_lo; |
011 | USHORT sel; |
012 | UCHAR always0; |
013 | UCHAR flags; |
014 | USHORT base_hi; |
015 | } idt_entry, *pidt_entry; |
016 |
017 | typedef struct _idt_ptr |
018 | { |
019 | USHORT limit; |
020 | ULONG base; |
021 | } idt_ptr, *pidt_ptr; |
덤프를 떳을대 모양은 아래와 같다.
00604050 C0108E00
0060C130 C0588E00
0060C190 C0588E00
0060C2C0 C058EE00
...
첫번째 엔트리인 00604050 C0108E00 에서 base_lo 의 부분이
4050 인데, 이것이 핸들러 주소의 하위 2바이트이고
base_hi 부분이 C010 인데 이것이 핸들러 주소의 상위 2바이트이다.
이 부분들을 내가 지정한 함수의 주소로 수정하는 코드를 아래와 같이
LKM 으로 만들어서 컴파일했다.
#include "linux/init.h" #include "linux/kernel.h" #include "linux/module.h" #include "linux/proc_fs.h" #include "linux/syscalls.h" #include "linux/kallsyms.h" #include "linux/sched.h" #include "asm/uaccess.h" #include "asm/unistd.h" unsigned char* p_idt = (unsigned char*)0xc0763000; void my_idt_hook(){ printk("idt 0 hooked\n"); } int my_init(void) { // printk("module init ok\n"); // asm("sidt %0\n" : :"m"(p_idt[25])); printk("gogogo\n"); write_cr0( read_cr0( ) & ( ~0x10000 ) ); /* int i; for(i=0; i<256; i++){ printk("%08X ", p_idt[i]); } */ p_idt[0] = (unsigned int)my_idt_hook & 0xFF; p_idt[1] = ((unsigned int)my_idt_hook & 0xFF00) >> 8; p_idt[6] = ((unsigned int)my_idt_hook & 0xFF0000) >> 16; p_idt[7] = ((unsigned int)my_idt_hook & 0xFF000000) >> 24; write_cr0( read_cr0( ) | 0x10000 ); printk("ok?\n"); /* int k=1; for(i=0; i<8*20; i++){ printk("%02X ", p_idt[i]); if(k++ % 8 == 0) printk("\n"); } */ return 0; } void my_exit(void) { printk("module unloaded\n "); } module_init(my_init); module_exit(my_exit);
그리고 divide by zero exception 을 일으키는 프로그램을 만들어서 실행시키고
dmesg 를 해보니 아래와같이 내가 정의한 my_idt_hook 함수가 호출된 것을 확인 할 수 있었다.
후킹한 ISR 함수를 제대로 안만들어서 kernel panic 이 되었지만 요점은 후킹이 성공했다는 점이다.