[Dreamhack]gdb

최윤지·2024년 2월 25일

System Hacking

목록 보기
4/9

디버거(Debugger)

버그(bug): 실수로 발생한 프로그램의 결함

디버거(Debugger): 버그를 없애기 위해 사용하는 도구

* 디버거 사용 => 버그 발견이 쉬워짐 => 개발자들이 버그를 고치기 쉬워짐 & 해커들이 취약점을 발견하기 쉬워짐

gdb(GNU debugger)

: 리눅스의 대표적인 디버거

ELF(Executable and Linkable Format): 리눅스의 실행파일의 형식

진입점(Entry Point, EP)
=> 운영체제는 ELF를 실행할 때, 진입점의 값부터 프로그램을 실행

readelf -h (디렉토리명)을 사용하여 진입점 확인 가능

gdb (디렉토리명): 디버깅 시작

pwndbg

entry: 진입점부터 프로그램을 분석할 수 있게 해주는 gdb의 명령어

  • 현재 rip의 값 = 진입점의 주소

맥락(Context)

주요 메모리들의 상태를 프로그램이 실행되고 있는 맥락이라 부름

  • REGISTERS: 레지스터의 상태를 보여줌
  • DISASM: rip부터 여러 줄에 걸쳐 디스어셈블된 결과를 보여줌
  • STACK: rsp부터 여러 줄에 걸쳐 스택의 값들을 보여줌
  • BACKTRACE: 현재 rip에 도달할 때까지 어떤 함수들이 중첩되어 호출됐는지를 보여줌

실행

break: 특정 주소에 중단점(breakpoint)을 설정하는 기능
continue: 중단된 프로그램을 계속 실행시키는 기능

run: 단순히 실행시키는 기능

  • 중단점을 설정해놓지 않았다면 프로그램이 끝까지 멈추지 않고 실행됨

어셈블리 명령어를 한 줄씩 실행시키는 명령어
ni(next instruction): 서브루틴의 내부로 들어가지 않음

  • 프로그램을 분석하다가, 함수의 내부가 궁금하지 않을 때 사용

si(step into): 서브루틴의 내부로 들어감

  • 프로그램을 분석하다가, 함수의 내부까지 궁금할 때 사용

finish: 함수의 끝까지 한 번에 실행시키는 기능

main() 심볼이 존재할 때 유용한 명령어

start

  • main() 심볼이 존재할 시 main()에 중단점을 설정한 후 실행
  • main() 심볼이 존재하지 않을 시 진입점에 중단점을 설정한 후 실행

main: start 명령어와 동일

분석

examine
x: 가상 메모리에 존재하는 임의 주소의 값을 관찰할 수 있는 기능(gdb에서 기본적으로 제공)

  • 특정 주소에서 원하는 길이만큼의 데이터를 원하는 형싱으로 인코딩하여 볼 수 있음
    • x(hex)
    • g(giant, 8bytes)
      ex) rsp부터 80바이트를 8바이트씩 hex형식으로 출력
      pwndbg> x/10gx $rsp
    • i(instruction)
      ex) rip부터 5줄의 어셈블리 명령어 출력
      pwndbg> x/5i $rip
    • s(string)
      ex) 특정 주소의 문자열 출력
      pwndbg> x/s 0x400000
    • 등등

telescope
tele: 메모리가 참조하고 있는 주소를 재귀적으로 탐색하여 값을 보여주는 기능(pwndbg가 제공하는 강력한 메모리 덤프 기능)

vmmap: 가상 메모리의 레이아웃을 보여주는 기능

  • 어떤 파일이 매핑 된 영역일 경우, 해당 파일의 경로까지 보여줌
    • 파일 매핑: 어떤 파일을 메모리에 적재하는 것
    • 리눅스에서 ELF를 실행할 때,
      -> ELF의 코드와 여러 데이터를 가상 메모리에 매핑
      -> 해당 ELF에 링크된 공유 오브젝트(Shared Object, so)를 추가로 메모리에 매핑

disassembly

disassemble: gdb가 기본적으로 제공하는 디스어셈블 명령어

# 예시 (helloworld.c 디스어셈블)

- helloworld.c 작성
helloworld.c

- 디스어셈블
disassemble

* 어셈블리어 분석

0x0000000000001149 <+0>:	endbr64
0x000000000000114d <+4>:	push	rbp					# rbp를 스택 최상단에 쌓음
0x000000000000114e <+5>:	mov 	rbp,rsp				# rsp의 값을 rbp에 대입
0x0000000000001151 <+8>:	lea		rax,[rip±0xeac]		# [rip±0xeac]를 rax에 저장
0x0000000000001158 <+15>:	mov 	rdi,rax				# rax의 값을 rdi에 대입
0x000000000000115b <+18>: 	call 	0x1050 <puts@plt>	# 0x1050에 위치한 프로시져 호출
0x0000000000001160 <+23>: 	mov		eax,0x0				# 0x0의 값을 eax에 대입
0x0000000000001165 <+28>:	pop		rbp					# 스택 최상단 값을 rbp에 대입
0x0000000000001166 <+29>:	ret							# return address로 반환

u, nearpc, pdisass는 디스어셈블된 코드를 가독성 좋게 출력해주는 디스어셈블 명령어

python

*argv
run 명령어의 인자로 $()와 함께 파이썬 코드를 입력하면 값을 전달할 수 있음

*input
$()와 함께 파이썬 코드를 입력하면 값을 입력할 수 있음. 입력값으로 전달하기 위해서는 <<<를 사용

ex) pwndbg > r $(python3 -c "print('\xff' * 100)") <<< $(python3 -c "print('dreamhack')")

0개의 댓글