볞묞 바로가Ʞ
💠볎안·ì·šì•œì /🔞시슀템·ìšŽì˜ì²Žì œ

[dreamhack] Tool: gdb

by Jenny:! 2022. 7. 28.

1. 서론

디버거

컎퓚터곌학에서는싀수로 발생한 프로귞랚의 결핚을 ë²„ê·ž(bug)띌고 하는데, 읎믞 완성된 윔드에서 버귞륌 찟는 것은 얎렵습니닀. 귞래서 읎런 얎렀움을 핎소하고자 ë””버거(Debugger)띌는 도구가 개발되었습니닀.

디버거는 묞자 귞대로 버귞륌 없애Ʞ 위핎 사용하는 도구입니닀. 프로귞랚을 얎셈랔늬 윔드 닚위로 싀행하멎서, 싀행 결곌륌 사용자에게 볎여쀍니닀.

귞러나 읎러한 디버거의 횚용을 개발자만 얻는 것은 아닙니닀. 핎컀, 늬버슀 엔지니얎 등을 비롯하여 소프튞웚얎에서 버귞륌 찟고자 하는 몚두가 읎 도구륌 사용하여 버귞륌 횚윚적윌로 탐색할 수 있습니닀.

읎번에는 늬눅슀의 대표적읞 디버거 쀑 하나읞 gdb의 Ʞ능듀에 대핮 배우고, 싀습을 통핎 사용법을 익혀볎겠습니닀.

 

2. gdb & pwndbg

gdb

gdb(GNU debugger)는 늬눅슀의 대표적읞 디버거입니닀. 였픈 소슀로 개발되얎 묎료로 섀치할 수 있윌며, 였래된만큌 닀양한 플러귞읞듀읎 개발되얎 있습니닀. 우늬가 사용하는 Ubuntu 18.04에는 Ʞ볞적윌로 섀치되얎 있습니닀.

gdb의 플러귞읞 쀑에서 바읎너늬 분석 용도로 널늬 사용되는 플러귞읞듀은 닀음곌 같습니닀. 

 

GitHub - pwndbg/pwndbg: Exploit Development and Reverse Engineering with GDB Made Easy

Exploit Development and Reverse Engineering with GDB Made Easy - GitHub - pwndbg/pwndbg: Exploit Development and Reverse Engineering with GDB Made Easy

github.com

 

섀치륌 마친 후, 터믞널에 gdb륌 입력했을 때, 아래와 같은 싀행 결곌가 나였멎 섀치에 성공한 것입니닀.

$ gdb
GNU gdb (Ubuntu 8.1-0ubuntu3.2) 8.1.0.20180409-git
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later 
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
Find the GDB manual and other documentation resources online at:
For help, type "help".
Type "apropos word" to search for commands related to "word".
pwndbg: loaded 193 commands. Type pwndbg [filter] for a list.
pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
pwndbg>

 

싀습 예제

간닚한 윔드륌 작성하고, 읎륌 분석하며 gdb의 사용법을 익혀볎겠습니닀. 우선 아래의 윔드륌 작성하고 컎파음합니닀.

// Name: debugee.c
// Compile: gcc -o debugee debugee.c -no-pie
#include <stdio.h>
int main(void) {
  int sum = 0;
  int val1 = 1;
  int val2 = 2;
  sum = val1 + val2;
  printf("1 + 2 = %d\\n", sum);
  return 0;
}

 

ê·ž 닀음 gdb debugee로 디버깅을 시작합니닀.

$ gcc -o debugee debugee.c
$ gdb debugee
GNU gdb (Ubuntu 8.1-0ubuntu3.2) 8.1.0.20180409-git
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
pwndbg: loaded 193 commands. Type pwndbg [filter] for a list.
pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
Reading symbols from debugee...(no debugging symbols found)...done.
pwndbg>

 

 

start

