기술문서 LD_PRELOAD 와공유라이브러리를사용한 libc 함수후킹 정지훈

Similar documents
Microsoft PowerPoint - chap02-C프로그램시작하기.pptx

1장. 유닉스 시스템 프로그래밍 개요

Microsoft PowerPoint - chap01-C언어개요.pptx

슬라이드 1

PowerPoint 프레젠테이션

Microsoft PowerPoint - chap06-2pointer.ppt


<4D F736F F F696E74202D20B8AEB4AABDBA20BFC0B7F920C3B3B8AEC7CFB1E22E BC8A3C8AF20B8F0B5E55D>

[ 마이크로프로세서 1] 2 주차 3 차시. 포인터와구조체 2 주차 3 차시포인터와구조체 학습목표 1. C 언어에서가장어려운포인터와구조체를설명할수있다. 2. Call By Value 와 Call By Reference 를구분할수있다. 학습내용 1 : 함수 (Functi

본 강의에 들어가기 전

11장 포인터

금오공대 컴퓨터공학전공 강의자료

임베디드시스템설계강의자료 6 system call 2/2 (2014 년도 1 학기 ) 김영진 아주대학교전자공학과

강의10

Microsoft Word - FunctionCall

PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

10.

PowerPoint Presentation

Chapter #01 Subject

PowerPoint 프레젠테이션

Microsoft PowerPoint - chap10-함수의활용.pptx

이번장에서학습할내용 동적메모리란? malloc() 와 calloc() 연결리스트 파일을이용하면보다많은데이터를유용하고지속적으로사용및관리할수있습니다. 2

chap7.key

Microsoft PowerPoint - chap11-포인터의활용.pptx

리눅스 취약점대응방안권고 / KISA 취약점점검팀 영향받는플랫폼 OS, FAQ 추가 개요 미국보안회사 에의해 시스템의 라이브러리 의특정함수에서임의코드를실행할수있는취약점이공개 해당취약점은 CVE 지정, 도메인네임을

11장 포인터

Microsoft PowerPoint - chap06-5 [호환 모드]

Microsoft PowerPoint - chap13-입출력라이브러리.pptx

본 강의에 들어가기 전

<322EBCF8C8AF28BFACBDC0B9AEC1A6292E687770>

버퍼오버플로우-왕기초편 10. 메모리를 Hex dump 뜨기 앞서우리는버퍼오버플로우로인해리턴어드레스 (return address) 가변조될수있음을알았습니다. 이제곧리턴어드레스를원하는값으로변경하는실습을해볼것인데요, 그전에앞서, 메모리에저장된값들을살펴보는방법에대해배워보겠습

PowerPoint 프레젠테이션

/chroot/lib/ /chroot/etc/

OCW_C언어 기초

untitled

vi 사용법

PowerPoint 프레젠테이션

Microsoft PowerPoint - lab14.pptx

PowerPoint 프레젠테이션

C 언어 프로그래밊 과제 풀이

K&R2 Reference Manual 번역본

PowerPoint 프레젠테이션

제 14 장포인터활용 유준범 (JUNBEOM YOO) Ver 본강의자료는생능출판사의 PPT 강의자료 를기반으로제작되었습니다.

Microsoft PowerPoint - additional01.ppt [호환 모드]

gdb 사용법 Debugging Debug라는말은 bug를없앤다는말이다. Bug란, 컴퓨터프로그램상의논리적오류를말하며, 이것을찾아해결하는과정이바로, debugging이다. 초기컴퓨터들은실제벌레가컴퓨터에들어가서오작동을일으키는경우가있었다고하며, 여기서 debug 이라는말이

Microsoft PowerPoint - ch07 - 포인터 pm0415

Chapter 4. LISTS

Microsoft PowerPoint - ch09 - 연결형리스트, Stack, Queue와 응용 pm0100

PowerPoint 프레젠테이션

vi 사용법

Poison null byte Excuse the ads! We need some help to keep our site up. List 1 Conditions 2 Exploit plan 2.1 chunksize(p)!= prev_size (next_chunk(p) 3

hlogin2

컴파일러

歯9장.PDF

설계란 무엇인가?

< E20C6DFBFFEBEEE20C0DBBCBAC0BB20C0A7C7D12043BEF0BEEE20492E707074>

Adobe Flash 취약점 분석 (CVE )

<B1E2BCFAB9AEBCAD5FB9DABAB4B1D45F F F64746F72732E687770>

C 프로그래밊 개요

Lab 3. 실습문제 (Single linked list)_해답.hwp

Microsoft PowerPoint - chap12-고급기능.pptx

PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

A Dynamic Grid Services Deployment Mechanism for On-Demand Resource Provisioning

<443A5C4C C4B48555C B3E25C32C7D0B1E25CBCB3B0E8C7C1B7CEC1A7C6AE425CBED0C3E0C7C1B7CEB1D7B7A55C D616E2E637070>

untitled

PowerPoint 프레젠테이션

UI TASK & KEY EVENT

쉽게 풀어쓴 C 프로그래밍

KEY 디바이스 드라이버

untitled

6주차.key

PowerPoint 프레젠테이션

ABC 11장


Microsoft Word - building the win32 shellcode 01.doc

untitled

A Hierarchical Approach to Interactive Motion Editing for Human-like Figures

3. 1 포인터란 3. 2 포인터변수의선언과사용 3. 3 다차원포인터변수의선언과사용 3. 4 주소의가감산 3. 5 함수포인터

학습목차 2.1 다차원배열이란 차원배열의주소와값의참조

PowerPoint 프레젠테이션

<4D F736F F F696E74202D20C1A63137C0E520B5BFC0FBB8DEB8F0B8AEBFCD20BFACB0E1B8AEBDBAC6AE>

untitled

<4D F736F F F696E74202D20C1A632C0E520C7C1B7CEB1D7B7A5B0B3B9DFB0FAC1A4>

PA for SWE2007

좀비프로세스 2


Microsoft PowerPoint - ch10 - 이진트리, AVL 트리, 트리 응용 pm0600

임베디드시스템설계강의자료 6 system call 1/2 (2014 년도 1 학기 ) 김영진 아주대학교전자공학과

Sena Technologies, Inc. HelloDevice Super 1.1.0

PowerPoint Template

Lab 4. 실습문제 (Circular singly linked list)_해답.hwp

C 프로그래밊 개요

Microsoft PowerPoint - Chapter_09.pptx

중간고사

PowerPoint 프레젠테이션

Microsoft PowerPoint - Chapter_08.pptx

고급 프로그래밍 설계

Transcription:

기술문서 LD_PRELOAD 와공유라이브러리를사용한 libc 함수후킹 정지훈 binoopang@is119.jnu.ac.kr

Abstract libc에서제공하는 API를후킹해본다. 물론이방법을사용하면다른라이브러리에서제공하는 API들도후킹할수있다. 여기서제시하는방법은리눅스후킹에서가장기본적인방법이될것이기때문에후킹의워밍업이라고생각하고읽어보자 :D

Content 1. 목적 1 1.1. 아이디어 1 2. Hooker 제작 2 2.1. 실제 libc 함수의포인터획득 2 2.2. Hooker 공유라이브러리생성 6 3. Hooker 테스트 10 3.1. 테스트환경 10 3.2. LD_PRELOAD 를사용한 Hooker 로드 10 4. 마치며 12 참고문헌 13

1. 목적 이문서에서는공유라이브러리와 LD_PRELOAD 를사용하여 API 후킹을시도할것이다. 기본적인 아이디어와기술이간단해서쉽게사용할수있는기술일것이다. 1.1. 아이디어 리눅스에서프로세스가로드될때여러가지라이브러리들을로드한다. 그중 'libc' 는 C언어에서제공되는 API들이들어있는라이브러리이다. 여기서 LD_PRELOAD를사용해서강제로라이브러리를프로세스에먼저로드시키고만약그라이브러리안에 'libc' 에들어있는함수와동일한이름의함수가존재할경우프로세스는 'libc' 가아닌 LD_PRELOAD를통해로드된라이브러리의함수를호출하게된다. 이것은라이브러리의로드순서의문제이다. 따라서우리는 LD_PRELOAD 를사용해서 'libc' 함수와동일한형식의후킹함수를로드시켜서 그함수를먼저실행한다음원래 'libc' 의함수로흐름을넘겨줄것이다. - 1 -

2. Hooker 제작 2.1. 실제 'libc' 함수의포인터획득 후킹의기본은함수포인터이다. 먼저함수포인터를사용해서실제 'libc' 의함수주소를가지고있다가우리의함수가일을마치거나필요시에실제 'libc' 함수를호출해야한다. 그렇다면어떻게실제 'libc' 함수주소를얻어낼수있을까? gdb를사용하여 getuid 주소를찾아보자. [ 그림 1] gdb 를사용한 getuid 함수주소출력 gdb 를사용해서 'getuid' 함수의주소를출력해보았다. [ 그림 1] 에서총 3 번에걸쳐서실행 하여각각주소를출력하였지만모두결과가다른것을볼수있다. 이것은실행할때마다라 이브러리의로드되는주소가약간씩달라지기때문에함수의주소도조금씩다른것이다. 2.1.1. 메모리스캐너 그렇다면매번실행할때마다 'getuid' 함수를찾아야할것같다. 여기서는메모리를스캔하 는방법을사용해보았다. - 2 -

1 main() 2 { 3 unsigned int offset; 4 char pattern[] = "\x55\x89\xe5\xb8"; 5 for(offset = 0xb7e00000 ; offset < 0xb7efffff ; offset++) 6 { 7 if(!strncmp((char *)offset, pattern, strlen(pattern))) 8 { 9 printf("found!! 0x%x\n", offset); 10 } 11 } 12 } [ 코드 1] 메모리스캔코드 [ 그림 1] 에서 getuid 의주소가 0xb7e00000 부근에서나타나는것을착안하여그부근을검 색하는것이다. 이때 pattern 에등록되어있는 '\x55\x89\xe5\xb8' 는 gdb 를사용해 서찾은 getuid 함수의기계어이다. [ 그림 2] getuid() 주소와기계어코드 [ 그림 2] 와같은방법으로찾을수있으며기계어코드의의미는다음과같다. 0xb7f01a50 <getuid+0>: push 0xb7f01a51 <getuid+1>: mov 0xb7f01a53 <getuid+3>: mov %ebp %esp,%ebp $0xc7,%eax [ 코드 2] 기계어코드해석 [ 코드 2] 에서보여지는어셈블리코드가 [ 그림 2] 에서찾은 'getuid' 의기계어이다. 조금 더정확도를높이고싶다면긴패턴을사용하면될것이다. - 3 -

[ 그림 3] 스캐너실행 [ 그림 3] 에서처럼스캐너를실행하면총 4개의함수주소가발견된다. 4개의주소는순서대로 getuid, geteuid, getgid, getegid 이다. 모두비슷한패턴을쓰다보니한꺼번에검색된것이다. [ 그림 3] 에서한가지문제점이있는데하단분에 'Segmentation fault' 가발생하였다. 보통 'SIGSEGV' 시그널은잘못된메모리에접근하였을때발생한다. 여기서는아마도 'libc' 를벗어난다른메모리지역에들어갔을경우이렇게 'SIGSEGV' 시그널이발생하는것같다. 2.1.2. libc 가로드된주소검색 [ 그림 3] 의문제점을해결하기위해서는실제 'libc' 가로드된주소를정확히알필요가있다. 많은검색을통해서 'dl_iterate_phdr()' 를알게되었고아래와같은코드를작성할수있었다. 1 #define _GNU_SOURCE 2 #include <stdio.h> 3 #include <link.h> 4 5 static int print_callback(struct dl_phdr_info *info, 6 size_t size, 7 void *data) 8 { 9 if((strstr(info->dlpi_name, "libc"))) 10 printf("%08x %s\n", info->dlpi_addr, info->dlpi_name); 11 return 0; 12 } 13 14 int main() 15 { 16 dl_iterate_phdr(print_callback, NULL); 17 return 0; 18 } [ 코드 3] 'libc' 라이브러리시작주소검색루틴 - 4 -

[ 코드 3] 에서 'dl_iterate_phdr' 은콜백함수를사용하며콜백함수는로드되는라이브러리횟수만큼호출되어서라이브러리정보를구조체에담는다여기서우리가필요한항목은라이브러리이름과시작주소이다. [ 코드 3] 의 9번줄에서 'strstr()' 을사용하여라이브러리이름에 'libc' 가들어가있으면해당라이브러리의시작주소를가져오는형식이다. [ 그림 4] 로드된 libc 라이브러리주소획득 참고로여기서사용된함수는 'GNU 확장함수 ' 1) 이기때문에 '#define _GNU_SOURCE' 를정의해주어야한다. 여기까지해서메모리스캔하는데필요한작업이완료되었다. 실제완성된스캔코드는아래와같다. 1 void search_getuid_offset(void) 2 { 3 printf("[hooker] Searching getuid offset\n"); 4 char pattern[] = "\x55\x89\xe5\xb8"; 5 for(offset = libc_start ; offset < 0xb7ffffff ; offset++) 6 { 7 if(!strncmp((char *)offset, pattern, strlen(pattern))) 8 { 9 printf("[hooker] Found offset : 0x%x\n", offset); 10 break; 11 } 12 } 13 if(offset == (unsigned long)null) 14 { 15 printf("[hooker] Can not found offset\n"); 16 exit(0); 17 } 18} [ 코드 4] 메모리스캔코드 1) GNU 확장함수는표준함수가아니기때문에꼭 _GNU_SOURCE 를정의해주어야한다. 그렇지않으면컴파일시에에러가발생한다. - 5 -

