본문 바로가기
Security_/Reversing

[Reversing] Radare2 설치 및 사용 방법 총 정리 [예제 포함]

by 낭람_ 2021. 8. 5.
반응형

 

더보기

목차 [궁금한게 있다면 Ctrl+F로 검색하면 빠르다.]

Radare2?
Radare2설치
바이너리 정보 확인
Radare2 실행
바이너리 분석을 위한 명령어
바이너리 내의 함수 목록 출력
바이너리 내의 함수 이름 변경
함수의 디스어셈블리 출력
탐색 위치 변경
바이너리 그래프 모드 출력
Hexdump 값 출력하기
Flagspaces확인
데이터/코드 참조 찾기
문자열 검색하기
디버그 모드 Radare2 살향
디버깅 시작
설정된 BreakPoint 리스트 확인
BreakPoint 설정
BreakPoint 해제
레지스터 상태 출력
변수의 상태 확인하기
다시 시작 (올리디버거의 Ctrl+f2)
프로그램 종료 확인
바이너리 패치 모드 Radare2 실행
Hex 값 변경하기
명령어 변경하기
rax2
radiff2

 

Radare2?

Unix 환경에서 사용할 수 있는 리버싱 툴이다. (윈도우도 있다.)

[공식홈페이지] https://rada.re/r/

 

radare

Radare is a portable reversing framework that can… Disassemble (and assemble for) many different architectures Debug with local native and remote debuggers (gdb, rap, webui, r2pipe, winedbg, windbg) Run on Linux, *BSD, Windows, OSX, Android, iOS, Solaris

rada.re

Radare is a portable reversing framework that can…

  • Disassemble (and assemble for) many different architectures
  • Debug with local native and remote debuggers (gdb, rap, webui, r2pipe, winedbg, windbg)
  • Run on Linux, *BSD, Windows, OSX, Android, iOS, Solaris and Haiku
  • Perform forensics on filesystems and data carving
  • Be scripted in Python, Javascript, Go and more
  • Support collaborative analysis using the embedded webserver
  • Visualize data structures of several file types
  • Patch programs to uncover new features or fix vulnerabilities
  • Use powerful analysis capabilities to speed up reversing
  • Aid in software exploitation

 

 

Radare2 설치

sudo apt update
sudo apt install radare2

 

 

예제는 Reversing.krEasy_ELF를 사용했다.

 

Reversing.Kr

This site tests your ability to Cracking & Reverse Code Engineering. Now Challenge a problem for each environment. (Windows, Linux, .Net, Flash, Java, Python, Mobile..) Admin E-Mail: gogil@reversing.kr

reversing.kr

반응형

 

 

바이너리 정보 확인

$ rabin2 -I Easy_ELF

 