늬눅슀는 싀행파음의 형식윌로 ELF(Executable and Linkable Format)륌 규정하고 있습니닀. ELF는 크게 í—€ë”와 여러 ì„¹ì…˜ë“€ë¡œ 구성되얎 있습니닀. 헀더에는 싀행에 필요한 여러 정볎가 적혀 있고, 섹션듀에는 컎파음된 Ʞ계얎 윔드, 프로귞랚 묞자엎을 비롯한 여러 데읎터가 포핚되얎 있습니닀.

ELF의 헀더 쀑에 ì§„입점(Entry Point, EP)읎띌는 필드가 있는데, 욎영첎제는 ELF륌 싀행할 때, 진입점의 값부터 프로귞랚을 싀행합니닀. readelf로 확읞핎볞 결곌, debugee의 진입점은 0x400400입니닀.

$ readelf -h debugee
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

 

 

gdb의 start ëª…령얎는 진입점부터 프로귞랚을 분석할 수 있게 핎죌는 gdb의 명령얎입니닀. DISASM영역의 화삎표(►)가 가늬킀는 죌소는 현재 rip의 값읞데, start명령얎륌 싀행하고 볎멎 0x400400을 가늬킀고 있습니닀. 읎는 앞서 삎펎볞 프로귞랚 진입점의 죌소와 음치합니닀.

pwndbg> start
Temporary breakpoint 1 at 0x400400
Temporary breakpoint 1, 0x0000000000400400 in _start ()
[쀑략]
───────────────────────────[ DISASM ]─────────────────────────────
 ► 0x400400 <_start>       xor    ebp, ebp
   0x400402 <_start+2>     mov    r9, rdx
   0x400405 <_start+5>     pop    rsi
   0x400406 <_start+6>     mov    rdx, rsp
   0x400409 <_start+9>     and    rsp, 0xfffffffffffffff0
   0x40040d <_start+13>    push   rax
   0x40040e <_start+14>    push   rsp
   0x40040f <_start+15>    mov    r8, __libc_csu_fini <0x4005a0>
   0x400416 <_start+22>    mov    rcx, __libc_csu_init <0x400530>
   0x40041d <_start+29>    mov    rdi, main <0x4004e7>
   0x400424 <_start+36>    call   qword ptr [rip + 0x200bc6] <__libc_start_main>
[쀑략]
pwndbg>

 

 

context

프로귞랚은 싀행되멎서 레지슀터륌 비롯한 여러 메몚늬에 접귌합니닀. 따띌서 디버거륌 읎용하여 프로귞랚의 싀행 곌정을 자섞히 ꎀ찰하렀멎 컎퓚터의 각종 메몚늬륌 한눈에 파악할 수 있는 것읎 좋습니닀. pwndbg는 죌요 메몚늬듀의 상태륌 프로귞랚읎 싀행되고 있는 ë§¥ëœ(Context)읎띌고 부륎며, 읎륌 가독성 있게 표현할 수 있는 읞터페읎슀륌 갖추고 있습니닀.

context는 크게 4개의 영역윌로 구분됩니닀.

  1. registers: 레지슀터의 상태륌 볎여쀍니닀.
  2. disasm: rip부터 여러 쀄에 걞쳐 디슀얎셈랔된 결곌륌 볎여쀍니닀.
  3. stack: rsp부터 여러 쀄에 걞쳐 슀택의 값듀을 볎여쀍니닀.
  4. backtrace: 현재 rip에 도달할 때까지 ì–Žë–€ 핚수듀읎 쀑첩되얎 혞출됐는지 볎여쀍니닀. ê³§ 예시륌 듀얎 더 자섞히 섀명하겠습니닀.

읎듀은 얎셈랔늬륌 싀행할 때마닀 갱신되얎 방ꞈ 싀행한 얎셈랔늬 명령얎가 메몚늬에 ì–Žë–€ 영향을 쀬는지 쉜게 파악할 수 있게 돕습니닀.

 

 

 

break & continue 

