haehet

프로그램 시작, 종료 과정 및 관련 취약점 분석 본문

Pwnable

프로그램 시작, 종료 과정 및 관련 취약점 분석

haehet 2025. 8. 23. 21:04

최근에 드림핵에서 tiny backdoor 8단계 문제를 풀었는데 .fini.array를 조작해야 하는 문제였다. 이 문제를 풀면서 프로그램의 시작, 종료 관련 취약점에 대해서 정리해야겠다는 생각이 들었다. 

*이 글은 (Ubuntu GLIBC 2.35-0ubuntu3.10)을 기준으로 분석했다. 라이브러리 버전마다 약간씩 차이가 있을 수 있다.

또한 gcc (Ubuntu 11.4.0-1ubuntu1~22.04.2) 기준으로 컴파일을 했다.

 

아래에 있는 간단한 코드를 통해 분석 해보겠따.

 

 

#include <stdio.h>

//gcc -o test test.c

int main(int argc, char* argv)
{
	printf("%s", "test\n");
	return 0;
}

 

프로그램 시작 과정 

1. execve -> ld.so

우리가 프로그램을 실행 시키면 execve를 통해 프로세스를 생성한다. 그리고 execve는 프로그램의 .interp 섹션에 저장되어 있는  ld.so를 실행 시킨다.

pwndbg> info file
Symbols from "/home/haehet/test".
Local exec file:
	`/home/haehet/test', file type elf64-x86-64.
	Entry point: 0x1060
	0x0000000000000318 - 0x0000000000000334 is .interp
	0x0000000000000338 - 0x0000000000000368 is .note.gnu.property
	0x0000000000000368 - 0x000000000000038c is .note.gnu.build-id
	0x000000000000038c - 0x00000000000003ac is .note.ABI-tag
	0x00000000000003b0 - 0x00000000000003d4 is .gnu.hash
	0x00000000000003d8 - 0x0000000000000480 is .dynsym
	0x0000000000000480 - 0x000000000000050d is .dynstr
	0x000000000000050e - 0x000000000000051c is .gnu.version
	0x0000000000000520 - 0x0000000000000550 is .gnu.version_r
	0x0000000000000550 - 0x0000000000000610 is .rela.dyn
	0x0000000000000610 - 0x0000000000000628 is .rela.plt
	0x0000000000001000 - 0x000000000000101b is .init
	0x0000000000001020 - 0x0000000000001040 is .plt
	0x0000000000001040 - 0x0000000000001050 is .plt.got
	0x0000000000001050 - 0x0000000000001060 is .plt.sec
	0x0000000000001060 - 0x0000000000001172 is .text
	0x0000000000001174 - 0x0000000000001181 is .fini
	0x0000000000002000 - 0x0000000000002009 is .rodata
	0x000000000000200c - 0x0000000000002040 is .eh_frame_hdr
	0x0000000000002040 - 0x00000000000020ec is .eh_frame
	0x0000000000003db8 - 0x0000000000003dc0 is .init_array
	0x0000000000003dc0 - 0x0000000000003dc8 is .fini_array
	0x0000000000003dc8 - 0x0000000000003fb8 is .dynamic
	0x0000000000003fb8 - 0x0000000000004000 is .got
	0x0000000000004000 - 0x0000000000004010 is .data
	0x0000000000004010 - 0x0000000000004018 is .bss
pwndbg> x/s 0x0000000000000318
0x318:	"/lib64/ld-linux-x86-64.so.2"
pwndbg>

 

ld.so는 동적 라이브러리 glibc를 프로그램에 매핑 해주고 각종 초기화 작업을 한다.

 

2. start

ld.so 다음에는 바이너리 내부에 Entry point에 있는 start 함수를 실행 시킨다.

pwndbg> info file
Symbols from "/home/haehet/test".
Local exec file:
	`/home/haehet/test', file type elf64-x86-64.
	Entry point: 0x1060
	0x0000000000000318 - 0x0000000000000334 is .interp
	0x0000000000000338 - 0x0000000000000368 is .note.gnu.property
	0x0000000000000368 - 0x000000000000038c is .note.gnu.build-id
	0x000000000000038c - 0x00000000000003ac is .note.ABI-tag
	0x00000000000003b0 - 0x00000000000003d4 is .gnu.hash
	0x00000000000003d8 - 0x0000000000000480 is .dynsym
	0x0000000000000480 - 0x000000000000050d is .dynstr
	0x000000000000050e - 0x000000000000051c is .gnu.version
	0x0000000000000520 - 0x0000000000000550 is .gnu.version_r
	0x0000000000000550 - 0x0000000000000610 is .rela.dyn
	0x0000000000000610 - 0x0000000000000628 is .rela.plt
	0x0000000000001000 - 0x000000000000101b is .init
	0x0000000000001020 - 0x0000000000001040 is .plt
	0x0000000000001040 - 0x0000000000001050 is .plt.got
	0x0000000000001050 - 0x0000000000001060 is .plt.sec
	0x0000000000001060 - 0x0000000000001172 is .text
	0x0000000000001174 - 0x0000000000001181 is .fini
	0x0000000000002000 - 0x0000000000002009 is .rodata
	0x000000000000200c - 0x0000000000002040 is .eh_frame_hdr
	0x0000000000002040 - 0x00000000000020ec is .eh_frame
	0x0000000000003db8 - 0x0000000000003dc0 is .init_array
	0x0000000000003dc0 - 0x0000000000003dc8 is .fini_array
	0x0000000000003dc8 - 0x0000000000003fb8 is .dynamic
	0x0000000000003fb8 - 0x0000000000004000 is .got
	0x0000000000004000 - 0x0000000000004010 is .data
	0x0000000000004010 - 0x0000000000004018 is .bss
