至于怎么搭建radare软件调试环境,可以参照之前写过的文章;
这里主要和大家一起学习一下radare2的二进制文件分析功能,首先讲讲基本的使用方法,准备调试一个编译出来的二进制文件;
我们这里从下面这个例子开始来分析二进制文件,就是让你输入一个密码,判断密码是否是违法的;
#include<stdio.h>
#include<string.h>
void main() {
char passwd[] = "5201314";
char str[128];
scanf("%s", &str);
if (!strcmp(passwd, str)) {
printf("the password is correct\n");
return;
}
printf("the password is invalid\n");
}
//生成测试文件
curits@curits-virtual-machine:~/Desktop/ld_preload$ gcc ldpreload.c -o test
//测试test,密码输入错误,程序退出
curits@curits-virtual-machine:~/Desktop/ld_preload$ ./test 11
11w
the password is invalid
curits@curits-virtual-machine:~/Desktop/ld_preload$ ./test
ddd
the password is invalid
curits@curits-virtual-machine:~/Desktop/ld_preload$
//进入r2进行调试
curits@curits-virtual-machine:~/Desktop/ld_preload$ r2 ./test
Warning: run r2 with -e io.cache=true to fix relocations in disassembly
-- Greetings, human.
[0x00000660]> //自动识别入口地址,也可以用命令ie查看
[0x00000660]> ie
[Entrypoints]
vaddr=0x00000660 paddr=0x00000660 haddr=0x00000018 hvaddr=0x00000018 type=program
1 entrypoints
使用aaa命令进行分析,更多命令可以使用a?查看;
[0x00000660]> a?
Usage: a [abdefFghoprxstc] [...]
| a alias for aai - analysis information
| a* same as afl*;ah*;ax*
| aa[?] analyze all (fcns + bbs) (aa0 to avoid sub renaming)
| a8 [hexpairs] analyze bytes
| ab[b] [addr] analyze block at given address
| abb [len] analyze N basic blocks in [len] (section.size by default)
| ac[?] manage classes
| aC[?] analyze function call
| aCe[?] same as aC, but uses esil with abte to emulate the function
| ad[?] analyze data trampoline (wip)
| ad [from] [to] analyze data pointers to (from-to)
| ae[?] [expr] analyze opcode eval expression (see ao)
| af[?] analyze Functions
| aF same as above, but using anal.depth=1
| ag[?] [options] draw graphs in various formats
| ah[?] analysis hints (force opcode size, ...)
| ai [addr] address information (show perms, stack, heap, ...)
| aj same as a* but in json (aflj)
| aL list all asm/anal plugins (e asm.arch=?)
| an [name] [@addr] show/rename/create whatever flag/function is used at addr
| ao[?] [len] analyze Opcodes (or emulate it)
| aO[?] [len] Analyze N instructions in M bytes
| ap find prelude for current offset
| ar[?] like 'dr' but for the esil vm. (registers)
| as[?] [num] analyze syscall using dbg.reg
| av[?] [.] show vtables
| ax[?] manage refs/xrefs (see also afx?)
//
[0x00000660]> 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] Check for vtables
[x] Type matching analysis for all functions (aaft)
[x] Propagate noreturn information
[x] Use -AA or aaaa to perform additional experimental analysis.
aaa分析完成之后, r2会将所有有用的信息和特定的名字绑定在一起,比如区段、函数、符号、字符串,这些都被称作 ‘flags’, flags 被整合进 ,一个 flag 是所有类似特征的集合;
//查看所有flag信息
[0x00000660]> fs
0 * classes
0 * functions
9 * imports
9 * relocs
29 * sections
10 * segments
2 * strings
31 * symbols
25 * symbols.sections
//查看你imports信息
[0x00000660]> fs imports; f
0x00000000 292 loc.imp._ITM_deregisterTMCloneTable
0x00000000 16 sym.imp.__libc_start_main
0x00000000 16 loc.imp.__gmon_start
0x00000000 16 loc.imp._ITM_registerTMCloneTable
0x00000610 6 sym.imp.puts
0x00000620 6 sym.imp.__stack_chk_fail
0x00000630 6 sym.imp.strcmp
0x00000640 6 sym.imp.__isoc99_scanf
0x00000650 6 sym.imp.__cxa_finalize
使用iz命令可以查看所有数据段的字符串信息,因为我们有打印对密码的匹配结果;
[0x00000660]> iz
[Strings]
nth paddr vaddr len size section type string
―――――――――――――――――――――――――――――――――――――――――――――――――――――――
0 0x00000897 0x00000897 23 24 .rodata ascii the password is correct
1 0x000008af 0x000008af 23 24 .rodata ascii the password is invalid
帮助信息:
[0x7efcaa4b1090]> ?
Usage: [.][times][cmd][~grep][@[@iter]addr!size][|>pipe] ; ...
Append '?' to any char command to get detailed help
Prefix with number to repeat command N times (f.ex: 3x)
| %var=value alias for 'env' command
| *[?] off[=[0x]value] pointer read/write data/values (see ?v, wx, wv)
| (macro arg0 arg1) manage scripting macros
| .[?] [-|(m)|f|!sh|cmd] Define macro or load r2, cparse or rlang file
| _[?] Print last output
| =[?] [cmd] send/listen for remote commands (rap://, raps://, udp://, http://, <fd>)
| <[...] push escaped string into the RCons.readChar buffer
| /[?] search for bytes, regexps, patterns, ..
| ![?] [cmd] run given command as in system(3)
| #[?] !lang [..] Hashbang to run an rlang script
| a[?] analysis commands
| b[?] display or change the block size
| c[?] [arg] compare block with given data
| C[?] code metadata (comments, format, hints, ..)
| d[?] debugger commands
| e[?] [a[=b]] list/get/set config evaluable vars
| f[?] [name][sz][at] add flag at current address
| g[?] [arg] generate shellcodes with r_egg
| i[?] [file] get info about opened file from r_bin
| k[?] [sdb-query] run sdb-query. see k? for help, 'k *', 'k **' ...
| l [filepattern] list files and directories
| L[?] [-] [plugin] list, unload load r2 plugins
| m[?] mountpoints commands
| o[?] [file] ([offset]) open file at optional address
| p[?] [len] print current block with format and length
| P[?] project management utilities
| q[?] [ret] quit program with a return value
| r[?] [len] resize file
| s[?] [addr] seek to address (also for '0x', '0x1' == 's 0x1')
| t[?] types, noreturn, signatures, C parser and more
| T[?] [-] [num|msg] Text log utility (used to chat, sync, log, ...)
| u[?] uname/undo seek/write
| v visual mode (v! = panels, vv = fcnview, vV = fcngraph, vVV = callgraph)
| w[?] [str] multiple write operations
| x[?] [len] alias for 'px' (print hexadecimal)
| y[?] [len] [[[@]addr Yank/paste bytes from/to memory
| z[?] zignatures management
| ?[??][expr] Help or evaluate math expression
| ?$? show available '$' variables and aliases
| ?@? misc help for '@' (seek), '~' (grep) (see ~??)
| ?>? output redirection
| ?|? help for '|' (pipe)
[0x00000660]> ax?
Usage: ax[?d-l*] # see also 'afx?'
| ax list refs
| ax* output radare commands
| ax addr [at] add code ref pointing to addr (from curseek)
| ax- [at] clean all refs/refs from addr
| ax-* clean all refs/refs
| axc addr [at] add generic code ref
| axC addr [at] add code call ref
| axg [addr] show xrefs graph to reach current function
| axg* [addr] show xrefs graph to given address, use .axg*;aggv
| axgj [addr] show xrefs graph to reach current function in json format
| axd addr [at] add data ref
| axq list refs in quiet/human-readable format
| axj list refs in json format
| axF [flg-glob] find data/code references of flags
| axm addr [at] copy data/code references pointing to addr to also point to curseek (or at)
| axt[?] [addr] find data/code references to this address //查找该地址的数据/代码引用
| axf [addr] find data/code references from this address
| axv [addr] list local variables read-write-exec references
| ax. [addr] find data/code references from and to this address
| axff[j] [addr] find data/code references from this function
| axs addr [at] add string ref
//查找数据/代码引用
[0x00000660]> axt @@ str.*
main 0x7d4 [DATA] lea rdi, str.the_password_is_correct
main 0x7e2 [DATA] lea rdi, str.the_password_is_invalid
//alf查看所有radare解析出的函数,从结果来看只有一个main函数值得注意
[0x00000660]> afl
0x00000660 1 42 entry0
0x00000690 4 50 -> 40 sym.deregister_tm_clones
0x000006d0 4 66 -> 57 sym.register_tm_clones
0x00000720 5 58 -> 51 sym.__do_global_dtors_aux
0x00000650 1 6 sym.imp.__cxa_finalize
0x00000760 1 10 entry.init0
0x00000880 1 2 sym.__libc_csu_fini
0x00000884 1 9 sym._fini
0x00000810 4 101 sym.__libc_csu_init
0x0000076a 6 154 main
0x000005e0 3 23 sym._init
0x00000610 1 6 sym.imp.puts
0x00000620 1 6 sym.imp.__stack_chk_fail
0x00000000 6 292 -> 318 loc.imp._ITM_deregisterTMCloneTable
0x00000630 1 6 sym.imp.strcmp
0x00000640 1 6 sym.imp.__isoc99_scanf
//用 's main' 指令定位到main函数入口处,'pdf'输出反汇编代码
[0x00000660]> s main
[0x0000076a]> pdf
; DATA XREF from entry0 @ 0x67d
┌ 147: int main (int argc, char **argv, char **envp);
│ ; var char *s1 @ rbp-0x98
│ ; var char *s2 @ rbp-0x90
│ ; var int64_t canary @ rbp-0x8
│ 0x0000076a 55 push rbp
│ 0x0000076b 4889e5 mov rbp, rsp
│ 0x0000076e 4881eca00000. sub rsp, 0xa0
│ 0x00000775 64488b042528. mov rax, qword fs:[0x28]
│ 0x0000077e 488945f8 mov qword [canary], rax
│ 0x00000782 31c0 xor eax, eax
│ 0x00000784 48b835323031. movabs rax, 0x34313331303235 ; '5201314'
│ 0x0000078e 48898568ffff. mov qword [s1], rax
│ 0x00000795 488d8570ffff. lea rax, [s2]
│ 0x0000079c 4889c6 mov rsi, rax
│ 0x0000079f 488d3dde0000. lea rdi, [0x00000884] ; "%s" ; const char *format
│ 0x000007a6 b800000000 mov eax, 0
│ 0x000007ab e890feffff call sym.imp.__isoc99_scanf ; int scanf(const char *format)
│ 0x000007b0 488d9570ffff. lea rdx, [s2]
│ 0x000007b7 488d8568ffff. lea rax, [s1]
│ 0x000007be 4889d6 mov rsi, rdx ; const char *s2
│ 0x000007c1 4889c7 mov rdi, rax ; const char *s1
│ 0x000007c4 e867feffff call sym.imp.strcmp ; int strcmp(const char *s1, const char *s2)
│ 0x000007c9 85c0 test eax, eax
│ ┌─< 0x000007cb 750e jne 0x7db
│ │ 0x000007cd 488d3db30000. lea rdi, str.the_password_is_correct ; 0x887 ; "the password is correct" ; const char *s
│ │ 0x000007d4 e837feffff call sym.imp.puts ; int puts(const char *s)
│ ┌──< 0x000007d9 eb0c jmp 0x7e7
│ ││ ; CODE XREF from main @ 0x7cb
│ │└─> 0x000007db 488d3dbd0000. lea rdi, str.the_password_is_invalid ; 0x89f ; "the password is invalid" ; const char *s
│ │ 0x000007e2 e829feffff call sym.imp.puts ; int puts(const char *s)
│ │ ; CODE XREF from main @ 0x7d9
│ └──> 0x000007e7 488b45f8 mov rax, qword [canary]
│ 0x000007eb 644833042528. xor rax, qword fs:[0x28]
│ ┌─< 0x000007f4 7405 je 0x7fb
│ │ 0x000007f6 e825feffff call sym.imp.__stack_chk_fail ; void __stack_chk_fail(void)
│ │ ; CODE XREF from main @ 0x7f4
│ └─> 0x000007fb c9 leave
└ 0x000007fc c3 ret
[0x0000076a]>
直接从反汇编代码中就可以看到movabs rax, 0x64726f7773736170 ; ‘password’ --> mov qword [s1], rax;然后再把rax送入内存[s1];
curits@curits-virtual-machine:~/Desktop/ld_preload$ ./test
5201314
the password is correct