목차 [궁금한게 있다면 Ctrl+F로 검색하면 빠르다.]
Radare2?
Radare2설치
바이너리 정보 확인
Radare2 실행
바이너리 분석을 위한 명령어
바이너리 내의 함수 목록 출력
바이너리 내의 함수 이름 변경
함수의 디스어셈블리 출력
탐색 위치 변경
바이너리 그래프 모드 출력
Hexdump 값 출력하기
Flagspaces확인
데이터/코드 참조 찾기
문자열 검색하기
디버그 모드 Radare2 살향
디버깅 시작
설정된 BreakPoint 리스트 확인
BreakPoint 설정
BreakPoint 해제
레지스터 상태 출력
변수의 상태 확인하기
다시 시작 (올리디버거의 Ctrl+f2)
프로그램 종료 확인
바이너리 패치 모드 Radare2 실행
Hex 값 변경하기
명령어 변경하기
rax2
radiff2
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\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
프로그램 종료 확인
[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
두 파일을 비교해서 내용이 같으면 아무것도 안뜨고, 다른 부분이 있으면 찾아준다.
'Security_ > Reversing' 카테고리의 다른 글
[풀이] abex' crackme #1 (2) | 2021.09.15 |
---|---|
[Themida / WinLicense] OllyDbg 오류 해결 정리! (0) | 2021.09.14 |
[리버싱] 정적/ 동적 분석 (리버싱 시작) (0) | 2019.07.23 |
[Reversing] call, ret, leave 어셈블리어 (0) | 2018.10.09 |
[Reversing] gdb 표기방식 변경 (0) | 2018.10.08 |
댓글