gdb륌 읎용하여 프로귞랚을 분석할 때, 음반적윌로 전첎 프로귞랚 쀑 아죌 음부분의 동작에만 ꎀ심읎 있습니닀. 읎 예제에서 main í•šìˆ˜ê°€ 분석의 대상읎띌고 가정하겠습니닀. 읎런 상황에서, 진입점부터 main í•šìˆ˜ê¹Œì§€ 윔드륌 한 쀄씩 싀행시쌜가며 main í•šìˆ˜ì— 도달핎알 한닀멎, 디버깅읎 횚윚적읎지 않습니닀.

귞래서 많은 디버거에는 break와 continue띌는 Ʞ능읎 있습니닀. break는 특정 죌소에 ì€‘닚점(breakpoint)을 섀정하는 Ʞ능읎고, continue는 쀑닚된 프로귞랚을 계속 싀행시킀는 Ʞ능입니닀. break로 원하는 핚수에 쀑닚점을 섀정하고, 프로귞랚을 계속 싀행하멎 핎당 핚수까지 멈추지 않고 싀행한 닀음 쀑닚됩니닀. 귞러멎 쀑닚된 지점부터 닀시 섞밀하게 분석할 수 있습니닀.

읎듀을 활용하여 현재 쀑닚된 start í•šìˆ˜ë¶€í„° main í•šìˆ˜ê¹Œì§€ 싀행시킀겠습니닀.

pwndbg> b *main
Breakpoint 2 at 0x4004e7
pwndbg> c
Continuing.
Breakpoint 2, 0x00000000004004e7 in main ()
[쀑략]
──────────────────────────[ DISASM ]─────────────────────────
 ► 0x4004e7 <main>       push   rbp <0x400530>
   0x4004e8 <main+1>     mov    rbp, rsp
   0x4004eb <main+4>     sub    rsp, 0x10
   0x4004ef <main+8>     mov    dword ptr [rbp - 0xc], 0
   0x4004f6 <main+15>    mov    dword ptr [rbp - 8], 1
   0x4004fd <main+22>    mov    dword ptr [rbp - 4], 2
   0x400504 <main+29>    mov    edx, dword ptr [rbp - 8]
   0x400507 <main+32>    mov    eax, dword ptr [rbp - 4]
   0x40050a <main+35>    add    eax, edx
   0x40050c <main+37>    mov    dword ptr [rbp - 0xc], eax
   0x40050f <main+40>    mov    eax, dword ptr [rbp - 0xc]
──────────────────────────[ STACK ]───────────────────────────
[생략]

 

 

run 

앞의 start가 진입점부터 프로귞랚을 분석할 수 있도록 자동윌로 쀑닚점을 섀정핎쀬닀멎, run은 닚순히 싀행만 시킵니닀. 따띌서 쀑닚점을 섀정핎놓지 않았닀멎 프로귞랚읎 끝까지 멈추지 않고 싀행됩니닀. 지ꞈ은 main í•šìˆ˜ì— 쀑닚점을 섀정핎놚Ʞ 때묞에 run명령얎륌 싀행핎도, main í•šìˆ˜ì—ì„œ 싀행읎 멈춥니닀.

pwndbg>r
Starting program: /home/dreamhack/debugee
Breakpoint 2, 0x00000000004004e7 in main ()
 
 
💡 gdb의 명령얎 축앜
gdb는 훌륭한 명령얎 축앜 Ʞ능을 제공합니닀. ì–Žë–€ 명령얎륌 특정할 수 있는 최소한의 묞자엎만 입력하멎 자동윌로 명령얎륌 ì°Ÿì•„ 싀행핎쀍니닀. 몇몇 대표적읞 명령얎듀(break, continue, run 등)은 특정할 수 없더띌도 우선윌로 싀행핎쀍니닀. 닀음은 자죌 사용되는 명령얎듀의 닚축킀 예입니닀.
  • b: break
  • c: continue
  • r: run
  • si: step into
  • ni: next instruction
  • i: info
  • k: kill
  • pd: pdisas

 

 

disassembly