pwndbg> x/13i 0x1060
   0x1060 <_start>:	endbr64 
   0x1064 <_start+4>:	xor    ebp,ebp
   0x1066 <_start+6>:	mov    r9,rdx
   0x1069 <_start+9>:	pop    rsi
   0x106a <_start+10>:	mov    rdx,rsp
   0x106d <_start+13>:	and    rsp,0xfffffffffffffff0
   0x1071 <_start+17>:	push   rax
   0x1072 <_start+18>:	push   rsp
   0x1073 <_start+19>:	xor    r8d,r8d
   0x1076 <_start+22>:	xor    ecx,ecx
   0x1078 <_start+24>:	lea    rdi,[rip+0xca]        # 0x1149 <main>
   0x107f <_start+31>:	call   QWORD PTR [rip+0x2f53]        # 0x3fd8
   0x1085 <_start+37>:	hlt

 

start 함수는 각종 register을 초기화 하고 rdi에 main의 주소를 넣은 뒤 특정영역 주소를 실행 시키는데 이 주소가 __libc_start_main_impl의 GOT가 된다.

 

3.   __libc_start_main_impl, _libc_start_call_main -> main 호출

__libc_start_main_impl에서는 각종 인자 세팅 및 점검 후 __libc_start_call_main을 호출 한다.

