티스토리 뷰
다이나믹 링커 를 이용한 후킹 / hooking with dynamic linker /
출처 : http://i5on9i.blogspot.kr/2013/05/hooking-wrapper-function.html
linux 에서 hooking 을 해보자. 여기서 하는 내용은 application 에 호출하는 libc 같은 shared library 의 함수 대신에 자신의 wrapper function 을 사용하는 방법을 설명한다. 여기서 replace 하는 function 은 application 에서 호출하는 shared library 까지 이다. shared library 에서 호출하는 function 을 다른 function 으로 replace 할 수 있는 방법은 아니다
Overview
개략적인 내용을 얘기하자면,
user program >> library >> system call
의 루틴으로 프로그램이 실행되는데, hooking 을 하는 것은 이 루틴을 아래처럼 바꾸는 것이다.[ref. 1, figure 2]
user program >> hook >> library >> system call
이것은 dynamic linker 가 executable(실행파일) 이 실행된 이후에 symbol 을 resolve 한다는 점을 이용하는 것이다. 그러니까, 원래 undefined symbol 을 실행파일이 가지고 있는데, 이 녀석을 resolve 하면 보통 우리가 흔히 쓰는 shared library 의 함수를 불러오게 되는데, 이 때 우리가 만든 shared library 를 먼저 검색하게 해서 우리의 함수를 호출하게 하는 것이다.
dynamic library 들을 이용하는 program을 컴파일 하면 binary 에 아래 2개의 list가 포함된다.
- 이 program 이 사용하는 library 의 list
- undefined symbols 의 list
dynamic linker 가 단순히 그 library 들을 뒤지면서 그 symbol 을 가지고 있는 첫 library 를 이용하게 된다.[ref. 6]
그렇기 때문에 우리가 만약 우리의 wrapper function들을 가지고 있는 library 를 program이 호출하게 한다면, 프로그램의 undefined symbol 들은 우리의 wrapper function 으로 해석될 것이다.
Test program
이제, 간단한 malloc 을 사용하는 program 하나를 만들어 보자.
#include <malloc.h> #include <stdlib.h> int main(void) { int *p = (int *)malloc(10); free(p); }
이 녀석의 compile 은 그냥 기존의 program 처럼 해 주면 된다.
$> gcc main.c -o app
이제 app 이 호출하는 malloc 이 우리가 만든 malloc 이 되도록 해보자.
LD_PRELOAD
프로그램이 실행되면 library 를 load 하는 것은 loader(여기서는 dynamic linker 가 될 것이다.) 가 담당하게 된다. 그러면 loader 가 어떻게 우리의 library 를 load 하게 만들 것인가? 여기에 사용되는 것이 LD_PRELOAD 라는 변수이다. LD_PRELOAD 에 정의된 값을 loader 가 가장 먼저 load 하게 되어 있다.
그런데 LD_PRELOAD 는 SUID permission bit 이 set 되어 있으면 무시된다. 왜냐하면, 이 방법으로 어떤 일을 할 지 모르기 때문에 보안상의 이유로 다른 user 나 group 이 이 방법을 사용하지 못하게 막는 것이다.
만약 app 에서 malloc() 을 호출한다고 하자. 보통 이 함수는 libc 에서 호출한다. 근데 우리가 이 malloc 에 대한 wrapper function 을 만들어서 우리의 malloc wrapper 를 기존의 malloc 대신에 호출하게 하고 싶다고 하자.
일단 우리의 malloc wrapper 를 만드는 것은 나중에 설명하고, malloc wrapper 를 가지고 있는 library 가 libmine.so 라고 하자. 이 경우에 아래처럼 실행하면 기존의 malloc 대신에 우리의 malloc wrapper 가 수행된다.
$> LD_PRELOAD=/home/libmine.so ./foo
만약 library 를 2개 이상 설정하고 싶다면, 아래처럼 실행하면 된다.
$> LD_PRELOAD=/home/libmine.so;/home/libmin2.so ./app
원래 함수 호출하는 법
wrapper function 의 original function 을 쓰려고 한다면 어떻게 해야 할까? 다시 말하면, malloc 의 wrapper 를 만들었는데, 내가 만든 wrapper 내부에서 system 의 malloc 을 호출(libc 의 malloc ) 하고 싶다면 어떻게 해야 할까?
원래 우리의 wrapper function 에서 바로 libc 의 malloc 을 부를 수는 없다. 왜냐하면 compiler 가 malloc 을 내 자신을 호출하는 줄 알기 때문이다.(재귀함수를 얘기하는 것이다.) 정확히 이야기 한다면, library 를 iterate 하면서 libmin.so 에서 malloc 을 찾아버리기 때문에, 더 이상 search 를 하지 않을 것이다.
우리는 그래서 다른 방법을 사용해야 한다. 이 방법은 처음 찾은 malloc 함수의 주소가 아니라, 2번째 찾은 malloc 함수의 주소를 가져와서 우리가 그 주소로 malloc 을 호출하는 것이다. 이 때 사용하는 것이 dlsym() 이다.
dlsym(RTLD_NEXT, "malloc");
dlsym()
- dlsym : dynamic linker symbol lookup function
- return : symbol(심볼) 의 address 를 return 해준다.
RTLD_NEXT option 에 의해, 이러면 malloc 을 제공하는 library 중에 2번째 library 를 택하게 된다.
RTLD_NEXT 는 GNU 에서 제공하는 녀석이어서
#define _GNU_SOURCE
가 필요하다.[ref. 2]
그러면 이제 wrapper 함수를 가지고 있는 libmine.so 를 만들어 보자.
libmine.so 만들기
#include <dlfcn.h> void* malloc(size_t size){ ... static void* (*my_malloc)(size_t) = NULL; ... my_malloc = dlsym(RTLD_NEXT, "malloc"); ... }
자세한 코드는 ref. 2 에 가면 볼 수 있다. 여기서는 대략적인 설명만 하도록 하자.
이 code 를 shared object 로 만들기 위해 ref.2 에서는 아래처럼 compile 을 하면 된다.
gcc -shared -fPIC -ldl libmine.c -o libmine.so
-shared -fPIC -l 옵션에 관련해서는 ref. 3 을 참고 하자.
근데 이 상황에서는
symbol lookup error : … undefined symbol: dlsym
이 발생한다.
그런데, ref. 4 에 따르면 Ubuntu 11.10 부터 ld 의 기본적인 동작이 바뀌었다고 한다. 그래서 command 를 아래와 같이 주어야 한다.
gcc -shared -Wl,--no-as-needed -ldl -fPIC libmine.c -o libmine.so
-Wl,--no-as-needed 는 linker 에 --no-as-needed 옵션을 주는 gcc 옵션이다.[ref.3]
--no-as-needed
--no-as-needed 는 --as-needed 를 원상복귀 시키는 option 인데, --as-needed 가 설정되면, ELF DT_NEEDED 의 flag 가 켜지고, DT_NEEDED section 에 정의된 shared object 를 찾게 된다.[ref. 5]
linux 에서 dynamic linking 을 지원하기 위해 ELF 에 DT_NEEDED section 을 둔다. 그래서 executable 이 실행될 때 비로서 dynamic linker 가 DT_NEEDED 에서 필요한 library 들을 보고 load 하고 이 library 를 뒤지면서, undefined symbol 을 resolve 하게 된다.[ref. 6, 7]
DT_NEEDED tag 는 DT_NEEDED 영역에 쓰여있는 entry 라고 보면 될 듯 하다. DT_NEEDED tag 에 dynamic linker 가 사용할 shared object(shared library 같은) 를 정의해 놓는다.[ref. 8]
아쉽게도, 이 방법으로는 internal library(libc 같은 library) 를 interpose 할 수 없다. 왜냐하면, internal library 의 함수는 runtime 이전에 symbol 이 resolved 되기 때문이다.[ref. 1]
구현과 관련해서는 ref. 1을 참고하는 것이 좀 더 쉬울 것이다.
References
- Tutorial: Function Interposition in Linux
- http://www.linuxforu.com/2011/08/lets-hook-a-library-function/
- http://gcc.gnu.org/onlinedocs/gcc/Link-Options.html
- gcc: symbol lookup error: ...libgendep.so: undefined symbol: dlsym
- http://www.kpitgnutools.com/manuals/ld.html
- http://en.wikipedia.org/wiki/Direct_binding
- http://docs.oracle.com/cd/E19957-01/806-0641/6j9vuqujs/index.html#chapter6-63352
- http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0458c/Beijedib.html
- Total
- Today
- Yesterday
- 미스터피자주문
- network error
- 인공안구
- 영귤차
- 그림편집
- 의학
- 샤워기전
- icon tool
- 인공눈
- 제주녹색농원
- 고강도
- 편집프로그램
- icon program
- sudachi
- 인테리어
- 칠오름농장
- 명언
- 보드고글
- 칠오름
- 무릎마사지
- 대일농장
- 녹색농원
- 상식
- 과학
- 늙기
- 스타치
- 제주영귤
- breakpoint
- 데크에 바인딩묶기
- 영귤
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |