Search

2.7 ELF 바이너리 코드 인젝션 기법

7.1 헥스 에디터를 이용한 원초적 수정 방법

기존의 코드와 동일한 사이즈만 수정이 가능함
무의미한 코드가 있을 경우 해당 영역도 포함해서 수정이 가능.

7.1.1 한 바이트 버그 탐구하기

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> void die(char const *fmt, ...) { va_list args; va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); exit(1); } int main(int argc, char *argv[]) { FILE *f; char *infile, *outfile; unsigned char *key, *buf; size_t i, j, n; if(argc != 4) die("Usage: %s <in file> <out file> <key>\n", argv[0]); infile = argv[1]; outfile = argv[2]; key = (unsigned char*)argv[3]; f = fopen(infile, "rb"); if(!f) die("Failed to open file '%s'\n", infile); fseek(f, 0, SEEK_END); n = ftell(f); fseek(f, 0, SEEK_SET); buf = malloc(n); if(!buf) die("Out of memory\n"); if(fread(buf, 1, n, f) != n) die("Failed to read file '%s'\n", infile); fclose(f); j = 0; for(i = 0; i < n-1; i++) { /* Oops! An off-by-one error! */ buf[i] ^= key[j]; j = (j+1) % strlen(key); } f = fopen(outfile, "wb"); if(!f) die("Failed to open file '%s'\n", outfile); if(fwrite(buf, 1, n, f) != n) die("Failed to write file '%s'\n", outfile); fclose(f); return 0; }
C
복사
반복문에서 마지막 1바이트가 빠지게 됨.(index가 0 일 경우 -1과 등호 둘중 하나만 사용해야 함)
00000410: 0a06 4106 094f 1810 0806 034f 090b 0d17 ..A..O.....O.... 00000420: 4648 4a11 462e 084d 4342 0e07 1209 060e FHJ.F..MCB...... 00000430: 045b 5d65 6542 4114 0503 0011 045a 0046 .[]eeBA......Z.F 00000440: 5468 6b52 461d 0a16 1400 084f 5f59 6b0f ThkRF......O_Yk. 00000450: 6c0a 00000410: 6564 2074 6f20 7772 6974 6520 6669 6c65 ed to write file 00000420: 2027 2573 275c 6e22 2c20 6f75 7466 696c '%s'\n", outfil 00000430: 6529 3b0a 0a20 2066 636c 6f73 6528 6629 e);.. fclose(f) 00000440: 3b0a 0a20 2072 6574 7572 6e20 303b 0a7d ;.. return 0;.} 00000450: 0a0a
C
복사
마지막 바이트가 암호화가 안 된것을 확인할 수 있다.

7.1.2 한바이트 버그 수정하기

4007cb: 4d 8d 24 06 lea r12,[r14+rax*1] 4007cf: 74 2e je 4007ff <main+0xdf> 4007d1: 0f 1f 80 00 00 00 00 nop DWORD PTR [rax+0x0] 4007d8: 41 0f b6 04 17 movzx eax,BYTE PTR [r15+rdx*1] 4007dd: 48 8d 6a 01 lea rbp,[rdx+0x1] 4007e1: 4c 89 ff mov rdi,r15 4007e4: 30 03 xor BYTE PTR [rbx],al 4007e6: 48 83 c3 01 add rbx,0x1 4007ea: e8 a1 fe ff ff call 400690 <strlen@plt> 4007ef: 31 d2 xor edx,edx 4007f1: 48 89 c1 mov rcx,rax 4007f4: 48 89 e8 mov rax,rbp 4007f7: 48 f7 f1 div rcx 4007fa: 49 39 dc cmp r12,rbx 4007fd: 75 d9 jne 4007d8 <main+0xb8>
C
복사
r12(n)의 값을 기준으로 같지 않을 경우 점프를 수행하여 암호화를 진행함
jne(jmp not equal) 을 jae(jmp above or equal)로 변조하면 r12가 rbx보다 크거나 같을 경우 점프하기 때문에 jne과 비교해서 반복문을 한번 더 수행이 가능하다.
jne(0x75)를 jae(0x73)으로 변조 후 암호화하여 다시 확인해보면
00000410: 0a06 4106 094f 1810 0806 034f 090b 0d17 ..A..O.....O.... 00000420: 4648 4a11 462e 084d 4342 0e07 1209 060e FHJ.F..MCB...... 00000430: 045b 5d65 6542 4114 0503 0011 045a 0046 .[]eeBA......Z.F 00000440: 5468 6b52 461d 0a16 1400 084f 5f59 6b0f ThkRF......O_Yk. 00000450: 6c65
C
복사
정상적으로 마지막까지 진행 된 것을 볼 수 있다.