pwndbg> x/90i  0x7ffff7c29dc0
   0x7ffff7c29dc0 <__libc_start_main_impl>:	endbr64 
   0x7ffff7c29dc4 <__libc_start_main_impl+4>:	push   r15
   0x7ffff7c29dc6 <__libc_start_main_impl+6>:	mov    r15,rcx
   0x7ffff7c29dc9 <__libc_start_main_impl+9>:	push   r14
   0x7ffff7c29dcb <__libc_start_main_impl+11>:	push   r13
   0x7ffff7c29dcd <__libc_start_main_impl+13>:	mov    r13,rdi
   0x7ffff7c29dd0 <__libc_start_main_impl+16>:	push   r12
   0x7ffff7c29dd2 <__libc_start_main_impl+18>:	mov    r12,rdx
   0x7ffff7c29dd5 <__libc_start_main_impl+21>:	push   rbp
   0x7ffff7c29dd6 <__libc_start_main_impl+22>:	mov    ebp,esi
   0x7ffff7c29dd8 <__libc_start_main_impl+24>:	push   rbx
   0x7ffff7c29dd9 <__libc_start_main_impl+25>:	sub    rsp,0x18
   0x7ffff7c29ddd <__libc_start_main_impl+29>:	test   r9,r9
   0x7ffff7c29de0 <__libc_start_main_impl+32>:	je     0x7ffff7c29dee <__libc_start_main_impl+46>
   0x7ffff7c29de2 <__libc_start_main_impl+34>:	mov    rdi,r9
   0x7ffff7c29de5 <__libc_start_main_impl+37>:	xor    edx,edx
   0x7ffff7c29de7 <__libc_start_main_impl+39>:	xor    esi,esi
   0x7ffff7c29de9 <__libc_start_main_impl+41>:	call   0x7ffff7c458c0 <__GI___cxa_atexit>
   0x7ffff7c29dee <__libc_start_main_impl+46>:	mov    rax,QWORD PTR [rip+0x1f00d3]        # 0x7ffff7e19ec8
   0x7ffff7c29df5 <__libc_start_main_impl+53>:	mov    eax,DWORD PTR [rax]
   0x7ffff7c29df7 <__libc_start_main_impl+55>:	mov    ebx,eax
   0x7ffff7c29df9 <__libc_start_main_impl+57>:	mov    DWORD PTR [rsp],eax
   0x7ffff7c29dfc <__libc_start_main_impl+60>:	and    ebx,0x2
   0x7ffff7c29dff <__libc_start_main_impl+63>:	jne    0x7ffff7c29ee9 <__libc_start_main_impl+297>
   0x7ffff7c29e05 <__libc_start_main_impl+69>:	mov    rax,QWORD PTR [rip+0x1f01ac]        # 0x7ffff7e19fb8
   0x7ffff7c29e0c <__libc_start_main_impl+76>:	mov    rdx,QWORD PTR [rax]
   0x7ffff7c29e0f <__libc_start_main_impl+79>:	test   r15,r15
   0x7ffff7c29e12 <__libc_start_main_impl+82>:	je     0x7ffff7c29e40 <__libc_start_main_impl+128>
   0x7ffff7c29e14 <__libc_start_main_impl+84>:	mov    rsi,r12
   0x7ffff7c29e17 <__libc_start_main_impl+87>:	mov    edi,ebp
   0x7ffff7c29e19 <__libc_start_main_impl+89>:	call   r15
   0x7ffff7c29e1c <__libc_start_main_impl+92>:	mov    r15,QWORD PTR [rip+0x1f017d]        # 0x7ffff7e19fa0
   0x7ffff7c29e23 <__libc_start_main_impl+99>:	mov    rdi,QWORD PTR [r15]
   0x7ffff7c29e26 <__libc_start_main_impl+102>:	call   0x7ffff7c286d0 <_dl_audit_preinit@plt>
   0x7ffff7c29e2b <__libc_start_main_impl+107>:	test   ebx,ebx
   0x7ffff7c29e2d <__libc_start_main_impl+109>:	jne    0x7ffff7c29eca <__libc_start_main_impl+266>
   0x7ffff7c29e33 <__libc_start_main_impl+115>:	mov    rdx,r12
   0x7ffff7c29e36 <__libc_start_main_impl+118>:	mov    esi,ebp
   0x7ffff7c29e38 <__libc_start_main_impl+120>:	mov    rdi,r13
   0x7ffff7c29e3b <__libc_start_main_impl+123>:	call   0x7ffff7c29d10 <__libc_start_call_main>
   0x7ffff7c29e40 <__libc_start_main_impl+128>:	mov    r15,QWORD PTR [rip+0x1f0159]        # 0x7ffff7e19fa0
   0x7ffff7c29e47 <__libc_start_main_impl+135>:	mov    r14,QWORD PTR [r15]
   0x7ffff7c29e4a <__libc_start_main_impl+138>:	mov    rcx,QWORD PTR [r14+0xa0]
   0x7ffff7c29e51 <__libc_start_main_impl+145>:	test   rcx,rcx
   0x7ffff7c29e54 <__libc_start_main_impl+148>:	je     0x7ffff7c29e6c <__libc_start_main_impl+172>
   0x7ffff7c29e56 <__libc_start_main_impl+150>:	mov    QWORD PTR [rsp],rdx
   0x7ffff7c29e5a <__libc_start_main_impl+154>:	mov    rcx,QWORD PTR [rcx+0x8]
   0x7ffff7c29e5e <__libc_start_main_impl+158>:	mov    rsi,r12
   0x7ffff7c29e61 <__libc_start_main_impl+161>:	mov    edi,ebp
   0x7ffff7c29e63 <__libc_start_main_impl+163>:	add    rcx,QWORD PTR [r14]
   0x7ffff7c29e66 <__libc_start_main_impl+166>:	call   rcx
   0x7ffff7c29e68 <__libc_start_main_impl+168>:	mov    rdx,QWORD PTR [rsp]
   0x7ffff7c29e6c <__libc_start_main_impl+172>:	mov    rdi,QWORD PTR [r14+0x108]
   0x7ffff7c29e73 <__libc_start_main_impl+179>:	test   rdi,rdi
   0x7ffff7c29e76 <__libc_start_main_impl+182>:	je     0x7ffff7c29e23 <__libc_start_main_impl+99>
   0x7ffff7c29e78 <__libc_start_main_impl+184>:	mov    rcx,QWORD PTR [r14+0x118]
   0x7ffff7c29e7f <__libc_start_main_impl+191>:	mov    rsi,QWORD PTR [rcx+0x8]
   0x7ffff7c29e83 <__libc_start_main_impl+195>:	mov    rcx,QWORD PTR [r14]
   0x7ffff7c29e86 <__libc_start_main_impl+198>:	add    rcx,QWORD PTR [rdi+0x8]
   0x7ffff7c29e8a <__libc_start_main_impl+202>:	shr    rsi,0x3
   0x7ffff7c29e8e <__libc_start_main_impl+206>:	test   esi,esi
   0x7ffff7c29e90 <__libc_start_main_impl+208>:	je     0x7ffff7c29e23 <__libc_start_main_impl+99>
   0x7ffff7c29e92 <__libc_start_main_impl+210>:	sub    esi,0x1
   0x7ffff7c29e95 <__libc_start_main_impl+213>:	lea    r14,[rcx+0x8]
   0x7ffff7c29e99 <__libc_start_main_impl+217>:	lea    rax,[r14+rsi*8]
   0x7ffff7c29e9d <__libc_start_main_impl+221>:	mov    QWORD PTR [rsp+0x8],rax
   0x7ffff7c29ea2 <__libc_start_main_impl+226>:	jmp    0x7ffff7c29eb0 <__libc_start_main_impl+240>
   0x7ffff7c29ea4 <__libc_start_main_impl+228>:	nop    DWORD PTR [rax+0x0]
   0x7ffff7c29ea8 <__libc_start_main_impl+232>:	mov    rdx,QWORD PTR [rsp]
   0x7ffff7c29eac <__libc_start_main_impl+236>:	add    r14,0x8
   0x7ffff7c29eb0 <__libc_start_main_impl+240>:	mov    QWORD PTR [rsp],rdx
   0x7ffff7c29eb4 <__libc_start_main_impl+244>:	mov    rsi,r12
   0x7ffff7c29eb7 <__libc_start_main_impl+247>:	mov    edi,ebp
   0x7ffff7c29eb9 <__libc_start_main_impl+249>:	call   QWORD PTR [rcx]
   0x7ffff7c29ebb <__libc_start_main_impl+251>:	mov    rcx,r14
   0x7ffff7c29ebe <__libc_start_main_impl+254>:	cmp    QWORD PTR [rsp+0x8],r14
   0x7ffff7c29ec3 <__libc_start_main_impl+259>:	jne    0x7ffff7c29ea8 <__libc_start_main_impl+232>
   0x7ffff7c29ec5 <__libc_start_main_impl+261>:	jmp    0x7ffff7c29e23 <__libc_start_main_impl+99>
   0x7ffff7c29eca <__libc_start_main_impl+266>:	mov    rbx,QWORD PTR [rip+0x1efff7]        # 0x7ffff7e19ec8
   0x7ffff7c29ed1 <__libc_start_main_impl+273>:	mov    rsi,QWORD PTR [r12]
   0x7ffff7c29ed5 <__libc_start_main_impl+277>:	lea    rdi,[rip+0x1ae0be]        # 0x7ffff7dd7f9a
   0x7ffff7c29edc <__libc_start_main_impl+284>:	xor    eax,eax
   0x7ffff7c29ede <__libc_start_main_impl+286>:	call   QWORD PTR [rbx+0x330]
   0x7ffff7c29ee4 <__libc_start_main_impl+292>:	jmp    0x7ffff7c29e33 <__libc_start_main_impl+115>
   0x7ffff7c29ee9 <__libc_start_main_impl+297>:	mov    rcx,QWORD PTR [rip+0x1effd8]        # 0x7ffff7e19ec8
   0x7ffff7c29ef0 <__libc_start_main_impl+304>:	mov    rsi,QWORD PTR [r12]
   0x7ffff7c29ef4 <__libc_start_main_impl+308>:	lea    rdi,[rip+0x1ae085]        # 0x7ffff7dd7f80
   0x7ffff7c29efb <__libc_start_main_impl+315>:	xor    eax,eax
   0x7ffff7c29efd <__libc_start_main_impl+317>:	call   QWORD PTR [rcx+0x330]
   0x7ffff7c29f03 <__libc_start_main_impl+323>:	jmp    0x7ffff7c29e05 <__libc_start_main_impl+69>

 