gdb는 프로귞랚을 얎셈랔늬 윔드 닚위로 싀행하고, 결곌륌 볎여쀍니닀. 프로귞랚의 윔드는 Ʞ계얎로 읎룚얎젞 있윌므로, gdb는 Ʞ계얎륌 ë””슀얎셈랔(Disassemble)하는 Ʞ능을 Ʞ볞적윌로 탑재하고 있습니닀. 추가로, pwndbg에는 디슀얎셈랔된 결곌륌 가독성 좋게 출력핎죌는 Ʞ능읎 있습니닀. 각각을 삎펎볎겠습니닀.

disassemble은 gdb가 Ʞ볞적윌로 제공하는 디슀얎셈랔 명령얎입니닀. 아래와 같읎 핚수 읎늄을 읞자로 전달하멎 핎당 핚수가 반환될 때 까지 전부 디슀얎셈랔하여 볎여쀍니닀.

 

 

gdb disassembly

 

 

u, nearpc, pdisassemble는 pwndbg에서 제공하는 디슀얎셈랔 명령얎입니닀. 디슀얎셈랔된 윔드륌 가독성 좋게 출력핎쀍니닀.

 

pwndbg disassembly

 

 

navigate

ꎀ찰하고자 하는 핚수의 쀑닚점에 도달했윌멎, ê·ž 지점부터는 명령얎륌 한 쀄씩 자섞히 분석핎알 합니닀. 읎때 사용하는 명령얎로 ni와 si가 있습니닀.

ni와 si는 몚두 얎셈랔늬 명령얎륌 한 쀄 싀행한닀는 공통점읎 있습니닀. 귞러나 만앜 call 등을 통핎 서람룚틎을 혞출하는 겜우 ni는 서람룚틎의 낎부로 듀얎가지 않지만, si는 서람룚틎의 낎부로 듀얎간닀는 찚읎점읎 있습니닀. 읎륌 확읞하Ʞ 위핎 음닚 main í•šìˆ˜ì—ì„œ printf í•šìˆ˜ë¥Œ 혞출하는 지점까지 싀행하겠습니닀.

pwndbg> b *main+57
Breakpoint 2 at 0x400520
pwndbg> c
Continuing.
Breakpoint 3, 0x0000000000400520 in main ()
...
──────────────────────────────────[ DISASM ]───────────────────────────────────
   0x40050c <main+37>            mov    dword ptr [rbp - 0xc], eax
   0x40050f <main+40>            mov    eax, dword ptr [rbp - 0xc]
   0x400512 <main+43>            mov    esi, eax
   0x400514 <main+45>            lea    rdi, [rip + 0x99]
   0x40051b <main+52>            mov    eax, 0
 ► 0x400520 <main+57>            call   printf@plt <printf@plt>
        format: 0x4005b4 ◂— '1 + 2 = %d\\n'
        vararg: 0x3
   0x400525 <main+62>            mov    eax, 0
   0x40052a <main+67>            leave
   0x40052b <main+68>            ret
   0x40052c                      nop    dword ptr [rax]
   0x400530 <__libc_csu_init>    push   r15
...

 

next instruction

ni륌 입력하멎, 아래와 같읎 printf í•šìˆ˜ 바로 닀음윌로 rip가 읎동한 것을 확읞할 수 있습니닀.

pwndbg> ni
0x0000000000400525 in main ()
...
──────────────────────────────────[ DISASM ]───────────────────────────────────
   0x40050f       <main+40>                  mov    eax, dword ptr [rbp - 0xc]
   0x400512       <main+43>                  mov    esi, eax
   0x400514       <main+45>                  lea    rdi, [rip + 0x99]
   0x40051b       <main+52>                  mov    eax, 0
   0x400520       <main+57>                  call   printf@plt <printf@plt>
 ► 0x400525       <main+62>                  mov    eax, 0
   0x40052a       <main+67>                  leave
   0x40052b       <main+68>                  ret
    ↓
   0x7ffff7a05b97 <__libc_start_main+231>    mov    edi, eax
   0x7ffff7a05b99 <__libc_start_main+233>    call   exit <exit>
   0x7ffff7a05b9e <__libc_start_main+238>    mov    rax, qword ptr [rip + 0x3ced23] <0x7ffff7dd48c8>
...
 
 
 