arch     x86
baddr    0x8048000
binsz    4398
bintype  elf
bits     32
canary   false
class    ELF32
compiler GCC: (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1
crypto   false
endian   little
havecode true
intrp    /lib/ld-linux.so.2
laddr    0x0
lang     c
linenum  false
lsyms    false
machine  Intel 80386
maxopsz  16
minopsz  1
nx       true
os       linux
pcalign  0
pic      false
relocs   false
relro    partial
rpath    NONE
sanitiz  false
static   false
stripped true
subsys   linux
va       true

carnary, nx, relro 등 보호기법 여부와, 프로그래밍 언어, OS 등을 확인 할 수 있다.

 

 

Radare2 실행

$ r2 Easy_ELF
정적모드

$ r2 -d Easy_ELF
Debugger 모드

$ r2 -w Easy_ELF
Write 모드

 

[0x08048380]>

 

 

바이너리 분석을 위한 명령어

[0x08048380]> aa
[x] Analyze all flags starting with sym. and entry0 (aa)

[0x08048380]> aaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Constructing a function name for fcn.* and sym.func.* functions (aan)
[x] Type matching analysis for all functions (afta)
[x] Use -AA or aaaa to perform additional experimental analysis.

aa(analyze all)를 통하여 분석을 실행할 수 있다.

aaa를 입력하면 aa를 포함한 aar, aac등의 다양한 명령어들을 실행시킨다. (aaa 안에 aa가 포함)

aaaa도 있지만 시간이 조금 걸리고, aaa에서 잡히지 않는 이상 거의 안잡힌다.

 

 

바이너리 내의 함수 목록 출력

[0x08048380]> afl

 

0x08048380    1 33           entry0
0x08048350    1 6            sym.imp.__libc_start_main
0x08048360    1 6            sym.imp.write
0x08048370    1 6            sym.imp.__isoc99_scanf
0x0804851b    4 99           main
0x08048340    1 6            loc.imp.__gmon_start
0x08048410    4 35           fcn.08048410
0x08048600    4 42           fcn.08048600
0x08048434    1 29           fcn.08048434
0x08048451   14 166          fcn.08048451
0x080484f7    1 36           fcn.080484f7
0x080485f2    1 4            fcn.080485f2
0x080482f4    3 46           fcn.080482f4
0x08048635    1 17           fcn.08048635
0x080483b0    6 85           fcn.080483b0

 

[0x08048380]> afl~main

 

0x08048350    1 6            sym.imp.__libc_start_main
0x0804851b    4 99           main

~을 쓰면 grep 쓰듯이 사용이 가능하다.

 

 

바이너리 내의 함수 이름 변경

[0x08048380]> afn func1 0x080483b0

 

0x08048380    1 33           entry0
0x08048350    1 6            sym.imp.__libc_start_main
0x08048360    1 6            sym.imp.write
0x08048370    1 6            sym.imp.__isoc99_scanf
0x0804851b    4 99           main
0x08048340    1 6            loc.imp.__gmon_start
0x08048410    4 35           fcn.08048410
0x08048600    4 42           fcn.08048600
0x08048434    1 29           fcn.08048434
0x08048451   14 166          fcn.08048451
0x080484f7    1 36           fcn.080484f7
0x080485f2    1 4            fcn.080485f2
0x080482f4    3 46           fcn.080482f4
0x08048635    1 17           fcn.08048635
0x080483b0    6 85           func1

0x080483b0 함수의 이름이 func1로 변경된 것을 확인 할 수 있다.

 

 

함수의 디스어셈블리 출력

[0x08048380]> pdf @main

 

            ; DATA XREF from entry0 @ 0x8048397
┌ 99: int main (int argc, char **argv, char **envp);
│           ; var char *ptr @ esp+0x4
│           ; var size_t nbytes @ esp+0x8
│           0x0804851b      55             push ebp
│           0x0804851c      89e5           mov ebp, esp
│           0x0804851e      83e4f0         and esp, 0xfffffff0
│           0x08048521      83ec10         sub esp, 0x10
│           0x08048524      c74424081700.  mov dword [nbytes], 0x17    ; [0x17:4]=-1 ; 23 ; size_t nbytes
│           0x0804852c      c74424045d86.  mov dword [ptr], str.Reversing.Kr_Easy_ELF ; [0x804865d:4]=0x65766552 ; "Reversing.Kr Easy ELF\n\n" ; const char *ptr
│           0x08048534      c70424010000.  mov dword [esp], 1          ; int fd
│           0x0804853b      e820feffff     call sym.imp.write          ; ssize_t write(int fd, const char *ptr, size_t nbytes)
│           0x08048540      e8effeffff     call fcn.08048434
│           0x08048545      e807ffffff     call fcn.08048451
│           0x0804854a      83f801         cmp eax, 1                  ; 1
│       ┌─< 0x0804854d      750c           jne 0x804855b
│       │   0x0804854f      e8a3ffffff     call fcn.080484f7
│       │   0x08048554      b800000000     mov eax, 0
│      ┌──< 0x08048559      eb21           jmp 0x804857c
│      ││   ; CODE XREF from main @ 0x804854d
│      │└─> 0x0804855b      c74424080600.  mov dword [nbytes], 6       ; size_t nbytes
│      │    0x08048563      c74424047586.  mov dword [ptr], str.Wrong  ; [0x8048675:4]=0x6e6f7257 ; "Wrong\n" ; const char *ptr
│      │    0x0804856b      c70424010000.  mov dword [esp], 1          ; int fd
│      │    0x08048572      e8e9fdffff     call sym.imp.write          ; ssize_t write(int fd, const char *ptr, size_t nbytes)
│      │    0x08048577      b800000000     mov eax, 0
│      │    ; CODE XREF from main @ 0x8048559
│      └──> 0x0804857c      c9             leave
└           0x0804857d      c3             ret

pdf(Print Disassemble Function) : pdf @funcname 으로 디스어셈블을 확인 할 수 있다.

만약 pd만 사용한다면 함수가 아닌 개체를 디스어셈블 해준다.

[0x08048380]> pd @0x0804851b

0x0804851b가 main 함수의 시작 주소이므로 pdf @main과 같은 화면을 볼 수 있다.

 

 

탐색 위치 변경

[0x08048380]> s main
[0x0804851b]>

s는 현재 탐색 위치를 지정하는데 사용한다.

s main을 통해 main 함수의 시작 위치로 이동한 것을 볼 수 있다. (main 시작 주소 0x0804851b)

  * afn 으로 함수 이름을 변경 후 s [함수명]을 하면 편리하게 이용이 가능하다.

[0x08048380]> s 0x0804851b
[0x0804851b]>

main 대신 주소를 적어도 된다.

 

 

바이너리 그래프 모드 출력

[0x0804851b]> VV

방향키로 움직이면서 디스어셈블리를 볼 수 있고, 현재 분석중인것은 위 사진처럼 파란색으로 표시된다.

다음 노드로 넘어갈려면 [Tab]을 누르거나 [g] 명령어로 노드를 선택 할 수 있다.

분석 하다가 현재 노드로 돌아가고 싶으면 .을 누르면 된다.

 

[p]를 누르면 그래프의 형태가 변화한다.

 

[x]를 누르면 현재 분석중인 노드의 위치를 알려준다.

방향키와 엔터를 이용하여 바로 그 위치로 이동할 수 있다.

 

[q]를 눌러서 이전 화면으로 돌아갈 수 있다.

 

 

Hexdump 값 출력하기

[0x0804851b]> px 0x6 @0x8048675

 

- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0x08048675  5772 6f6e 670a                           Wrong.

px 로 hexdump를 볼 수 있다. 0x6을 지정해서 0x6만큼 보겠다고 지정을 한 것이다. 

[0x0804851b]> x 0x30

 

- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0x0804851b  5589 e583 e4f0 83ec 10c7 4424 0817 0000  U.........D$....
0x0804852b  00c7 4424 045d 8604 08c7 0424 0100 0000  ..D$.].....$....
0x0804853b  e820 feff ffe8 effe ffff e807 ffff ff83  . ..............

