1. 실행 전 분석 - ELF
- 리눅스는 실행파일의 형식으로 ELF(Executable and Linkable Format)를 규정하고 있다.
- readelf -h [파일명]으로 확인할 수 있다.
$ readelf -h [파일명] //example: readelf -h dabi
- ELF 헤더 중 진입점(Entry Point, EP) 필드를 통해 시작 주소를 확인할 수 있다. 아래 예시에서는 0X400400임을 알 수 있다.
$ readelf -h dabi
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: 0x400400
Start of program headers: 64 (bytes into file)
Start of section headers: 6376 (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
- start 명령어로 프로그램 진입점의 주소를 확인해볼 수 있다.
2. GDB 분석
(1) 시작과 종료
• 시작 : gdb [프로그램명][core 파일명][PID]
• 종료 : q or ctrl + d
(2) 소스보기 ( list or l )
• list : main 함수 기점으로 소스 출력
• list 10 : 10행을 기준으로 출력
• list func : func함수의 소스를 출력 (c++ 의 클래스 멤버의 경우 클래스 이름도 입력 해야 함)
• list - : 출력된 행의 이전행을 출력
• list file.c:func : file의 func 함수 부분을 출력
• file.c:10 : file의 10행을 기준으로 출력
(3) 브레이크 포인트 ( break or b )
• break func : func 함수의 시작부분에 브레이크 포인트 설정
• break 10 : 10행에 브레이크포인트 설정
• break file.c:func : file.c 파일에 func함수에 브레이크 포인트 설정
• break file.c:10 : file.c 파일에 10행에 브레이크 포인트 설정
• break +2 : 현재 행에서 2개 행 이후 브레이크 포인트 설정
• break -2 : 현재 행에서 2개 행 이전 지점에 브레이크 포인트 설정
• break *0x8049000 : 특정 주소에 브레이크 포인트 설정
• break 10 if var ==0 : 10행에 브레이크포인트를 설정하는데 var 값이 0일 때 작동
• tb : break 와 같으나 1회용 브레이크 포인트임. 문법은 b 와 같음
• info break : 현재 브레이크 포인트 보기
• cl : 브레이크 포인트 지우기 ( 옵션은 b와 유사하다 )
• d : 모든 브레이크 포인트 지우기
(3) 진행 명령어
• run (r) : 프로그램 수행 ( ndk 환경에서는 지원되지 않는다. )
- run 명령어 사용 시 인자값을 주려면 $()와 함께 파이썬 코드를 입력하면 전달 가능
Example)
- 다음과 같은 코드를 컴파일 했다고 가정.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
char name[20];
if( argc < 2 ) {
printf("Give me the argv[2]!\n");
exit(0);
}
memset(name, 0, sizeof(name));
printf("argv[1] %s\n", argv[1]);
read(0, name, sizeof(name)-1);
printf("Name: %s\n", name);
return 0;
}
- 첫번째 인자값 설정
pwndbg> r $(python -c 'print "\xff"*100')
argv[1]
????????????????????????????????????????????????????????????????????????????????????????????????????
- 첫번째 인자값 설정 후 입력값도 설정
- 입력값 전달을 위해서는 '<<<' 문자를 사용
pwndbg> r $(python -c 'print "\xff"*100') <<< $(python -c 'print "dabi"')
argv[1] ????????????????????????????????????????????????????????????????????????????????????????????????????
Name: dabi
• kill (k) : 프로그램 수행 종료
• step (s): 현재 행 수행 후 정지, 함수 호출시 함수 안으로 들어감
• s 5 : step 다섯번 수행과 동일
• next (n) : 현재 행 수행 후 정지, 함수 호출시 함수 수행 다음 행으로 감
• n 5 : next 다섯번 수행과 동일
• continue (c) : 다음 브레이크 포인트까지 진행
• u : 현재 루프를 빠져나감
• finish : 현재 함수를 수행하고 빠져 나감
• return : 현재 함수를 수행하지 않고 빠져 나감
• return 123 : 위와 같으나 리턴값을 지정함
• si : 어셈블리 명령어 단위의 수행 ( 진행은 step 과 같음 )
• ni : 어셈블리 명령어 단위의 수행 ( 진행은 next 와 같음 )
(4) 와치 포인트 ( watch )
• watch 변수명 : 특정변수에 와치 포인트를 설정하고, 특정변수가 바뀔 때마다 브레이크가 걸리면서 이전/현재값을 출력한다.
(5) 변수출력 관련
• info locals : 현재 스택의 로컬변수모두 출력
• info variables : 전역변수 모두 출력 ( 스크롤 압박주의! )
• p [변수명] : 해당변수 value 출력 ( 포인터변수 입력시 주소값출력, *포인터변수명시 실제 value출력 )
• p $[레지스터명] : 레지스터 값출력 ( p $eax )
• p *[포인터]@[숫자] : struct/class 의 배열일 때 배열의 크기를 알림 ( p *pt@4 )
• p ‘[파일명]’::[변수명] : 변수명 중복시 특정 파일의 전역변수 출력
• p [함수명]::[변수명] : 변수명 중복 시 특정 함수의 static 변수명 출력 ( 변수명이 중복될 때 기본으로 local 변수가 출력 )
• p /[출력형식][변수명] : 출력형식에 맞추어 변수값 출력
- t : 2진수
- o : 8진수
- d : 부호없는 10진수
- u : 부호없는 10진수
- x : 16진수
- c : 최초 1바이트 값을 문자형으로 출력
- f : 부동소수점
- a : 가장가까운 심볼의 오프셋을 출력
- p (캐스팅)[변수명] : 변수를 캐스팅하여 출력 ( p (char *)ptr )
- p [포인터변수or배열]+[숫자] : 특정 주소 + 숫자 위치 출력 ( p (array[1]+4) )
- p [변수명] = [value] : 특정 변수의 값을 설정
• info registers : 레지스터 전체 출력
• info all-registers : MMX 포함 레지스터 전체출력
• info registers : 레지스터 전체 출력
• info all-registers : MMX 포함 레지스터 전체출력
• display [변수명] : 매번 p 치기 귀찮으니 특정변수 진행 중 계속 출력 ( p 와 동일한 방식으로 출력형식 지정가능 )
- disable display [번호] : 일시적으로 디스플레이 중단
- enable display [번호] : 중단했던 번호 다시 출력
- undisplay [번호] : 출력하던 display 변수 제거
(6) 스택 상태 검사
• info f [프레임 번호] : 스택 프레임 내용 출력
• info args : 함수 호출시 인자를 출력
• info locals : 함수의 지역변수를 출력
• info catch : 함수의 예외 핸들러를 출력
• bt : 전체 스택 프레임 출력 ( 콜스택 )
• frame [스택번호] : 스택번호의 스택 프레임으로 이동
• up : 상위 스택프레임으로 이동
• up [숫자] : 숫자만큼 상위 스택프레임으로 이동
• down : 하위 스택프레임으로 이동
• down [숫자] : 숫자만큼 하위 스택프레임으로 이동
(7) 메모리상태 검사
• x/[범위][출력형식][범위의단위] [메모리주소나 함수명]
• 범위 : 기본 4byte 단위
• 출력 형식
- t : 2진수
- o : 8진수
- d : 부호없는 10진수
- u : 부호없는 10진수
- x : 16진수
- c : 최초 1바이트 값을 문자형으로 출력
- f : 부동소수점
- a : 가장가까운 심볼의 오프셋을 출력
- s : 문자열로 출력
- i : 어셈블리 형식으로 출력
• 범위의 단위
- b : 1 byte 단위
- h : 2 byte 단위
- w : 4 byte 단위
- g : 8 byte 단위
• Example
- x/10i main : main 함수로 부터 40byte 를 어셈블리로 출력
- x/10 main : main 함수로 부터 40byte를 출력
- x/10b 0x8048200 : 주소로 부터 10byte를 출력
(8) 기타
• directory [경로] : 소스파일을 탐색하기 위해 경로에 directory 를 추가
• objectdir [경로] : 오브젝트 경로 등록
• disas [함수명] : 특정함수의 어셈블리 코드를 출력
• disas [주소] [주소] : 주소사이의 어셈블리 코드를 출력
• call [함수명(인자)] : 특정 함수를 인자값으로 호출함
• jump *[주소] : 주소로 강제적으로 분기
• jump [행번호] : 특정 행으로 강제 분기
• jump [ 함수명] : 특정 함수로 강제 분기
• info signals : signal 종류 출력
• signal [시그널명] : 디버깅중인 프로세스에 시그널 전달 ( signal SIGKILL )
• set {타입}[주소] = [값] : 특정 메모리에 값을 지정 ( set {int}0x8048300 = 100 )
• info 탭키 : info 로 확인 가능한 명령어 출력
• 환경 설정
- info set : 설정 가능한 내용 출력
- set prompt euclid : 프롬프트른 euclid 로 변경