💡 ì™œ printf륌 싀행했는데 아묎 묞자엎도 출력되지 않나요?
printf가 출력하고자 하는 묞자엎은 stdout의 버퍌에서 잠시 대Ʞ한 ë’€ 출력됩니닀. 여Ʞ서 버퍌는 '데읎터가 목적지로 읎동하Ʞ 전에 잠시 저장되는 장소'띌는 의믞입니닀. stdout버퍌는 특정 조걎읎 만족됐을 때만 데읎터륌 목적지로 읎동시킀는데, ê·ž 조걎은 닀음곌 같습니닀.
  1. 프로귞랚읎 종료될 때
  2. 버퍌가 가득 찌을 때
  3. fflush와 같은 핚수로 버퍌륌 비우도록 명시했을 때
  4. 개행묞자가 버퍌에 듀얎왔을 때
예시는 위 조걎을 하나도 만족하지 않Ʞ 때묞에, 프로귞랚읎 종료될 때까지 묞자엎을 출력하지 않습니닀.

 

step into

printf í•šìˆ˜ë¥Œ 혞출하는 지점까지 닀시 프로귞랚을 싀행시킚 ë’€, si륌 입력하멎 아래와 같읎 printf í•šìˆ˜ 낎부로 rip가 읎동한 것을 확읞할 수 있습니닀. 프로귞랚을 분석하닀가, ì–Žë–€ 핚수의 낎부까지 궁ꞈ할 때는 si륌, ê·žë ‡ì§€ 않을 때는 ni륌 사용합니닀. 여Ʞ서 잠시 context하닚의 Backtrace륌 볎멎, main í•šìˆ˜ì—ì„œ printf륌 혞출했윌므로 main í•šìˆ˜ 위에 printf í•šìˆ˜ê°€ 쌓읞 것을 볌 수 있습니닀.

pwndbg> si
0x00000000004003f0 in printf@plt ()
...
──────────────────────────────────[ DISASM ]───────────────────────────────────
 ► 0x4003f0       <printf@plt>                       jmp    qword ptr [rip + 0x200c22] <0x601018>
   0x4003f6       <printf@plt+6>                     push   0
   0x4003fb       <printf@plt+11>                    jmp    0x4003e0 <0x4003e0>
    ↓
   0x4003e0                                          push   qword ptr [rip + 0x200c22] <0x601008>
   0x4003e6                                          jmp    qword ptr [rip + 0x200c24] <_dl_runtime_resolve_xsavec>
    ↓
   0x7ffff7dec7a0 <_dl_runtime_resolve_xsavec>       push   rbx
   0x7ffff7dec7a1 <_dl_runtime_resolve_xsavec+1>     mov    rbx, rsp
   0x7ffff7dec7a4 <_dl_runtime_resolve_xsavec+4>     and    rsp, 0xffffffffffffffc0
   0x7ffff7dec7a8 <_dl_runtime_resolve_xsavec+8>     sub    rsp, qword ptr [rip + 0x210059] <0x7ffff7ffc808>
   0x7ffff7dec7af <_dl_runtime_resolve_xsavec+15>    mov    qword ptr [rsp], rax
   0x7ffff7dec7b3 <_dl_runtime_resolve_xsavec+19>    mov    qword ptr [rsp + 8], rcx
...
──────────────────────────────────[ BACKTRACE ]───────────────────────────────────
 ► f 0           4003f0 printf@plt
   f 1           400525 main+62
   f 2     7ffff7a05b97 __libc_start_main+231
────────────────────────────────────────────────────────────────────────────────
pwndbg>

 

 

finish

step into로 핚수 낎부에 듀얎가서 필요한 부분을 몚두 분석했는데, 핚수의 규몚가 컀서 ni로는 원래 싀행 흐늄윌로 돌아가Ʞ 얎렀욞 수 있습니닀. 읎럎 때는 finish띌는 명령얎륌 사용하여 핚수의 끝까지 한 번에 싀행할 수 있습니닀.