[ 코드 4] 에서 5 번줄의 'libc_start' 변수는 'dl_inerate_phdr' 의콜백함수에의해얻어낸 'libc' 가로드된주소이다. 우리는검색되는 4 개의함수중첫번째함수만필요하므로첫번 째함수가호출되면 'break' 를사용하여 for 문을빠져나온다. 2.2. Hooker 공유라이브러리생성 스캔코드를기반으로이제공유라이브러리를생성해야한다. 여기서는 'getuid' 함수를후킹할것이기때문에공유라이브러리에서메인함수는 'getuid()' 이름으로해야한다. 그래야실제어플리케이션에서 'getuid()' 를호출하면우리의라이브러리에존재하는 'getuid()' 를호출한다. 1 // getuid 후킹함수 2 int getuid() 3 { 4 int ret; 5 if(signal(sigsegv, sig_usr) == SIG_ERR) 6 fprintf(stderr, "Can not catch signal\n"); 7 8 dl_iterate_phdr(scan_callback, NULL); 9 printf("[hooker] libc start address : 0x%x\n", libc_start); 10 search_getuid_offset(); 11 orig_getuid = offset; 12 printf("[hooker] Call Orig getuid!!\n"); 13 ret = orig_getuid(); 14 printf("[hooker] Return value of getuid : %d\n", ret); 15 return ret+1; 16 } [ 코드 5] getuid() 후킹함수 [ 코드 5] 는 'getuid()' 후킹함수이다. 이함수가흔히우리가프로그래밍할때사용하는 main() 의역할을하게된다. 8번줄에서가장먼저 'libc' 의로드주소를찾은다음 10번줄에서실제 'libc' 의 getuid함수주소를찾는다. 찾아낸주소는 11번줄에서함수포인터에넣어지고 13번줄에서호출되어변수에저장된다. 가장마지막줄에 'return ret+1' 이있는데이렇게되면실제 uid에 1을더한 uid가리턴될것이다. - 6 -

