Post

(kernel) LKM, Loadable Kernel Module / Kernel Compile

Loadable Kernel Module

https://www.kernel.org/doc/Documentation/kbuild/modules.txt

Note ) root가 아니면 insmod를 사용할 수 없기 때문에, LKM을 등록할 수 없다. LKM을 이용하면 커널을 recompile/reboot하지 않아도 커널에 기능을 추가/확장할 수 있다. 따라서 syscall을 추가하고, hooking하는 것도 가능하다. 드라이버가 대체로 LKM으로 구현되어 있다. 확장자는 \*.ko 다.

1
2
3
4
5
6
lsmod      // list
insmod     // insert
rmmod      // remove
modinfo    // info
modprobe   // insmod와 달리 의존 관계에 있는 모듈까지 insert해준다.

LKM 추가하기

1
2
apt-get install build-essential linux-headers-$(uname -r)

컴파일에 필요한 헤더 다운. /usr/src/linux-headers-$(uname -r) 경로에 다운로드 되며 나중에 Makefile에서 이 곳을 참조하도록 설정하게 된다. 안나오는 경우 apt-cache search해보면 조회는 되는데 kernel 버전이 다를 것이다. 이런 경우 다른 버전으로 make까지는 가능한데, insmod에서 잘못된 module이라고 뜨며 로드가 안된다.

1. sym_print.c 작성

LKM 내부에서도 strcmp() 등을 사용할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <linux/module.h>    // included for all kernel modules
#include <linux/kernel.h>    // included for KERN\_INFO
#include <linux/init.h>      // included for \_\_init and \_\_exit macros
MODULE\_LICENSE("GPL");
MODULE\_AUTHOR("umbum");
MODULE\_DESCRIPTION("sys\_call\_table hooking test");
static int \_\_init sym\_print\_init(void)
{
unsigned long \*k = 0xc2072f60;
unsigned long \*s = 0xc1072f60;
unsigned long \*\*sct = 0xc25d3160;
printk(KERN\_INFO "sym\_print LKM!\n");
printk("kallsyms sys\_getpid   %p : %p\n", k, \*k);
printk("System.map sys\_getpid %p : %p\n", s, \*s);
printk("sct[20(\_\_NR\_getpid)]  %p : %p : %p\n", &sct[20], sct[20], \*sct[20]);
return 0;    // Non-zero return means that the module couldn't be loaded.
}
static void \_\_exit sym\_print\_exit(void)
{
printk(KERN\_INFO "sym\_print LKM removed.\n");
}
module\_init(sym\_print\_init);
module\_exit(sym\_print\_exit);

2. Makefile 작성
  • .o라고 적혀있다고 컴파일할 필요 없음.
  • 어디서 make하든 경로는 상관 없다.
  • -C 옵션으로 적은 경로가 include path다.
  • 앞에 한 칸의 tab이 들어가야 한다.
1
2
3
4
5
6
obj-m += sym\_print.o
all:
[\t]make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
[\t]make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

3. make
1
2
3
4
5
6
7
8
9
10
11
12
13
root@kali32:~/add\_syscall# make
make -C /lib/modules/4.13.0-kali1-686-pae/build M=/root/add\_syscall modules
make[1]: Entering directory '/usr/src/linux-headers-4.13.0-kali1-686-pae'
CC [M]  /root/add\_syscall/sym\_print.o
Building modules, stage 2.
MODPOST 1 modules
CC      /root/add\_syscall/sym\_print.mod.o
LD [M]  /root/add\_syscall/sym\_print.ko
make[1]: Leaving directory '/usr/src/linux-headers-4.13.0-kali1-686-pae'
root@kali32:~/add\_syscall# ls
Makefile        sym\_print.c   sym\_print.mod.c  sym\_print.o
Module.symvers  sym\_print.ko  sym\_print.mod.o  modules.order

4.
1
2
3
4
5
6
7
8
9
10
root@kali32:~/add\_syscall# insmod sym\_print.ko
root@kali32:~/add\_syscall# dmesg | tail -4
[11061.736957] sym\_print LKM!
[11061.736962] kallsyms sys\_getpid   c2072f60 : 26748d3e
[11061.736964] System.map sys\_getpid c1072f60 : 9a67ff72
[11061.736965] sct[20(\_\_NR\_getpid)]  c25d31b0 : c2072f60 : 26748d3e

root@kali32:~/add\_syscall# dmesg | tail -1
[11076.582411] sym\_print LKM removed.

Kernel Compile

https://docs.kali.org/development/recompiling-the-kali-linux-kernel recompile이라고 나와있지만, compile도 동일한 프로세스로 진행된다. kali compile이지만 보편적인 compile process를 따른다. 참고하면 좋다. https://www.debian.org/releases/lenny/ia64/ch08s06.html.ko

This post is licensed under CC BY 4.0 by the author.