__libc_start_call_main은 main에 사용되는 인자를 세팅 한 후 libc_csu_init과 main을 호출 한다. 이 함수는 .initi_array에 있는 함수들을 호출한다.  위 바이너리를 내가 컴파일 했을 때는 libc_csu_init이 나오지 않았다. 최적화 문제인가 싶어서 코드를 길게 짜보아도 왜인지 나오지 않았다. gcc버전 문제인듯 하다. libc_csu_init를 가젯으로 이용하는 기법이 있으므로 찾아보도록 하자.

 

프로그램 종료 과정

1.  __GI_exit

main 함수에서 ret 후 __libc_start_call_main에서는 __GI_exit을 실행 시킨다.  __GI_exit은 인자에 __exit_funcs을 넣고 __run_exit_handlers을 호출한다.

 

pwndbg> x/8i 0x7ffff7c455f0
   0x7ffff7c455f0 <__GI_exit>:	endbr64 
   0x7ffff7c455f4 <__GI_exit+4>:	push   rax
   0x7ffff7c455f5 <__GI_exit+5>:	pop    rax
   0x7ffff7c455f6 <__GI_exit+6>:	mov    ecx,0x1
   0x7ffff7c455fb <__GI_exit+11>:	mov    edx,0x1
   0x7ffff7c45600 <__GI_exit+16>:	lea    rsi,[rip+0x1d5231]        # 0x7ffff7e1a838 <__exit_funcs>
   0x7ffff7c45607 <__GI_exit+23>:	sub    rsp,0x8
   0x7ffff7c4560b <__GI_exit+27>:	call   0x7ffff7c45390 <__run_exit_handlers>