x 명령어로 현재 위치에서 0x30 만큼의 hex 값을 확인 할 수 있다.

 

 

Flagspaces 확인

[0x0804851b]> fs

 

    0 . classes
    9 . functions
    4 . imports
    4 . relocs
    0 . search
   28 . sections
   10 . segments
    3 * strings
    3 . symbols

 

[0x0804851b]> fs strings; f

 

0x08048653 10 str.Correct
0x0804865d 24 str.Reversing.Kr_Easy_ELF
0x08048675 7 str.Wrong

fs strings; f를 이용하여 문자열 플래그들을 목록화 해서 볼 수 있다.

 

 

데이터/코드 참조 찾기

[0x0804851b]> axt @@ str.Wrong

 

main 0x8048563 [DATA] mov dword [ptr], str.Wrong

axt @@ str.*로 문자열 플래그들의 참조를 찾을 수 있다.

 

 

문자열 검색하기

[0x0804851b]> izzq~Wrong

 

0x8048675 7 6 Wrong\n

izzq~[String] 으로 사용하면 된다.

 

 

 

디버그 모드 Radare2 실행

$ r2 -d Easy_ELF

 

Process with PID 3361 started...
= attach 3361 3361
bin.baddr 0x08048000
Using 0x8048000
asm.bits 32
glibc.fc_offset = 0x00148

r2 실행시 -d를 붙이면 디버그 모드를 실행할 수 있다.

 

 

디버깅 시작

[0xf7f2e120]> dc

dc 명령어로 시작 시킬 수 있다.

맨 처음에 프로그램을 실행하거나 브레이크 포인트 때문에 멈춘 상황에서 다시 실행할 수 있게 한다.

 

 

설정된 BreakPoint 리스트 확인

[0xf7f2e120]> db

 

0x0804851b - 0x0804851c 1 --x sw break enabled valid cmd="" cond="" name="0x0804851b" module="/home/nanglam/Downloads/Easy_ELF"

db만 쓰면 설정되어 있는 breakpoint 리스트를 확인할 수 있다.

 

 