pwndbg> finish
Run till exit from #0  0x00000000004003f0 in printf@plt ()
0x0000000000400525 in main ()
...
───────────────────────────────────[ DISASM ]───────────────────────────────────
   0x400520       <main+57>                  call   printf@plt <printf@plt>
 ► 0x400525       <main+62>                  mov    eax, 0
   0x40052a       <main+67>                  leave
   0x40052b       <main+68>                  ret
    ↓
   0x7ffff7a05b97 <__libc_start_main+231>    mov    edi, eax
   0x7ffff7a05b99 <__libc_start_main+233>    call   exit <exit>
   0x7ffff7a05b9e <__libc_start_main+238>    mov    rax, qword ptr [rip + 0x3ced23] <0x7ffff7dd48c8>
   0x7ffff7a05ba5 <__libc_start_main+245>    ror    rax, 0x11
   0x7ffff7a05ba9 <__libc_start_main+249>    xor    rax, qword ptr fs:[0x30]
   0x7ffff7a05bb2 <__libc_start_main+258>    call   rax
   0x7ffff7a05bb4 <__libc_start_main+260>    mov    rax, qword ptr [rip + 0x3cecfd] <0x7ffff7dd48b8>
───────────────────────────────────[ STACK ]────────────────────────────────────
[생략]
pwndbg> finishRun till exit from #0  0x00000000004003f0 in printf@plt ()0x0000000000400525 in main ()...───────────────────────────────────[ DISASM ]───────────────────────────────────   0x400520       <main+57>                  call   printf@plt <printf@plt> ► 0x400525       <main+62>                  mov    eax, 0   0x40052a       <main+67>                  leave   0x40052b       <main+68>                  ret    ↓   0x7ffff7a05b97 <__libc_start_main+231>    mov    edi, eax   0x7ffff7a05b99 <__libc_start_main+233>    call   exit <exit>   0x7ffff7a05b9e <__libc_start_main+238>    mov    rax, qword ptr [rip + 0x3ced23] <0x7ffff7dd48c8>   0x7ffff7a05ba5 <__libc_start_main+245>    ror    rax, 0x11   0x7ffff7a05ba9 <__libc_start_main+249>    xor    rax, qword ptr fs:[0x30]   0x7ffff7a05bb2 <__libc_start_main+258>    call   rax   0x7ffff7a05bb4 <__libc_start_main+260>    mov    rax, qword ptr [rip + 0x3cecfd] <0x7ffff7dd48b8>───────────────────────────────────[ STACK ]────────────────────────────────────[생략]

 

 

examine

프로귞랚을 분석하닀 볎멎 가상 메몚늬에 졎재하는 임의 죌소의 값을 ꎀ찰핎알할 때가 있습니닀. 읎륌 위핎 gdb에서는 Ʞ볞적윌로 x띌는 명령얎륌 제공합니닀. x륌 읎용하멎 íŠ¹ì • 죌소에서 ì›í•˜ëŠ” Ꞟ읎만큌의 데읎터륌 ì›í•˜ëŠ” 형식윌로 읞윔딩하여 볌수 있습니닀.

 

Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal), t(binary), f(float), a(address), i(instruction), c(char), s(string) and z(hex, zero padded on the left). Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes).

아래는 예시입니닀.

 

 

1. rsp부터 80바읎튞륌 8바읎튞씩 hex형식윌로 출력

pwndbg> x/10gx $rsp
0x7fffffffc228: 0x00007ffff7a05b97      0x0000000000000001
0x7fffffffc238: 0x00007fffffffc308      0x0000000100008000
0x7fffffffc248: 0x00000000004004e7      0x0000000000000000
0x7fffffffc258: 0x71eb993d1f26e436      0x0000000000400400
0x7fffffffc268: 0x00007fffffffc300      0x0000000000000000

 

2. rip부터 5쀄의 얎셈랔늬 명령얎 출력

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

 

3. íŠ¹ì • 죌소의 묞자엎 출력

pwndbg> x/s 0x400000
0x400000:       "\177ELF\002\001\001"

 

gdb / python argv

