当前位置: 首页 > 工具软件 > radare2 > 使用案例 >

Linux radare2 二进制代码分析

胥英奕
2023-12-01

至于怎么搭建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
 类似资料: