[System Hacking][DreamHack][Stage3] Tool: gdb

marceline·2023년 3월 31일
0

[System Hacking]

목록 보기
11/17
post-thumbnail

Introduce

debugger

bug

실수로 발생한 프로그램의 결함

gdb

Linux 의 대표적인 debugger 중 하나

gdb & pwndbg 설치하기

pwndbg
위의 링크를 클릭하고 README 파일에 나와있는 내용대로 따라한다

DreaHack - SystemHacking 커리큘럼에서는 pwndbg 를 기준으로 설명할 것이므로, pwndbg 만 설치해야한다.

추가로 참고 하였던 글

$ git clone https://github.com/pwndbg/pwndbg
$ cd pwndbg
$ ./setup.sh


처음에는 이런 오류가 나왔엇는데 잘 이유를 알 수 없었다
그래서 다시 시도 해보니



다음 사진과같이 성공적으로 설치가 되었다.

라고 생각했다...

실습예제

vim

gdb debugee 로 디버깅하기

// Name: debugee.c
// compile: gcc -o debugee debugee.c -no-pie

Start !

ELF (Executable and Linkable Format)

ELF 는 실행파일이다

Unix 계열 운영체제의 실행, 오브젝트 파일, 공유 라이브러리, 또는 코어덤프를 할 수 있게 하는 바이너리 파일이다

EP (Entry Point); 진입점

ELF 의 헤더 필드 중 하나
운영체제가 ELF 를 실행 할 때, 진입점의 값부터 프로그램을 실행한다.

readelf


Entry Point adress: 0x640 주목!!

start

gdb 의 start 명령어는 진입점부터 프로그램을 분석할 수 있게 해주는 gdb 의 명령어
|> DISASM 영역의 화살표가 가리키는 주소는 현재 rip 의 값이다.

start 명령어 실행시 명령을 찾을수 없다고 떳다. 그래서 구글링을 해보니,
애초에 pwndbg 를 잘못 설치했을 가능성이 높은 것 같았다...

어디서 부터 잘못되었는지 모르겠어서 리눅스를 재설치를 하기로 했다...

빠르게 재설치

기존의 학과 리눅스 수업에 사용하던 "myUbuntu" 리눅스와 시스템해킹 공부를 위해 사용하는 리눅스를 분리하는게 좋을 것 같다고도 생각이 들어서 "SystemHacking" 이라는 새로운 환경을 구축하였다.

ssh 설치 및 설정

$ sudo apt update
$ sudo apt install openssh-server

ubuntu desktop

$ sudo apt update
$ sudo apt install tasksel
$ sudo tasksel install ubuntu-desktop

reboot

$ sudo reboot

완료

(재시도) start!!

debugee 의 진입점 (Entry Point adress) == 현재 rip 값


앞서 readelf 로 확인해본 Entry Point adress 와 start 명령어로 살펴본, DISASM 영역의 화살표가 가리키는 주소 (즉, rip 값) 이 일치한다.

context; 맥락

pwndbg == Context 이다

-> 디버거를 이용하여 프로그램의 실행과정을 자세히 관찰하려면 컴퓨터의 각종 메모리를 한눈에 파악 할 수있어야함
-> 따라서 pwndbg (Context) 는 가독성있게 표현 할 수 있는 인터페이스를 갖추고있다.

< Context 의 4 영역>
1. register: 레지스터의 상태
2. disasm: rip 부터 여러 줄에 걸쳐 디스어셈블 된 결과
3. stack: rsp 부터 여러 줄에 걸쳐 스택의 값들을 보여준다
4. gacktrace: 현재 rip 에 도달할 때까지 어떤 함수들이 중첩되어 호출 됐는지 보여준다
-> 이들은 어셈블리를 실행할 때마다 갱신되어 방금 실행한 어셈블리 명령어가 메모리에 어떤 영향을 줬는지 쉽게 파악 할 수 있게 돕는다

break & continue

break

특정 주소에 Break Point (중단점) 을 설정하는 기능
원하는 함수에 중단점 설정
중단된 지점부터 다시 세밀하게 분석 가능하다

continue

중단된 프로그램을 계속 실행 시키는 기능

실습

run

start 는 진입점부터 프로그램을 분석 할 수 있도록 자동으로 중단점 설정
run 은 단순 실행
중단점 설정안해놓으면 프로그램이 끝까지 실행
(지금은 위에서 "b* main" 으로 설정해놓음)

gdb 명령어 축약

  • b: break
  • c: continue
  • r: run
  • si: step into
  • ni: next instruction
  • i: info
  • k: kill
  • pd: pdisas

disassembly

gdb 는 프로그램을 어셈블리 코드 단위로 실행하고 결과를 보여준다.

따라서 gdb 는 기계어를 Disassemble (디스어셈블) 하는 기능 탑재

pwndbg 는 disassemble 된 결과를 가독성 좋게 출력해주는 기능