run 명령얎의 읞자로 $()와 핚께 파읎썬 윔드륌 입력하멎 값을 전달할 수 있습니닀. 닀음은 파읎썬에서 print í•šìˆ˜ë¥Œ 통핎 출력한 값을 run 명령얎의 읞자로 전달하는 명령얎입니닀.

pwndbg> tele
00:0000│ rsp  0x7fffffffc228 —▾ 0x7ffff7a05b97 (__libc_start_main+231) ◂— mov    edi, eax
01:0008│      0x7fffffffc230 ◂— 0x1
02:0010│      0x7fffffffc238 —▾ 0x7fffffffc308 —▾ 0x7fffffffc557 ◂— '/home/dreamhack/debugee'
03:0018│      0x7fffffffc240 ◂— 0x100008000
04:0020│      0x7fffffffc248 —▾ 0x4004e7 (main) ◂— push   rbp
05:0028│      0x7fffffffc250 ◂— 0x0
06:0030│      0x7fffffffc258 ◂— 0x71eb993d1f26e436
07:0038│      0x7fffffffc260 —▾ 0x400400 (_start) ◂— xor    ebp, ebp

 

 

gdb / python input

읎전곌 같읎 $()와 핚께 파읎썬 윔드륌 입력하멎 값을 입력할 수 있습니닀. 입력값윌로 전달하Ʞ 위핎서는 '<<<' 묞자륌 사용합니닀. 닀음은 앞서 배욎 argv[1]에 임의의 값을 전달하고, 값을 입력하는 명령얎입니닀.

pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
          0x400000           0x401000 r-xp     1000 0      /home/dreamhack/debugee
          0x600000           0x601000 r--p     1000 0      /home/dreamhack/debugee
          0x601000           0x602000 rw-p     1000 1000   /home/dreamhack/debugee
    0x7ffff79e4000     0x7ffff7bcb000 r-xp   1e7000 0      /lib/x86_64-linux-gnu/libc-2.27.so
    0x7ffff7bcb000     0x7ffff7dcb000 ---p   200000 1e7000 /lib/x86_64-linux-gnu/libc-2.27.so
    0x7ffff7dcb000     0x7ffff7dcf000 r--p     4000 1e7000 /lib/x86_64-linux-gnu/libc-2.27.so
    0x7ffff7dcf000     0x7ffff7dd1000 rw-p     2000 1eb000 /lib/x86_64-linux-gnu/libc-2.27.so
    0x7ffff7dd1000     0x7ffff7dd5000 rw-p     4000 0
    0x7ffff7dd5000     0x7ffff7dfc000 r-xp    27000 0      /lib/x86_64-linux-gnu/ld-2.27.so
    0x7ffff7dd5000     0x7ffff7dfc000 rwxp    27000 0      <explored>
    0x7ffff7fe3000     0x7ffff7fe5000 rw-p     2000 0
    0x7ffff7ff7000     0x7ffff7ffa000 r--p     3000 0      [vvar]
    0x7ffff7ffa000     0x7ffff7ffc000 r-xp     2000 0      [vdso]
    0x7ffff7ffc000     0x7ffff7ffd000 r--p     1000 27000  /lib/x86_64-linux-gnu/ld-2.27.so
    0x7ffff7ffd000     0x7ffff7ffe000 rw-p     1000 28000  /lib/x86_64-linux-gnu/ld-2.27.so
    0x7ffff7ffe000     0x7ffff7fff000 rw-p     1000 0
    0x7ffffffdc000     0x7ffffffff000 rw-p    23000 0      [stack]
pwndbg>

 

 

💡 파음 맀핑읎란?

ì–Žë–€ 파음을 메몚늬에 적재하는 것을 파음 맀핑읎띌고 합니닀. (위 메몚늬 레읎아웃에서 /home/dreamhack/debugee와 /lib/x86_64-linux-gnu/libc-2.27.so, /lib/x86_64-linux-gnu/ld-2.27.so가 맀핑된 파음듀입니닀.)

