제임스딘딘의
Tech & Life

개발자의 기록 노트/Linux

Kprobes 사용하기 [2] : 시스템콜에 probe 삽입하기

제임스-딘딘 2012. 9. 12. 00:37

Kprobes 사용하기 [2] : 시스템콜에 probe 삽입하기


Kprobe 를 이용하려면 모듈로 작성하여야 함.


System call 중 sys_open( ) 이 호출되는 것을 로그로 감지하는 probe를 삽입해 보겠다.


우선 커널에서 sys_open( )의 심볼 주소를 얻어야 한다.

적어도 다음과 같은 3가지 방법이 있다.


/proc/kallsyms 파일 항목을 사용한다.

사용예 : cat /proc/kallsyms | grep sys_open

nm 명령어를 커널에 적용한다.
사용예 : nm vmlinux | grep sys_open (vmlinux 의 위치에서, 아닌경우 경로 지정할 것)

커널의 System.map을 사용한다.
사용예 : grep sys_open System.map (System.map 의 위치에서, 아닌경우 경로 지정할 것)


위 명령을 사용하면 심볼 주소를 알 수 있다.

c1169ba0 T sys_open 과 같이 결과가 뱉어진다.

나는 c1169ba0  임을 알 수 있었다.


kprobe의 addr에 넣어주면 된다.


다음 소스코드를 c 파일로 작성한다.

나는 kprobe_sys_open.c 로 저장하였다.


#include <linux/module.h>

#include <linux/kprobes.h>


struct kprobe kpb;

int handler_pre_sys_open(struct kprobe* p, struct pt_regs* regs) {

printk("sys_open_pre_handler: p->addr=0x%p\n", p->addr);

return 0;

}


void handler_post_sys_open(struct kprobe* p, struct pt_regs* regs, unsigned long flags) {

printk("post_handler_sys_open: p->addr=0x%p\n", p->addr);

}


int handler_fault_sys_open(struct kprobe* p, struct pt_regs* regs, int trapnr) {

printk("handler_fault_sys_open: p->addr=0x%p\n", p->addr);

return 0;

}


int init_module(void)

{

kpb.fault_handler = handler_fault_sys_open;

kpb.pre_handler = handler_pre_sys_open;

kpb.post_handler = handler_post_sys_open;

kpb.addr = (kprobe_opcode_t *) 0xc1169ba0; // 이 부분이 심볼 주소

register_kprobe(&kpb);

printk("register kprobe \n");

return 0;

}


void cleanup_module(void)

{

unregister_kprobe(&kpb);

printk("unregister kprobe\n");


}


MODULE_LICENSE("GPL");



모듈로 만들어 주기 위한 Makefile 을 작성했다.


vi Makefile 


위 명령으로 Makefile을 만든 뒤 아래 내용을 넣어주고 저장한다.


obj-m += kprobe_sys_open.o


vi 에디터에서 빠져 나온 뒤 make 명령을 해주면, module 파일이 생성된다

다음과 같이 해준다.


make -C /usr/src/linux SUBDIRS=$PWD modules 


몇개의 생성되는 파일이 있는데, .ko 확장자를 갖는 파일이 모듈 파일이다.

모듈의 삽입과 제거는 다음과 같이 수행한다.


insmod kprobe_sys_open.ko  (모듈 삽입)


rmmod kprobe_sys_open.ko  (모듈 제거)


모듈 삽입 후 커널의 로그 메세지를 보면, kprobe의 핸들러에서 printk 를 통해 출력하는 메세지들이 기록되는 것을 볼 수 있다. 로그가 기록되는 시점은 sys_open 시스템 콜이 불려질 때마다 전 (pre), 후 (post) 핸들러가 실행되어 로그를 기록한다.

로그 확인 뒤 모듈 제거를 하도록 한다.


커널 로그의 확인은 리눅스 배포판 마다 다른 듯 하다.


Ubuntu 12.04 에서는 다음과 같이 확인한다.


cat /proc/kmsg


여러 다른 로그가 쌓이는 중, kprobe가 기록하는 메세지도 함께 쌓이는 것을 확인 가능하다.