7.2 LD_PRELOAD를 사용해 공유 라이브러리 동작 변경하기

공유 라이브러리 함수의 동작을 변경하고자 하는 경우 LD_PRELOAD를 이용하여 더 수월하게 가능하다.
LD_PRELOAD는 동적 링커의 동작과 관련 있는 환경 변수의 이름이다. 해당 환경 변수에 라이브러리를 명시하면 해당 라이브러리가 최 우선적으로 로드되며, 함수 명이 같을 경우 오버라이드 하여 변조한 함수를 호출 가능하다.
윈도우에도 비슷한 기법이 존재하는데, 윈도우에서는 DLL을 로드하여 모든 실행파일에 해당 DLL의 메인을 실행하는 용도로 사용된다.

7.3.1 힙 오버플로우 취약점

아래 소스코드는 첫번째 인자만큼 메모리를 할당하며, 두번째 만큼 할당한 버퍼에 채운다.
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char *argv[]) { char *buf; unsigned long len; if(argc != 3) { printf("Usage: %s <len> <string>\n", argv[0]); return 1; } len = strtoul(argv[1], NULL, 0); printf("Allocating %lu bytes\n", len); buf = malloc(len); if(buf && len > 0) { memset(buf, 0, len); strcpy(buf, argv[2]); printf("%s\n", buf); free(buf); } return 0; }
C
복사
그러나 할당을 작게하고 문자열을 길게 할 경우 strcpy에서 검증이 되지 않아 힙오버플로우가 발생한다.
binary@binary-VirtualBox:~/code/chapter7$ ./heapoverflow 13 "Hello World" Allocating 13 bytes Hello World binary@binary-VirtualBox:~/code/chapter7$ ./heapoverflow 13 `perl -e 'print "A"x100'` Allocating 13 bytes AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA *** Error in `./heapoverflow': free(): invalid next size (fast): 0x00000000014bd420 *** ======= Backtrace: ========= /lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f381d9327e5] /lib/x86_64-linux-gnu/libc.so.6(+0x8037a)[0x7f381d93b37a] /lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7f381d93f53c] ./heapoverflow[0x4007aa] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f381d8db830] ./heapoverflow[0x400609] ======= Memory map: ======== 00400000-00401000 r-xp 00000000 08:01 2361724 /home/binary/code/chapter7/heapoverflow 00600000-00601000 r--p 00000000 08:01 2361724 /home/binary/code/chapter7/heapoverflow 00601000-00602000 rw-p 00001000 08:01 2361724 /home/binary/code/chapter7/heapoverflow 014bd000-014de000 rw-p 00000000 00:00 0 [heap] 7f3818000000-7f3818021000 rw-p 00000000 00:00 0 7f3818021000-7f381c000000 ---p 00000000 00:00 0 7f381d6a5000-7f381d6bb000 r-xp 00000000 08:01 2233513 /lib/x86_64-linux-gnu/libgcc_s.so.1 7f381d6bb000-7f381d8ba000 ---p 00016000 08:01 2233513 /lib/x86_64-linux-gnu/libgcc_s.so.1 7f381d8ba000-7f381d8bb000 rw-p 00015000 08:01 2233513 /lib/x86_64-linux-gnu/libgcc_s.so.1 7f381d8bb000-7f381da7b000 r-xp 00000000 08:01 2228538 /lib/x86_64-linux-gnu/libc-2.23.so 7f381da7b000-7f381dc7b000 ---p 001c0000 08:01 2228538 /lib/x86_64-linux-gnu/libc-2.23.so 7f381dc7b000-7f381dc7f000 r--p 001c0000 08:01 2228538 /lib/x86_64-linux-gnu/libc-2.23.so 7f381dc7f000-7f381dc81000 rw-p 001c4000 08:01 2228538 /lib/x86_64-linux-gnu/libc-2.23.so 7f381dc81000-7f381dc85000 rw-p 00000000 00:00 0 7f381dc85000-7f381dcab000 r-xp 00000000 08:01 2228536 /lib/x86_64-linux-gnu/ld-2.23.so 7f381de8e000-7f381de91000 rw-p 00000000 00:00 0 7f381dea9000-7f381deaa000 rw-p 00000000 00:00 0 7f381deaa000-7f381deab000 r--p 00025000 08:01 2228536 /lib/x86_64-linux-gnu/ld-2.23.so 7f381deab000-7f381deac000 rw-p 00026000 08:01 2228536 /lib/x86_64-linux-gnu/ld-2.23.so 7f381deac000-7f381dead000 rw-p 00000000 00:00 0 7ffdf12bf000-7ffdf12e0000 rw-p 00000000 00:00 0 [stack] 7ffdf1382000-7ffdf1384000 r--p 00000000 00:00 0 [vvar] 7ffdf1384000-7ffdf1386000 r-xp 00000000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] Aborted (core dumped) binary@binary-VirtualBox:~/code/chapter7$
C
복사
#define _GNU_SOURCE //필수 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #include <dlfcn.h> // 함수 포인터 제공 void* (*orig_malloc)(size_t); void (*orig_free)(void*); char* (*orig_strcpy)(char*, const char*); typedef struct { uintptr_t addr; size_t size; } alloc_t; #define MAX_ALLOCS 1024 alloc_t allocs[MAX_ALLOCS]; unsigned alloc_idx = 0; void* malloc(size_t s) { if(!orig_malloc) orig_malloc = dlsym(RTLD_NEXT, "malloc"); //다음번의 malloc 함수(원본함수) 획득. void *ptr = orig_malloc(s); if(ptr) { allocs[alloc_idx].addr = (uintptr_t)ptr; // 원본 함수 호출결과(주소) allocs[alloc_idx].size = s; // 사이즈 alloc_idx = (alloc_idx+1) % MAX_ALLOCS; // 맥스 사이즈 넘을 경우 다시 인덱스 초기화 } return ptr; } void free(void *p) { if(!orig_free) orig_free = dlsym(RTLD_NEXT, "free"); orig_free(p); for(unsigned i = 0; i < MAX_ALLOCS; i++) { if(allocs[i].addr == (uintptr_t)p) { allocs[i].addr = 0; allocs[i].size = 0; break; } } } char* strcpy(char *dst, const char *src) { if(!orig_strcpy) orig_strcpy = dlsym(RTLD_NEXT, "strcpy"); for(unsigned i = 0; i < MAX_ALLOCS; i++) { if(allocs[i].addr == (uintptr_t)dst) { if(allocs[i].size <= strlen(src)) { printf("Bad idea! Aborting strcpy to prevent heap overflow\n"); exit(1); } break; } } return orig_strcpy(dst, src); }
C
복사
//컴파일 gcc -fPIC -c heapcheck.c gcc -shared -o heapcheck.so heapcheck.o -lc -ldl binary@binary-VirtualBox:~/code/chapter7$ ls elfinject.c heapcheck.c heapoverflow.c hello-got.bin ls.entry xor_encrypt.c encrypted heapcheck.o hello.bin hello-got.s ls.got xor_encrypt.fixed encrypted.fixed heapcheck.so hello-ctor.bin hello.s ls.plt xor_encrypt.original encrypted.original heapoverflow hello-ctor.s ls.ctor Makefile //실행 binary@binary-VirtualBox:~/code/chapter7$ LD_PRELOAD=`pwd`/heapcheck.so ./heapoverflow 13 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Allocating 13 bytes Bad idea! Aborting strcpy to prevent heap overflow
C
복사

7.3 코드 섹션 끼워 넣기

1.
Hex 수정으로 인한 바이너리 개조는 매우 제한적
2.
LD_PRELOAD를 이용한 방식은 동적 라이브러리만 가능함

7.3.1 ELF 섹션 끼워넣기: 전체적 맥락

새로운 섹션을 삽입하려면,
1.
섹션이 차지할 바이트 수 추가.
2.
섹션 헤더 추가
3.
프로그램 헤더 추가
프로그램 해더의 경우 ELF 파일 해더 바로 뒤에 존재하기 때문에 추가하려면 헤더 뒤로 데이터를 다 밀어야 하기 때문에 좀 더 편한 방법인
기존에 존재하는 섹션 중 쓰이지 않는 섹션을 수정하여 사용한다.
PT_NOTE 세그먼트 덮어쓰기
PT_NOTE 세그먼트는 바이너리에 대한 부가적인 정보를 포함한 섹션이다.
그림 7-2에서는 임의로 .note.ABI-tag 섹션을 변조하여 사용한다.
거기에 프로그램 헤더와 섹션 헤더에서 해당 섹션이 실행 가능하도록 변경한다.
ELF 엔트리 포인트로 전환하기
그림 7-2의 4번째 단계는 선택적이다.
.injected 섹션의 함수를 먼저 실행해야 할 경우에는 엔트리 포인트로 전환하여야 하지만,
기존 함수에서 .injected섹션으로 전환하는 코드를 추가하거나, 추가로 해당 섹션의 코드가 실행되는 트리거를 설정하여야 한다.
두가지 모두 하지 않았을 경우 삽입된 섹션은 실행되지 않는다.

7.3.2 elfinject를 사용해 ELF 섹션 삽입하기

binary@binary-VirtualBox:~/code/chapter7$ cp /bin/ls . binary@binary-VirtualBox:~/code/chapter7$ make elfinject gcc -o elfinject -O2 elfinject.c -lelf binary@binary-VirtualBox:~/code/chapter7$ ./elfinject ls hello.bin ".injected" 0x800000 0 binary@binary-VirtualBox:~/code/chapter7$ ./ls hello world! elfinject encrypted.original heapoverflow hello-ctor.s ls ls.plt xor_encrypt.original elfinject.c heapcheck.c heapoverflow.c hello-got.bin ls.ctor Makefile encrypted heapcheck.o hello.bin hello-got.s ls.entry xor_encrypt.c encrypted.fixed heapcheck.so hello-ctor.bin hello.s ls.got xor_encrypt.fixed
C
복사
binary@binary-VirtualBox:~/code/chapter7$ readelf --wide --headers ls ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: EXEC (Executable file) Machine: Advanced Micro Devices X86-64 Version: 0x1 Entry point address: 0x800e78 Start of program headers: 64 (bytes into file) Start of section headers: 124728 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 9 Size of section headers: 64 (bytes) Number of section headers: 29 Section header string table index: 28 Section Headers: [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 [ 1] .interp PROGBITS 0000000000400238 000238 00001c 00 A 0 0 1 [ 2] .init PROGBITS 00000000004022b8 0022b8 00001a 00 AX 0 0 4 [ 3] .note.gnu.build-id NOTE 0000000000400274 000274 000024 00 A 0 0 4 [ 4] .gnu.hash GNU_HASH 0000000000400298 000298 0000c0 00 A 5 0 8 [ 5] .dynsym DYNSYM 0000000000400358 000358 000cd8 18 A 6 1 8 [ 6] .dynstr STRTAB 0000000000401030 001030 0005dc 00 A 0 0 1 [ 7] .gnu.version VERSYM 000000000040160c 00160c 000112 02 A 5 0 2 [ 8] .gnu.version_r VERNEED 0000000000401720 001720 000070 00 A 6 1 8 [ 9] .rela.dyn RELA 0000000000401790 001790 0000a8 18 A 5 0 8 [10] .rela.plt RELA 0000000000401838 001838 000a80 18 AI 5 24 8 [11] .plt PROGBITS 00000000004022e0 0022e0 000710 10 AX 0 0 16 [12] .plt.got PROGBITS 00000000004029f0 0029f0 000008 00 AX 0 0 8 [13] .text PROGBITS 0000000000402a00 002a00 011259 00 AX 0 0 16 [14] .fini PROGBITS 0000000000413c5c 013c5c 000009 00 AX 0 0 4 [15] .rodata PROGBITS 0000000000413c80 013c80 006974 00 A 0 0 32 [16] .eh_frame_hdr PROGBITS 000000000041a5f4 01a5f4 000804 00 A 0 0 4 [17] .eh_frame PROGBITS 000000000041adf8 01adf8 002c6c 00 A 0 0 8 [18] .jcr PROGBITS 000000000061de10 01de10 000008 00 WA 0 0 8 [19] .init_array INIT_ARRAY 000000000061de00 01de00 000008 00 WA 0 0 8 [20] .fini_array FINI_ARRAY 000000000061de08 01de08 000008 00 WA 0 0 8 [21] .got PROGBITS 000000000061dff8 01dff8 000008 08 WA 0 0 8 [22] .dynamic DYNAMIC 000000000061de18 01de18 0001e0 10 WA 6 0 8 [23] .got.plt PROGBITS 000000000061e000 01e000 000398 08 WA 0 0 8 [24] .data PROGBITS 000000000061e3a0 01e3a0 000260 00 WA 0 0 32 [25] .gnu_debuglink PROGBITS 0000000000000000 01e600 000034 00 0 0 1 [26] .bss NOBITS 000000000061e600 01e600 000d68 00 WA 0 0 32 [27] .injected PROGBITS 0000000000800e78 01ee78 00003f 00 AX 0 0 16 [28] .shstrtab STRTAB 0000000000000000 01e634 000102 00 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings), l (large) I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown) O (extra OS processing required) o (OS specific), p (processor specific) Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align PHDR 0x000040 0x0000000000400040 0x0000000000400040 0x0001f8 0x0001f8 R E 0x8 INTERP 0x000238 0x0000000000400238 0x0000000000400238 0x00001c 0x00001c R 0x1 [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] LOAD 0x000000 0x0000000000400000 0x0000000000400000 0x01da64 0x01da64 R E 0x200000 LOAD 0x01de00 0x000000000061de00 0x000000000061de00 0x000800 0x001568 RW 0x200000 DYNAMIC 0x01de18 0x000000000061de18 0x000000000061de18 0x0001e0 0x0001e0 RW 0x8 LOAD 0x01ee78 0x0000000000800e78 0x0000000000800e78 0x00003f 0x00003f R E 0x1000 GNU_EH_FRAME 0x01a5f4 0x000000000041a5f4 0x000000000041a5f4 0x000804 0x000804 R 0x4 GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10 GNU_RELRO 0x01de00 0x000000000061de00 0x000000000061de00 0x000200 0x000200 R 0x1 Section to Segment mapping: Segment Sections... 00 01 .interp 02 .interp .init .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .plt .plt.got .text .fini .rodata .eh_frame_hdr .eh_frame 03 .jcr .init_array .fini_array .got .dynamic .got.plt .data .bss 04 .dynamic 05 .injected 06 .eh_frame_hdr 07 08 .jcr .init_array .fini_array .got .dynamic binary@binary-VirtualBox:~/code/chapter7$
C
복사

7.4 삽입된 코드 호출하기

7.4.1 엔트리 포인트 개조

헥스 편집기를 통해 엔트리 포인트 자체를 직접 수정하는 방식을 사용하겠다.
해당 실습에 사용할 소스는 아래와 같다.
BITS 64 //64비트 SECTION .text global main main: push rax ; save all clobbered registers // 함수 프롤로그 push rcx ; (rcx and r11 destroyed by kernel) push rdx push rsi push rdi push r11 mov rax,1 ; sys_write //syscall write 호출 변수 mov rdi,1 ; stdout lea rsi,[rel $+hello-$] ; hello mov rdx,[rel $+len-$] ; len syscall pop r11 //함수 에필로그 pop rdi pop rsi pop rdx pop rcx pop rax push 0x4049a0 ; jump to original entry point ret hello: db "hello world",33,10 //문자열 len : dd 13 // 길이
C
복사
해당 코드를 컴파일 하고 elfinject를 이용하여 삽입해준다
binary@binary-VirtualBox:~/code/chapter7$ ./elfinject ls.entry hello.bin ".injected" 0x800000 -1 binary@binary-VirtualBox:~/code/chapter7$ readelf -h ./ls.entry ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: EXEC (Executable file) Machine: Advanced Micro Devices X86-64 Version: 0x1 Entry point address: 0x4049a0 Start of program headers: 64 (bytes into file) Start of section headers: 124728 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 9 Size of section headers: 64 (bytes) Number of section headers: 29 Section header string table index: 28
C
복사
확인 해 보면 엔트리포인트가 변경되지 않았다.
hexedit으로 직접 수정해준다.
00000000 7F 45 4C 46 02 01 01 00 00 00 00 00 00 00 00 00 02 00 3E 00 01 00 00 00 .ELF..............>..... 00000018 78 0E 80 00 00 00 00 00 40 00 00 00 00 00 00 00 38 E7 01 00 00 00 00 00 x.......@.......8....... 00000030 00 00 00 00 40 00 38 00 09 00 40 00 1D 00 1C 00 06 00 00 00 05 00 00 00 ....@.8...@............. 00000048 40 00 00 00 00 00 00 00 40 00 40 00 00 00 00 00 40 00 40 00 00 00 00 00 @.......@.@.....@.@..... 00000060 F8 01 00 00 00 00 00 00 F8 01 00 00 00 00 00 00 08 00 00 00 00 00 00 00 ........................ 00000078 03 00 00 00 04 00 00 00 38 02 00 00 00 00 00 00 38 02 40 00 00 00 00 00 ........8.......8.@..... 00000090 38 02 40 00 00 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 00 00 00 00 8.@..................... 000000A8 01 00 00 00 00 00 00 00 01 00 00 00 05 00 00 00 00 00 00 00 00 00 00 00 ........................ 000000C0 00 00 40 00 00 00 00 00 00 00 40 00 00 00 00 00 64 DA 01 00 00 00 00 00 ..@.......@.....d....... 000000D8 64 DA 01 00 00 00 00 00 00 00 20 00 00 00 00 00 01 00 00 00 06 00 00 00 d......... ............. 000000F0 00 DE 01 00 00 00 00 00 00 DE 61 00 00 00 00 00 00 DE 61 00 00 00 00 00 ..........a.......a..... 00000108 00 08 00 00 00 00 00 00 68 15 00 00 00 00 00 00 00 00 20 00 00 00 00 00 ........h......... ..... 00000120 02 00 00 00 06 00 00 00 18 DE 01 00 00 00 00 00 18 DE 61 00 00 00 00 00 ..................a..... binary@binary-VirtualBox:~/code/chapter7$ readelf -h ./ls.entry ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: EXEC (Executable file) Machine: Advanced Micro Devices X86-64 Version: 0x1 Entry point address: 0x800e78 Start of program headers: 64 (bytes into file) Start of section headers: 124728 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 9 Size of section headers: 64 (bytes) Number of section headers: 29 Section header string table index: 28 binary@binary-VirtualBox:~/code/chapter7$
C
복사
정상적으로 변조된 것을 확인할 수 있다.
binary@binary-VirtualBox:~/code/chapter7$ ./ls.entry hello world! elfinject encrypted.original heapoverflow hello-ctor.s ls ls.plt xor_encrypt.original elfinject.c heapcheck.c heapoverflow.c hello-got.bin ls.ctor Makefile encrypted heapcheck.o hello.bin hello-got.s ls.entry xor_encrypt.c encrypted.fixed heapcheck.so hello-ctor.bin hello.s ls.got xor_encrypt.fixed binary@binary-VirtualBox:~/code/chapter7$
C
복사
실행해보면 정상적으로 실행되는것을 볼 수 있다.

7.4.2 생성자와 소멸자 탈취하기

생성자와 소멸자의 주소값을 후킹하여 삽입한 바이너리가 호출되도록 변조하여 보자.
BITS 64 SECTION .text global main main: push rax ; save all clobbered registers push rcx ; (rcx and r11 destroyed by kernel) push rdx push rsi push rdi push r11 mov rax,1 ; sys_write mov rdi,1 ; stdout lea rsi,[rel $+hello-$] ; hello mov rdx,[rel $+len-$] ; len syscall pop r11 pop rdi pop rsi pop rdx pop rcx pop rax push 0x404a70 ; jump to original constructor ret hello: db "hello world",33,10 len : dd 13
C
복사
elfInject로 바이너리를 삽입한 후 확인해보자
binary@binary-VirtualBox:~/code/chapter7$ readelf --wide -S ls.ctor There are 29 section headers, starting at offset 0x1e738: Section Headers: [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 [ 1] .interp PROGBITS 0000000000400238 000238 00001c 00 A 0 0 1 [ 2] .init PROGBITS 00000000004022b8 0022b8 00001a 00 AX 0 0 4 [ 3] .note.gnu.build-id NOTE 0000000000400274 000274 000024 00 A 0 0 4 [ 4] .gnu.hash GNU_HASH 0000000000400298 000298 0000c0 00 A 5 0 8 [ 5] .dynsym DYNSYM 0000000000400358 000358 000cd8 18 A 6 1 8 [ 6] .dynstr STRTAB 0000000000401030 001030 0005dc 00 A 0 0 1 [ 7] .gnu.version VERSYM 000000000040160c 00160c 000112 02 A 5 0 2 [ 8] .gnu.version_r VERNEED 0000000000401720 001720 000070 00 A 6 1 8 [ 9] .rela.dyn RELA 0000000000401790 001790 0000a8 18 A 5 0 8 [10] .rela.plt RELA 0000000000401838 001838 000a80 18 AI 5 24 8 [11] .plt PROGBITS 00000000004022e0 0022e0 000710 10 AX 0 0 16 [12] .plt.got PROGBITS 00000000004029f0 0029f0 000008 00 AX 0 0 8 [13] .text PROGBITS 0000000000402a00 002a00 011259 00 AX 0 0 16 [14] .fini PROGBITS 0000000000413c5c 013c5c 000009 00 AX 0 0 4 [15] .rodata PROGBITS 0000000000413c80 013c80 006974 00 A 0 0 32 [16] .eh_frame_hdr PROGBITS 000000000041a5f4 01a5f4 000804 00 A 0 0 4 [17] .eh_frame PROGBITS 000000000041adf8 01adf8 002c6c 00 A 0 0 8 [18] .jcr PROGBITS 000000000061de10 01de10 000008 00 WA 0 0 8 [19] .init_array INIT_ARRAY 000000000061de00 01de00 000008 00 WA 0 0 8 [20] .fini_array FINI_ARRAY 000000000061de08 01de08 000008 00 WA 0 0 8 [21] .got PROGBITS 000000000061dff8 01dff8 000008 08 WA 0 0 8 [22] .dynamic DYNAMIC 000000000061de18 01de18 0001e0 10 WA 6 0 8 [23] .got.plt PROGBITS 000000000061e000 01e000 000398 08 WA 0 0 8 [24] .data PROGBITS 000000000061e3a0 01e3a0 000260 00 WA 0 0 32 [25] .gnu_debuglink PROGBITS 0000000000000000 01e600 000034 00 0 0 1 [26] .bss NOBITS 000000000061e600 01e600 000d68 00 WA 0 0 32 [27] .injected PROGBITS 0000000000800e78 01ee78 00003f 00 AX 0 0 16 [28] .shstrtab STRTAB 0000000000000000 01e634 000102 00 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings), l (large) I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown) O (extra OS processing required) o (OS specific), p (processor specific) binary@binary-VirtualBox:~/code/chapter7$ objdump ls.ctor -s --section=.init_array ls.ctor: file format elf64-x86-64 Contents of section .init_array: 61de00 704a4000 00000000 pJ@.....
C
복사
해당 섹션을 확인해보면 생성자 함수의 포인터를 보여준다. 해당 값을 변조해주고 실행해보면
binary@binary-VirtualBox:~/code/chapter7$ ./ls.ctor hello world! elfinject encrypted.original heapoverflow hello-ctor.s ls ls.plt xor_encrypt.original elfinject.c heapcheck.c heapoverflow.c hello-got.bin ls.ctor Makefile encrypted heapcheck.o hello.bin hello-got.s ls.entry xor_encrypt.c encrypted.fixed heapcheck.so hello-ctor.bin hello.s ls.got xor_encrypt.fixed
C
복사
아래와 같이 hello world! 가 호출된다.