1. 설치 방법
https://github.com/pwndbg/pwndbg
여기에 들어가서
git clone https://github.com/pwndbg/pwndbg
cd pwndbg
./setup.sh
gdb
위 명령어를 그대로 치면 아래와 같은 화면이 나와야 한다. quit을 입력하면 pwndbg를 나갈 수 있다.
2. pwndbg 개요
리눅스는 실행 파일 형식으로 ELF (Executable and Linkable Format) 를 사용하는데,
ELF의 헤더에는 진입점 (Entry Point, EP) 이라는 필드의 값으로 해당 바이너리의 진입점의 위치가 저장되어있다.
왼쪽의 사진 처럼 readelf -h 를 입력하고 뒤에 바이너리 이름을 적으면 ELF 헤더를 볼 수 있다.
debugee라는 바이너리는 진입점이 0x401050 인 것을 알 수 있다.
그래서 pwndbg에서 entry를 입력하면 아까 헤더에서 봤던 진입점의 값과 동일한 주소를 얻을 수 있다.
3. pwndbg 화면 구성
pwndbg는 주요 메모리들의 상태를 Context (맥락) 이라고 부르는데,
- REGISTERS: 레지스터들의 상태 표시
- DISASM: rip부터 여러 줄에 걸쳐 디스어셈블된 결과 표시
- STACK: rsp부터 여러 줄에 걸쳐 스택의 값들을 표시
- BACKTRACE: 현재 rip에 도달할 때까지 어떤 함수들이 중첩되어 호출됐는지 표시
이렇게 4가지 화면으로 구성되어 있다.
4. breakpoint
pwndbg의 간단한 중단점 설정과 관련된 명령어들은 이런 것들이 있다.
- b: break
- c: continue
- r: run
- si: step into ; 서브루틴의 내부로 들어감
- ni: next instruction ; 서브루틴의 내부로 들어가지 않음
- i: info
- k: kill
- pd: pdisas
- finish: 함수의 끝까지 한번에 실행
- start: 중단점이 없다면 진입점을 중단점으로 설정하고 실행
5. disassemble
u, nearpc, pdisass 명령어를 사용하면 disassemble 된 코드를 볼 수 있다.
6. examine
디버거를 실행 중에 특정 주소에 저장된 데이터를 x 라는 명령어로 볼 수 있다.
사용하는 방법은
x/[원하는 길이][원하는 형식] [특정 주소]
예)
pwndbg> x/10gx $rsp
0x7fffffffc228: 0x00007ffff7a05b97 0x0000000000000001
0x7fffffffc238: 0x00007fffffffc308 0x0000000100008000
0x7fffffffc248: 0x00000000004004e7 0x0000000000000000
0x7fffffffc258: 0x71eb993d1f26e436 0x0000000000400400
0x7fffffffc268: 0x00007fffffffc300 0x0000000000000000
pwndbg> x/5i $rip
=> 0x4004e7 <main>: push rbp
0x4004e8 <main+1>: mov rbp,rsp
0x4004eb <main+4>: sub rsp,0x10
0x4004ef <main+8>: mov DWORD PTR [rbp-0xc],0x0
0x4004f6 <main+15>: mov DWORD PTR [rbp-0x8],0x1
pwndbg> x/s 0x400000
0x400000: "\177ELF\002\001\001"
telescope 명령어를 사용하면 특정 주소의 메모리 값들을 보여주는 것에서 그치지 않고, 메모리가 참조하고 있는 주소를 재귀적으로 탐색하여 값을 보여준다.
vmmap은 가상 메모리의 레이아웃을 보여준다. 매핑된 파일과 그 경로도 보여준다.
7. python으로 인자 전달
run 명령어의 인자로 $() 와 함께 파이썬 코드를 입력하면 값을 전달할 수 있다.
<<< 를 사용하면 입력값으로 전달 할 수 있다.