BreakPoint 설정

[0xf7f2e120]> db main
[0xf7f2e120]> db 0x0804851b

db  [함수명] 명령어로 breakpoint를 설정할 수 있다.

db  [주소] 명령어도 가능하다.

 

 

BreakPoint 해제

[0xf7f2e120]> db -main
[0xf7f2e120]> db -0x0804851b

db -[함수명] 명령어로 breakpoint를 해제할 수 있다.

db -[주소] 명령어도 가능하다.

 

 

레지스터 상태 출력

[0xf7f2e120]> dr

 

eax = 0x00000000
ebx = 0x00000000
ecx = 0x00000000
edx = 0x00000000
esi = 0x00000000
edi = 0x00000000
esp = 0xffb976d0
ebp = 0x00000000
eip = 0xf7f2e120
eflags = 0x00000200
oeax = 0x0000000b

dr  명령어로 현재 레지스터 상태를 출력할 수 있다.

 

 

변수의 상태 확인하기

[0xf7f2e120]> afvd

 

Cannot find function.

afvd 명령어로 현재 생성된 변수와 값을 여러 형태로 출력한다.

  * 왜 나는 Cannot find function만 나올까.. 해결중이다..

 

다시 시작 (올리디버거의 Ctrl+f2)

[0xf7f2e120]> ood
[0xf7f2e120]> ood arg1 arg2

 

Process with PID 3455 started...
= attach 3455 3455
File dbg:///home/nanglam/Downloads/Easy_ELF  reopened in read-write mode
3455

ood 명령어로 디버그 모드로 다시 열기가 가능하다.

ood arg1 arg2 방식으로 인자값을 넣는것도 가능하다.

  * ood를 하고 나서 소스를 보면 invalid로 바뀌는 경우가 있는데, r2를 다시시작 하면 된다. (aslr 때문이다)

  * 참고 : https://fir3.tistory.com/?page=4

 

FiR333

 

fir3.tistory.com

 

 

프로그램 종료 확인

[0xf7f2e120]> dc

 

child exited with status 0

==> Process finished

dc를 했을 때, Process finished가 출력되면 프로그램을 끝까지 실행한 것이다.

 

 

바이너리 패치 모드 Radare2 실행

$ r2 -w Easy_ELF

 

[0x08048380]>

-w 를 붙이면 쓰기 모드가 된다.

실행한 바이너리 값이 수정되어 저장되므로 복사본을 만들어 두는것이 좋다.

 

 

Hex 값 변경하기

[0x08048675]> px 0x6
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0x08048675  5772 6f6e 670a                           Wrong.

 

[0x08048675]> wx 41

 

[0x08048675]> px 0x6
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0x08048675  4172 6f6e 670a                           Arong.

기존의 문자열은 Wrong. 이였지만 wx 41로 Arong.으로 변경하였다.

wx [Hex값] 으로 사용할 수 있다.

 

 

명령어 변경하기

[0x08048675]> px 0x6
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0x08048675  4172 6f6e 670a                           Arong.

 

[0x08048675]> wa je 0x000
Written 6 byte(s) (je 0x000) = wx 0f848579fbf7

 

[0x08048675]> pi 1
je section.

[0x08048675]> px 0x10
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0x08048675  0f84 8579 fbf7 0001 1b03 3b48 0000 0008  ...y......;H....

기존엔 Arong. 문자열이였지만, je로 변경된 것을 확인할 수 있다.

 

 

rax2 

$ rax2 10
0xa

$ rax2 0xa
10

진법 변환기이다.

$ rax2 10b
0x2

$ rax2 b10
1010b

b를 쓰면 2진수도 가능하다.

$ rax2 ?

?를 붙이면 다양한 진법 변환을 확인할 수 있다.

 

 

radiff2

$ cat a.txt
1,2,3
$ cat b.txt
1,2,3
$ radiff2 a.txt b.txt

 

$ cat a.txt
1,2,3
$ cat b.txt
4,5,6
$ radiff2 a.txt b.txt
0x00000000 31 => 34 0x00000000
0x00000002 32 => 35 0x00000002
0x00000004 33 => 36 0x00000004

두 파일을 비교해서 내용이 같으면 아무것도 안뜨고, 다른 부분이 있으면 찾아준다.

반응형

댓글