늬눅슀에서는 ELF륌 싀행할 때, 뚌저 ELF의 윔드와 여러 데읎터륌 가상 메몚늬에 맀핑하고, 핎당 ELF에 링크된 ê³µìœ  였람젝튞(Shared Object, so)륌 추가로 메몚늬에 맀핑합니닀. 공유 였람젝튞는 윈도우의 DLL곌 대응되는 개념윌로, 자죌 사용되는 핚수듀을 믞늬 컎파음핎둔 것입니닀. C얞얎의 printf, scanf 등읎 늬눅슀에서는 libc(library C)에 구현되얎 있습니닀. 공유 였람젝튞에 읎믞 구현된 핚수륌 혞출할 때는 맀핑된 메몚늬에 졎재하는 핚수륌 대신 혞출합니닀.

 

 

gdb / python

gdb륌 통핎 디버깅할 때 직접 입력할 수 없을 때가 있습니닀. 예륌 듀얎, 숫자와 알파벳읎 아닌 값을 입력하는 상황입니닀. 읎러한 값은 읎용자가 직접 입력할 수 없는 값읎Ʞ 때묞에 파읎썬윌로 입력값을 생성하고, 읎륌 사용핎알 합니닀. 파읎썬을 읎용하는 방법을 삎펎볎Ʞ에 앞서 아래 윔드륌 작성하고 컎파음합니닀.

윔드륌 삎펎볎멎, 프로귞랚의 읞자로 전달된 값곌 읎용자로부터 입력받은 값을 출력하는 예제입니닀.

// Name: debugee2.c
// Compile: gcc -o debugee2 debugee2.c -no-pie
#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;
}

 

 

ê·ž ë’€, gdb debugee2로 디버깅을 시작합니닀.

$ gcc -o debugee2 debugee2.c
$ gdb debugee2
GNU gdb (Ubuntu 8.1-0ubuntu3.2) 8.1.0.20180409-git
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
pwndbg: loaded 193 commands. Type pwndbg [filter] for a list.
pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
Reading symbols from debugee...(no debugging symbols found)...done.
pwndbg>

 

 

gdb / python argv

run 명령얎의 읞자로 $()와 핚께 파읎썬 윔드륌 입력하멎 값을 전달할 수 있습니닀. 닀음은 파읎썬에서 print í•šìˆ˜ë¥Œ 통핎 출력한 값을 run 명령얎의 읞자로 전달하는 명령얎입니닀.

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

 

 

 

gdb / python input

읎전곌 같읎 $()와 핚께 파읎썬 윔드륌 입력하멎 값을 입력할 수 있습니닀. 입력값윌로 전달하Ʞ 위핎서는 '<<<' 묞자륌 사용합니닀. 닀음은 앞서 배욎 argv[1]에 임의의 값을 전달하고, 값을 입력하는 명령얎입니닀.

r $(python -c 'print "\xff"*100') <<< $(python -c 'print "dreamhack"')
Starting program: /home/s0ngsari/a $(python -c 'print "\xff"*100') <<< $(python -c 'print "dreamhack"')
argv[1] ????????????????????????????????????????????????????????????????????????????????????????????????????
Name: dreamhack

 

 

3. 요앜

명령얎

  • start: 진입점에 쀑닚점을 섀정하고, 싀행
  • break(b): 쀑닚점 섀정
  • continue(c): 계속 싀행
  • disassemble: 디슀얎셈랔 결곌 출력
  • u, nearpc, pd: 디슀얎셈랔 결곌 가독성 좋게 출력
  • x: 메몚늬 조회
  • run(r): 프로귞랚 처음부터 싀행
  • context: 레지슀터, 윔드, 슀택, 백튞레읎슀의 상태 출력
  • nexti(ni): 명령얎 싀행, 핚수 낎부로는 듀얎가지 않음
  • stepi(si): 명령얎 싀행, 핚수 낎부로 듀얎감
  • telescope(tele): 메몚늬 조회, 메몚늬값읎 포읞터음 겜우 재귀적윌로 따띌가며 몚든 메몚늬값 출력
  • vmmap: 메몚늬 레읎아웃 출력