pwndbg> x/6gx 0x7ffff7e1a838
0x7ffff7e1a838 <__exit_funcs>:	0x00007ffff7e1bf00	0x00007ffff7e1c320
0x7ffff7e1a848:	0x0000000000000000	0x0000000000000000
0x7ffff7e1a858:	0x0000000000000000	0x00007ffff7e1a210
pwndbg> x/gx 0x00007ffff7e1bf00
0x7ffff7e1bf00 <initial>:	0x0000000000000000
pwndbg> x/gx 0x00007ffff7e1c320
0x7ffff7e1c320 <initial_quick>:	0x0000000000000000
pwndbg> x/gx 0x00007ffff7e1a210
0x7ffff7e1a210 <randtbl+16>:	0x4e508aaa3e01511e

 

2.  __run_exit_handlers (exit handler overwrite)

__run_exit_handlers은 프로그램 종료시 등록되어 있는 함수들을 실행시키는 함수이다. 코드가 길어서 중요한 부분만 보도록하겠다.

   0x00007ffff7c45463 <+211>:	mov    rax,QWORD PTR [rdx+0x18]
   0x00007ffff7c45467 <+215>:	mov    r13,QWORD PTR [rdx+0x20]
   0x00007ffff7c4546b <+219>:	mov    QWORD PTR [rdx+0x10],0x0
   0x00007ffff7c45473 <+227>:	mov    edx,ebx
   0x00007ffff7c45475 <+229>:	ror    rax,0x11
   0x00007ffff7c45479 <+233>:	xor    rax,QWORD PTR fs:0x30
   0x00007ffff7c45482 <+242>:	xchg   DWORD PTR [r14],edx
   0x00007ffff7c45485 <+245>:	cmp    edx,0x1
   0x00007ffff7c45488 <+248>:	jg     0x7ffff7c455a0 <__run_exit_handlers+528>
   0x00007ffff7c4548e <+254>:	mov    esi,ebp
   0x00007ffff7c45490 <+256>:	mov    rdi,r13
   0x00007ffff7c45493 <+259>:	call   rax

  RDX  0x7ffff7e1bf00 (initial) ◂— 0