disassemble

pwndbg> disassemble main

u

pwndbg> u

nearpc

pwndbg> nearpc

명령어를 한줄씩 자세히 분석한다
어셈블리어 명령어를 한줄씩 실행
call 등을 통해 한줄 서브루틴을 호출하는 경우

ni

서브루틴 내부로 들어가지 않는다

si

서브루틴 내부로 들어간다

main 에서 printf 를 호출하는 문장의 navigate

pwndbg> b* main+57

pwndbg> ni

pwndbg> ni 시 오류 발생

pwndbg> b* [함수이름] + [상수] = 해당영역에 breakPoint 를 설정한다
참고 블로그

따라서 +[상수] 의 57이 오류를 일으켰을것이라는 생각이 들었다.
그러나 disassemble main 에서 main 함수의 printf 문을 가리키는 상수가 56 이므로 +57 이 맞다는 결과를 얻었다.

오류수정

다음 사진과 같이 'The Program is not being run ' 라는 error 메시지가 출력이 된다.
구글링 결과
'The Program is not being run' error

실행 또는 시작 명령을 사용하여 프로그램을 재시작 하면 된다고 한다.

따라서,

$ gdb debugee
pwndbg> start
pwndbg> b* main+57
pwndbg> ni


즉, 다시 start 명령어를 쳐주니 정상적으로 실행이 되었다!

ni 명령어 실행결과

si 명령어 실행결과

finish 명령어 실행결과

examin

프로그램을 분석하다 보면 가상 메모리에 존재하는 임의 주소의 값을 관찰해야할 때가 있는데, 이를 위해서 gdb에서 기본적으로 x라는 명령어를 제공합니다. x를 이용하면 특정 주소에서 원하는 길이만큼의 데이터를 원하는 형식으로 인코딩하여 볼수 있다.

<예시>

1. rsp부터 80바이트를 8바이트씩 hex형식으로 출력

2. rip부터 5줄의 어셈블리 명령어 출력

3. 특정 주소의 문자열 출력

telescope

telescope 은 pwndbg 가 제공하는 메모리 덤프기능이다.
특정 주소의 메모리 값들을 보여주는걸 넘어서서 메모리가 참조하고 있는 주소를 재귀적으로 탐색하여 값을 보여준다

tele 명령어 실행결과

vmmap

vmmap 은 가상메모리의 LayOut 을 보여준다.
mapping 된 파일 영역은 해당 파일의 경로까지 보여준다.

파일 mapping

어떤 파일을 메모리에 적재하는 것

위 메모리 레이아웃에서 매핑된 파일은 3가지다
1. /home/dreamhack/debugee
2. /lib/x86_64-linux-gnu/libc-2.27.so,
3. /lib/x86_64-linux-gnu/ld-2.27.so
리눅스에서 ELF 를 실행 할때, 먼저 ELF 의 코드와 여러 데이터를 가상 메모리에 매핑하고, 해당 ELF 에 링크된 공유 오브젝트 (Shared Object, so) 를 추가로 메모리에 매핑한다.
공유 오브젝트(so) 는 윈도우의 DLL 과 대응되는 개념이다.
(자주 사용되는 함수들을 미리 컴파일 해 둔것)

C 언어의 printf, scanf 가 리눅스에서는 libc(library C) 에 구현되어있다.

vmmap 명령어 실행결과

gdb/ python

숫자 또는 알파벳이 아닌 입력값은 gdb 를 통해 입력 할 수 없기 때문에 파이썬으로 입력값을 생성하고, 이를 사용하여야 한다.

gdb/ python argv

run 의 인자 $() 와 함께 파이썬 코드를 입력하면 값을 전달 할 수 있다.

pwndbg> r $(python -c 'print "\xff"*100')
starting program: /home/s0ngsari/a $(python -c 'print "\xff"*100')
argv[1] ?????????????????????????????????????????????

입력값으로 전달하기 위한 '<<<' 문자 사용

argv[1] 에 임의의 값을 전달하고, 값을 입력하는 명령어

명령어 요약

  • start: 진입점에 중단점을 설정하고, 실행
  • break(b) : 중단점 설정
  • continue(c): 계속 실행
  • disassemble: 디스어셈블 결과 출력
  • u, nearpc, pd: 디스어셈블 결과 가독성 좋게 출력
  • x: 메모리 조회
  • run(r): 프로그램 처음부터 실행
  • context: 레지스터, 코드, 스택, 백트레이스의 상태 출력
    -nexti(ni): 명령어 실행, 함수 내부로는 들어가지 않음
  • step(si): 명령어 실행, 함수 내부로 들어감
  • telescope(tele): 메모리 조회, 메모리 값이 포인터 일 경우 재귀적으로 따라가며 모든 메모리 값 출력
  • vmmap: 메모리 레이아웃 출력

0개의 댓글