on
[Reversing] Radare2 설치 및 사용 방법 총 정리 [예제 포함]
[Reversing] Radare2 설치 및 사용 방법 총 정리 [예제 포함]
반응형
Radare2?
Unix 환경에서 사용할 수 있는 리버싱 툴이다. (윈도우도 있다.)
[공식홈페이지] https://rada.re/r/
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.kr 의 Easy_ELF를 사용했다.
바이너리 정보 확인
$ 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
" ; 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
" ; 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
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
프로그램 종료 확인
[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
두 파일을 비교해서 내용이 같으면 아무것도 안뜨고, 다른 부분이 있으면 찾아준다.
반응형
from http://security-nanglam.tistory.com/527 by ccl(A) rewrite - 2021-08-05 18:00:32