여기서 rax에는 initial+0x18의 주소가 들어간다. initial+0x18에서 함수의 주소를 가져온 후 함수의 rdi에는 initial+0x20의 값을 넣는다. 그 후 가져온 함수 주소를 ror 0x11연산을 하고 fs:0x30 값과 xor을 한 후 사용한다. 이 것을 이용해서 glibc 2.35에서 사용 가능한 강력한 기법이 있다.

exit handler overwrite

1. fsbase+0x30 값을 leak 또는 0으로 덮는다.

2. 우리가 넣을 함수 주소가 system이라 하면 mangled_system = fsbase+0x30 ^ (rol system, 0x11)과 같이 계산해준다.

3. initial+0x10에 p64(0x4) + p64(mangled_system) + p64(binsh) 이렇게 쓴다. 

 

3.  _dl_fini

__run_exit_handlers는 initial에서 _dl_fini 함수를 실행시킨다. _dl_fini에도 특정 구조체를 덮어서 실행 흐름을 바꾸는 overwrite _rtld_global 기법이 존재한다. 하지만 glibc 2.35에서는 하기 어렵다. 따라서 여기서는 다루지 않겠다.

*RAX  0x7ffff7fc9040 (_dl_fini) ◂— endbr64 
 RBX  0
*RCX  4
*RDX  1
*RDI  0
*RSI  0
*R8   0
*R9   0x5555555592a0 ◂— 0xa74736574 /* 'test\n' */
*R10  0x77
*R11  0x246
*R12  0x7ffff7e1a838 (__exit_funcs) —▸ 0x7ffff7e1bf00 (initial) ◂— 0
*R13  0
*R14  0x7ffff7e1bee8 (__exit_funcs_lock) ◂— 0
*R15  0x7ffff7e1bf00 (initial) ◂— 0
*RBP  0
*RSP  0x7fffffffdec0 —▸ 0x555555556004 ◂— 0x74736574 /* 'test' */
*RIP  0x7ffff7c45493 (__run_exit_handlers+259) ◂— call rax
────────────────────────[ DISASM / x86-64 / set emulate on ]────────────────────────
 ► 0x7ffff7c45493 <__run_exit_handlers+259>    call   rax                         <_dl_fini>

 

_dl_fini는 .fini_array에 있는 값들을 호출 한다.

 0x00007ffff7fc9242 <+514>:	nop    WORD PTR [rax+rax*1+0x0]
 0x00007ffff7fc9248 <+520>:	mov    QWORD PTR [rbp-0x38],rax
 0x00007ffff7fc924c <+524>:	call   QWORD PTR [rax]
   
 RAX  0x555555557dc0 (__do_global_dtors_aux_fini_array_entry) —▸ 0x555555555100 (__do_global_dtors_aux) ◂— endbr64 
 0x0000555555557dc0 - 0x0000555555557dc8 is .fini_array

 

 