1 /* -- API Hooking by bin00pang -- */ 2 3 #define _GNU_SOURCE 4 #include <stdio.h> 5 #include <link.h> 6 #include <stdlib.h> 7 #include <string.h> 8 #include <signal.h> 9 10 // 실제 getuid의주소를담을변수 11 unsigned long offset = (unsigned long)null; 12 13 unsigned long libc_start = (unsigned long)null; 14 15 // 실제 getuid() 의진입점을가리킬함수포인터 16 int (*orig_getuid)(void) = NULL; 17 18 void search_getuid_offset(void); 19 20 // SIGSEGV 시그널핸들러 21 static void sig_usr() 22 { 23 printf("[hooker] Received SIGSEGV signal.. quit.. \n"); 24 exit(0); 25 } 26 27 // libc가로드된주소를찾기위한루틴 28 static int scan_callback(struct dl_phdr_info *info, 29 size_t size, 30 void *data) 31 { 32 if(strstr(info->dlpi_name, "libc")) 33 libc_start = (unsigned int)info->dlpi_addr; 34 return 0; 35 } 36 37 38 // getuid 후킹함수 39 int getuid() - 7 -

40 { 41 int ret; 42 if(signal(sigsegv, sig_usr) == SIG_ERR) 43 fprintf(stderr, "Can not catch signal\n"); 44 45 dl_iterate_phdr(scan_callback, NULL); 46 printf("[hooker] libc start address : 0x%x\n", libc_start); 47 search_getuid_offset(); 48 orig_getuid = offset; 49 printf("[hooker] Call Orig getuid!!\n"); 50 ret = orig_getuid(); 51 printf("[hooker] Return value of getuid : %d\n", ret); 52 return ret+1; 53 } 54 55 // 실제 getuid의진입점찾는루틴 56 void search_getuid_offset(void) 57 { 58 printf("[hooker] Searching getuid offset\n"); 59 char pattern[] = "\x55\x89\xe5\xb8"; 60 for(offset = libc_start ; offset < 0xb7ffffff ; offset++) 61 { 62 if(!strncmp((char *)offset, pattern, strlen(pattern))) 63 { 64 printf("[hooker] Found offset : 0x%x\n", offset); 65 break; 66 } 67 } 68 69 if(offset == (unsigned long)null) 70 { 71 printf("[hooker] Can not found offset\n"); 72 exit(0); 73 } 74 } [ 코드 6] Hooker 전체코드 [ 코드 6] 은전체적인 Hooker 의코드이다. 생각보다길지않은것을볼수있다.( 물론더짧 게만들수도있다.:D ) - 8 -