여기서 또 가능한 기법이 있다.

 

.fini_array overwrite

No RELRO일때 .fini_array를 덮으면 우리가 원하는 함수 실행이 가능하다.

 

4.  _fini

_dl_fini는 _fini라는 함수를 실행 시키는데 딱히 하는 동작이 없는 함수이다.

 0x00007ffff7fc926b <+555>:	mov    rax,QWORD PTR [rax+0x8]
 0x00007ffff7fc926f <+559>:	add    rax,QWORD PTR [r15]
 0x00007ffff7fc9272 <+562>:	call   rax


 RAX  0x555555555174 (_fini) ◂— endbr64 

pwndbg> x/4i 0x555555555174
   0x555555555174 <_fini>:	endbr64 
   0x555555555178 <_fini+4>:	sub    rsp,0x8
   0x55555555517c <_fini+8>:	add    rsp,0x8
   0x555555555180 <_fini+12>:	ret

 

5.  __GI__exit

_dl_fini가 종료되고 __run_exit_handlers로 돌아오면 __GI__exit를 실행 시킨다. 이 함수는 처음에 설명한 함수와 다른 함수이다.(_가 하나 더있다) 이 함수는 syscall 231번(sys_exit_group)을 통해 프로그램을 종료시킨다.

pwndbg> disass __GI__exit
Dump of assembler code for function __GI__exit:
   0x00007ffff7fe9e90 <+0>:	endbr64 
   0x00007ffff7fe9e94 <+4>:	mov    esi,0xe7
   0x00007ffff7fe9e99 <+9>:	mov    edx,0x3c
   0x00007ffff7fe9e9e <+14>:	jmp    0x7ffff7fe9ead <__GI__exit+29>
   0x00007ffff7fe9ea0 <+16>:	mov    eax,edx
   0x00007ffff7fe9ea2 <+18>:	syscall 
   0x00007ffff7fe9ea4 <+20>:	cmp    rax,0xfffffffffffff000
   0x00007ffff7fe9eaa <+26>:	ja     0x7ffff7fe9ec8 <__GI__exit+56>
   0x00007ffff7fe9eac <+28>:	hlt    
   0x00007ffff7fe9ead <+29>:	mov    eax,esi
   0x00007ffff7fe9eaf <+31>:	syscall 
   0x00007ffff7fe9eb1 <+33>:	cmp    rax,0xfffffffffffff000
   0x00007ffff7fe9eb7 <+39>:	jbe    0x7ffff7fe9ea0 <__GI__exit+16>
   0x00007ffff7fe9eb9 <+41>:	neg    eax
   0x00007ffff7fe9ebb <+43>:	mov    DWORD PTR [rip+0x143df],eax        # 0x7ffff7ffe2a0 <rtld_errno>
   0x00007ffff7fe9ec1 <+49>:	jmp    0x7ffff7fe9ea0 <__GI__exit+16>
   0x00007ffff7fe9ec3 <+51>:	nop    DWORD PTR [rax+rax*1+0x0]
   0x00007ffff7fe9ec8 <+56>:	neg    eax
   0x00007ffff7fe9eca <+58>:	mov    DWORD PTR [rip+0x143d0],eax        # 0x7ffff7ffe2a0 <rtld_errno>
   0x00007ffff7fe9ed0 <+64>:	jmp    0x7ffff7fe9eac <__GI__exit+28>

 

 

이번 글에서는 프로그램의 시작, 종료 과정과 그와 관련된 취약점에 대해 알아보았다. 여기에서 설명한 시작, 종료 함수 외에도 많은 함수가 존재하는 것 같다. 

'Pwnable' 카테고리의 다른 글

MIPS Architecture Exploitation  (0) 2026.05.01
tcache_perthread_struct overwriting  (0) 2026.01.26
FSOP 정리  (0) 2025.11.08
heap exploit 정리  (0) 2025.11.05
side channel attack(with assembly)  (0) 2025.10.02