이제실제 [ 코드 6] 을공유라이브러리로만들어보자. 공유라이브러리는아래와같은과정 으로만들어진다. [ 그림 5] 공유라이브러리생성 생성되는대략적인순서는다음과같다. 먼저오브젝트파일로컴파일한다. $ gcc -fpic -c -o hooker hooker.c 공유라이브러리로컴파일한다. $ gcc -shared -W1,-soname,libhooker.so.0 -o libhooker.so hooker 이와같은과정을거치면 [ 그림 5] 와같이 'libhooker.so' 라는공유라이브러리가생성된다. 이제모든후킹의준비가완료되었다. - 9 -

3. Hooker 테스트 3.1. 테스트환경 Hooker 의테스트환경은다음과같다. - 커널버전 : 2.6.24-19-generic - gcc 버전 : 4.2.3 3.2. LD_PRELOAD 를사용한 Hooker 로드 우리가만든 Hooker 를사용하기위해서는일단라이브러리가프로세스에로드되어야한다. 이작업은환경변수인 LD_PRELOAD 가쉽게해준다. [ 그림 6] LD_PRELOAD 익스포트 [ 그림 6] 과같이 LD_PRELOAD 의값을 libhooker.so 의절대경로로설정한다음 export 시키면 이제준비가끝난것이다. [ 그림 7] 디버그모드로실행 [ 그림 7] 은 'id' 명령어를디버그모드로실행한것이다. 보면가장먼저로드하는라이브러리 - 10 -

가바로방금우리가만든 'libhooker.so' 라는것을확인할수있다. 먼저정상적인 'id' 의결 과를확인해보자. [ 그림 8] 정상적인 id 의결과 'libhooker.so' 를로드하기전에는정상적인 id 결과가출력된다. 실제 'binoopang' 의 uid 는 1000 이다. 이제후킹을한다음의결과를보자. [ 그림 9] 후킹후의 id 결과 [ 그림 9] 에서정상적으로 getuid 가후킹되었고원래 1000 이었던 uid 가 1001 로바뀌어출력된 것을확인할수있다. - 11 -

3. 마치며 이문서에서제시한후킹방법은매우간단하다.( 사실걸어가다생각나서해본것이다.) 이방법에는후킹으로써는제한되는부분이많이있다. 특히라이브러리를사용하는방법이기때문에제거하는것이너무쉽다. 다음에는다른방법으로후킹하는방법에대해서써봐야겠다. - 12 -

참고문헌 [1] Linux Manpage, "ld_iterate_phdr" http://linux.die.net/man/3/dl_iterate_phdr - 13 -