动态调试elf文件的几种方法

技术
动态调试elf文件的几种方法

最近在刷题的时候遇到了很多elf文件,虽然可以通过ida分析伪代码解出来,但是发现有些通过动态调试的方式可以直接找到flag,这样简单了不少,因为之前接触的linux下的逆向题目比较少,所以通过这次刷题也记录一下动态调试elf文件的几种方式。

0x01 ida动态调试

ida不光可以静态分析函数伪代码,也可以通过动态调试的方式来分析linux下的elf文件。

首先将ida/dbgsrv/路径下的linux_server/linux_serverx64文件复制到linux下,两个文件分别是调试32位和64位程序使用的:

picture.image

在linux下启动对应的文件:

picture.image

把我们要调试的文件放到相应的文件夹中,这里我放到/homt/test/文件夹中。

在ida中选择Debugger-Run-Remote linux debugger

picture.image

picture.image

在弹出的对话框中,Application填写文件存放的位置和文件名,Directory中填写文件存放的路径,Parameters是指传递的参数,如果程序运行需要传参的话可以在这填入,Hostname就是linux的ip地址,Port一般都是默认的23946,如果设置了password在下方填入,没有就空着:

picture.image

进入ida动态调试界面,默认情况下界面大概分为6个区域(通用寄存器和标志寄存器窗口为1个),模块列表和线程列表我不怎么看,主要是看反汇编和寄存器还有堆栈。

ida在动态调试的时候和OD差不多,F9继续运行,F7步入,F8步过,F2下断点。 通过Debugger-Breakpoints-Breakpoint list或者Ctrl+Alt+B来查看已经下的断点:

picture.image

也可以通过Debugger-Debugger windows-Stack trace或者Ctrl+Alt+S查看是谁调用了当前的函数:

picture.image

虽然感觉没有OD好用,但是实现简单的调试还是没有问题的。

0x02 gdb动态调试

GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具。

一般在kali中,gdb都是默认安装的。 使用gdb调试可执行文件


        
  `gdb <program> //启动`
  `quit //结束`
 
      

运行程序


        
  `run:简写为r,运行调试程序,直到断点处`
  `stepi:简写为s,执行一条指令,步入函数`
  `nexti:简写为n,执行一条指令,步过函数`
  `continue:简写为c,继续执行`
  `until:在一个循环体内部单步跟踪的时候,可以通过until命令跳出循环`
  `until+行号:运行至某行`
 
      

断点


        
  `break *address:简写b *address,设置断点`
  `info breakpoints:简写为info b,查看断点`
  `delete *address:删除断点`
  `disable *address:暂停断点`
  `enable *address:开启断点`
  `delete breakpoints:删除所有断点`
 
      

查看


        
  `info register:简写为info r,查看寄存器`
  `x/countFormatSize addr:以指定格式Format打印地址address处的指定大小size、指定数量count的对象`
  `Size:b(字节)、h(半字)、w(字)、g(8字节)`
  `Format:o(八进制)、d(十进制)、x(十六进制)、u(无符号十进制)、t(二进制)、f(浮点数)、a(地 址)、i(指令)、c(字符)、s(字符串)`
  `backtrace:打印函数调用栈回溯`
  `set $reg=value:修改寄存器`
  `set *(type*)(address)=value:修改内存地址addr为value`
 
      

我在使用的过程中大概用到的就是这些命令。

0x03 radare2动态调试

radare2是一个开源项目,他可以使用命令直接执行,也有GUI程序叫做Cutter并且兼容多平台。

在kali中r2也是默认安装的,可以直接在控制台运行,进入程序后使用aaa命令分析程序


        
  `$ r2 ./e3dd9674429f4ce1a25c08ea799fc027` 
  `[0x00400660]> 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.`
 
      

也可以直接使用r2 -A ./program来直接分析程序


        
  `$ r2 -A ./e3dd9674429f4ce1a25c08ea799fc027` 
  `[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.`
 
      

在分析程序之前,r2的iI命令可以提供很多有用的信息


        
  `[0x00400660]> iI`
  `arch x86`
  `baddr 0x400000`
  `binsz 9449`
  `bintype elf`
  `bits 64`
  `canary true`
  `class ELF64`
  `compiler GCC: (Ubuntu 5.4.1-2ubuntu1~14.04) 5.4.1 20160904 GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4`
  `crypto false`
  `endian little`
  `havecode true`
  `intrp /lib64/ld-linux-x86-64.so.2`
  `laddr 0x0`
  `lang c`
  `linenum true`
  `lsyms true`
  `machine AMD x86-64 architecture`
  `maxopsz 16`
  `minopsz 1`
  `nx true`
  `os linux`
  `pcalign 0`
  `pic false`
  `relocs true`
  `relro partial`
  `rpath NONE`
  `sanitiz false`
  `static false`
  `stripped false`
  `subsys linux`
  `va true`
 
      

在了解程序的基本信息后你还可以通过iiiE命令来看下程序的导入和导出函数,从而能够更好的了解程序实现的功能


        
  `[0x00400660]> ii`
  `[Imports]`
  `nth vaddr bind type lib name`
  `―――――――――――――――――――――――――――――――――――――`
  `1 0x004005c0 GLOBAL FUNC remove`
  `2 0x004005d0 GLOBAL FUNC fclose`
  `3 0x004005e0 GLOBAL FUNC strlen`
  `4 0x004005f0 GLOBAL FUNC __stack_chk_fail`
  `5 0x00400600 GLOBAL FUNC fputc`
  `6 0x00400610 GLOBAL FUNC __libc_start_main`
  `7 0x00400620 GLOBAL FUNC fprintf`
  `8 0x00400630 WEAK NOTYPE __gmon_start__`
  `9 0x00400640 GLOBAL FUNC fseek`
  `10 0x00400650 GLOBAL FUNC fopen`
 
  `[0x00400660]> iE`
  `[Exports]`
 
  `nth paddr vaddr bind type size lib name`
  `――――――――――――――――――――――――――――――――――――――――――――――――――――――`
  `45 0x00000960 0x00400960 GLOBAL FUNC 2 __libc_csu_fini`
  `49 0x000010e0 0x006010e0 GLOBAL OBJ 44 t`
  `50 ---------- 0x0060120c GLOBAL NOTYPE 0 _edata`
  `51 0x00001160 0x00601160 GLOBAL OBJ 172 p`
  `53 0x00000964 0x00400964 GLOBAL FUNC 0 _fini`
  `58 0x00001080 0x00601080 GLOBAL NOTYPE 0 __data_start`
  `61 0x00001088 0x00601088 GLOBAL OBJ 0 __dso_handle`
  `62 0x00000970 0x00400970 GLOBAL OBJ 4 _IO_stdin_used`
  `63 0x000008f0 0x004008f0 GLOBAL FUNC 101 __libc_csu_init`
  `64 ---------- 0x00601210 GLOBAL NOTYPE 0 _end`
  `65 0x00000660 0x00400660 GLOBAL FUNC 0 _start`
  `67 0x000010a0 0x006010a0 GLOBAL OBJ 33 s`
  `68 0x00001120 0x00601120 GLOBAL OBJ 44 u`
  `69 ---------- 0x0060120c GLOBAL NOTYPE 0 __bss_start`
  `70 0x00000756 0x00400756 GLOBAL FUNC 407 main`
  `73 ---------- 0x00601210 GLOBAL OBJ 0 __TMC_END__`
  `75 0x00000590 0x00400590 GLOBAL FUNC 0 _init`
 
      

你还可以通过afl命令查看程序存在的函数,从而找到main函数,定位到对应的位置,查看反汇编代码


        
  `[0x00400660]> afl`
  `0x00400660 1 41 entry0`
  `0x00400610 1 6 sym.imp.__libc_start_main`
  `0x00400690 4 50 -> 41 sym.deregister_tm_clones`
  `0x004006d0 4 58 -> 55 sym.register_tm_clones`
  `0x00400710 3 28 sym.__do_global_dtors_aux`
  `0x00400730 4 38 -> 35 entry.init0`
  `0x00400960 1 2 sym.__libc_csu_fini`
  `0x00400964 1 9 sym._fini`
  `0x004008f0 4 101 sym.__libc_csu_init`
  `0x00400756 12 407 main`
  `0x00400590 3 26 sym._init`
  `0x00400630 1 6 loc.imp.__gmon_start__`
  `0x004005c0 1 6 sym.imp.remove`
  `0x004005d0 1 6 sym.imp.fclose`
  `0x004005e0 1 6 sym.imp.strlen`
  `0x004005f0 1 6 sym.imp.__stack_chk_fail`
  `0x00400600 1 6 sym.imp.fputc`
  `0x00400620 1 6 sym.imp.fprintf`
  `0x00400640 1 6 sym.imp.fseek`
  `0x00400650 1 6 sym.imp.fopen`
 
      

在找到程序内存在的函数后,可以使用axt命令来查看函数调用


        
  `[0x00400660]> axt main`
  `entry0 0x40067d [DATA] mov rdi, main`
 
      

在找到main函数后,使用s命令定位到main函数,pdf命令来查看函数的反汇编代码,s命令后可以加地址或者函数名


        
  `[0x00400660]> s main`
  `[0x00400756]> pdf`
  `; DATA XREF from entry0 @ 0x40067d`
  `┌ 407: int main (int argc, char **argv, char **envp);`
  `│ ; var int64_t var_40h @ rbp-0x40`
  `│ ; var int64_t var_3ch @ rbp-0x3c`
  `│ ; var file*stream @ rbp-0x38`
  `│ ; var char *filename @ rbp-0x30`
  `│ ; var int64_t var_28h @ rbp-0x28`
  `│ ; var int64_t var_24h @ rbp-0x24`
  `│ ; var int64_t canary @ rbp-0x18`
  `│ 0x00400756 55 push rbp`
  `│ 0x00400757 4889e5 mov rbp, rsp`
  `│ 0x0040075a 53 push rbx`
  `│ 0x0040075b 4883ec38 sub rsp, 0x38`
  `│ 0x0040075f 64488b042528. mov rax, qword fs:[0x28]`
  `│ 0x00400768 488945e8 mov qword [canary], rax`
  `│ 0x0040076c 31c0 xor eax, eax`
  `│ 0x0040076e c745c0000000. mov dword [var_40h], 0`
  `│ ; CODE XREF from main @ 0x4007c5`
  `│ ┌─> 0x00400775 8b45c0 mov eax, dword [var_40h]`
  `│ ╎ 0x00400778 4863d8 movsxd rbx, eax`
  `│ ╎ 0x0040077b bfa0106000 mov edi, obj.s ; 0x6010a0 ; "c61b68366edeb7bdce3c6820314b7498" ; const char *s`
  `│ ╎ 0x00400780 e85bfeffff call sym.imp.strlen ; size_t strlen(const char *s)`
  `│ ╎ 0x00400785 4839c3 cmp rbx, rax`
  `│ ┌──< 0x00400788 733d jae 0x4007c7`
  `│ │╎ 0x0040078a 8b45c0 mov eax, dword [var_40h]`
  `│ │╎ 0x0040078d 8d500a lea edx, [rax + 0xa]`
  `│ │╎ 0x00400790 8b45c0 mov eax, dword [var_40h]`
  `│ │╎ 0x00400793 4898 cdqe`
  `│ │╎ 0x00400795 0fb680a01060. movzx eax, byte [rax + obj.s] ; [0x6010a0:1]=99 ; "c61b68366edeb7bdce3c6820314b7498"`
  `│ │╎ 0x0040079c 89c1 mov ecx, eax`
  `│ │╎ 0x0040079e 8b45c0 mov eax, dword [var_40h]`
  `│ │╎ 0x004007a1 83e001 and eax, 1`
  `│ │╎ 0x004007a4 85c0 test eax, eax`
  `│ ┌───< 0x004007a6 7407 je 0x4007af`
  `│ ││╎ 0x004007a8 b801000000 mov eax, 1`
  `│ ┌────< 0x004007ad eb05 jmp 0x4007b4`
  `│ │││╎ ; CODE XREF from main @ 0x4007a6`
  `│ │└───> 0x004007af b8ffffffff mov eax, 0xffffffff ; -1`
  `│ │ │╎ ; CODE XREF from main @ 0x4007ad`
  `│ └────> 0x004007b4 01c8 add eax, ecx`
  `│ │╎ 0x004007b6 89c1 mov ecx, eax`
  `│ │╎ 0x004007b8 4863c2 movsxd rax, edx`
  `│ │╎ 0x004007bb 8888e0106000 mov byte [rax + obj.t], cl ; [0x6010e0:1]=83 ; "SharifCTF{????????????????????????????????}"`
  `│ │╎ 0x004007c1 8345c001 add dword [var_40h], 1`
  `│ │└─< 0x004007c5 ebae jmp 0x400775`
  `│ │ ; CODE XREF from main @ 0x400788`
  `│ └──> 0x004007c7 48b82f746d70. movabs rax, 0x616c662f706d742f ; '/tmp/fla'`
  `│ 0x004007d1 488945d0 mov qword [filename], rax`
  `│ 0x004007d5 c745d8672e74. mov dword [var_28h], 0x78742e67 ; 'g.tx'`
  `│ 0x004007dc 66c745dc7400 mov word [var_24h], 0x74 ; 't' ; 116`
  `│ 0x004007e2 488d45d0 lea rax, [filename]`
  `│ 0x004007e6 be74094000 mov esi, 0x400974 ; const char *mode`
  `│ 0x004007eb 4889c7 mov rdi, rax ; const char *filename`
  `│ 0x004007ee e85dfeffff call sym.imp.fopen ; file*fopen(const char *filename, const char *mode)`
  `│ 0x004007f3 488945c8 mov qword [stream], rax`
  `│ 0x004007f7 488b45c8 mov rax, qword [stream]`
  `│ 0x004007fb ba20116000 mov edx, obj.u ; 0x601120 ; "*******************************************" ; ...`
  `│ 0x00400800 be76094000 mov esi, 0x400976 ; const char *format`
  `│ 0x00400805 4889c7 mov rdi, rax ; FILE *stream`
  `│ 0x00400808 b800000000 mov eax, 0`
  `│ 0x0040080d e80efeffff call sym.imp.fprintf ; int fprintf(FILE *stream, const char *format, ...)`
  `│ 0x00400812 c745c4000000. mov dword [var_3ch], 0`
  `│ ; CODE XREF from main @ 0x4008b0`
  `│ ┌─> 0x00400819 8b45c4 mov eax, dword [var_3ch]`
  `│ ╎ 0x0040081c 4863d8 movsxd rbx, eax`
  `│ ╎ 0x0040081f bfe0106000 mov edi, obj.t ; 0x6010e0 ; "SharifCTF{????????????????????????????????}" ; const char *s`
  `│ ╎ 0x00400824 e8b7fdffff call sym.imp.strlen ; size_t strlen(const char *s)`
  `│ ╎ 0x00400829 4839c3 cmp rbx, rax`
  `│ ┌──< 0x0040082c 0f8383000000 jae 0x4008b5`
  `│ │╎ 0x00400832 8b45c4 mov eax, dword [var_3ch]`
  `│ │╎ 0x00400835 4898 cdqe`
  `│ │╎ 0x00400837 8b0485601160. mov eax, dword [rax*4 + obj.p] ; [0x601160:4]=30`
  `│ │╎ 0x0040083e 4863c8 movsxd rcx, eax`
  `│ │╎ 0x00400841 488b45c8 mov rax, qword [stream]`
  `│ │╎ 0x00400845 ba00000000 mov edx, 0 ; int whence`
  `│ │╎ 0x0040084a 4889ce mov rsi, rcx ; long offset`
  `│ │╎ 0x0040084d 4889c7 mov rdi, rax ; FILE *stream`
  `│ │╎ 0x00400850 e8ebfdffff call sym.imp.fseek ; int fseek(FILE *stream, long offset, int whence)`
  `│ │╎ 0x00400855 8b45c4 mov eax, dword [var_3ch]`
  `│ │╎ 0x00400858 4898 cdqe`
  `│ │╎ 0x0040085a 8b0485601160. mov eax, dword [rax*4 + obj.p] ; [0x601160:4]=30`
  `│ │╎ 0x00400861 4898 cdqe`
  `│ │╎ 0x00400863 0fb680e01060. movzx eax, byte [rax + obj.t] ; [0x6010e0:1]=83 ; "SharifCTF{????????????????????????????????}"`
  `│ │╎ 0x0040086a 0fbec0 movsx eax, al`
  `│ │╎ 0x0040086d 488b55c8 mov rdx, qword [stream]`
  `│ │╎ 0x00400871 4889d6 mov rsi, rdx ; FILE *stream`
  `│ │╎ 0x00400874 89c7 mov edi, eax ; int c`
  `│ │╎ 0x00400876 e885fdffff call sym.imp.fputc ; int fputc(int c, FILE *stream)`
  `│ │╎ 0x0040087b 488b45c8 mov rax, qword [stream]`
  `│ │╎ 0x0040087f ba00000000 mov edx, 0 ; int whence`
  `│ │╎ 0x00400884 be00000000 mov esi, 0 ; long offset`
  `│ │╎ 0x00400889 4889c7 mov rdi, rax ; FILE *stream`
  `│ │╎ 0x0040088c e8affdffff call sym.imp.fseek ; int fseek(FILE *stream, long offset, int whence)`
  `│ │╎ 0x00400891 488b45c8 mov rax, qword [stream]`
  `│ │╎ 0x00400895 ba20116000 mov edx, obj.u ; 0x601120 ; "*******************************************" ; ...`
  `│ │╎ 0x0040089a be76094000 mov esi, 0x400976 ; const char *format`
  `│ │╎ 0x0040089f 4889c7 mov rdi, rax ; FILE *stream`
  `│ │╎ 0x004008a2 b800000000 mov eax, 0`
  `│ │╎ 0x004008a7 e874fdffff call sym.imp.fprintf ; int fprintf(FILE *stream, const char *format, ...)`
  `│ │╎ 0x004008ac 8345c401 add dword [var_3ch], 1`
  `│ │└─< 0x004008b0 e964ffffff jmp 0x400819`
  `│ │ ; CODE XREF from main @ 0x40082c`
  `│ └──> 0x004008b5 488b45c8 mov rax, qword [stream]`
  `│ 0x004008b9 4889c7 mov rdi, rax ; FILE *stream`
  `│ 0x004008bc e80ffdffff call sym.imp.fclose ; int fclose(FILE *stream)`
  `│ 0x004008c1 488d45d0 lea rax, [filename]`
  `│ 0x004008c5 4889c7 mov rdi, rax ; const char *filename`
  `│ 0x004008c8 e8f3fcffff call sym.imp.remove ; int remove(const char *filename)`
  `│ 0x004008cd b800000000 mov eax, 0`
  `│ 0x004008d2 488b5de8 mov rbx, qword [canary]`
  `│ 0x004008d6 6448331c2528. xor rbx, qword fs:[0x28]`
  `│ ┌─< 0x004008df 7405 je 0x4008e6`
  `│ │ 0x004008e1 e80afdffff call sym.imp.__stack_chk_fail ; void __stack_chk_fail(void)`
  `│ │ ; CODE XREF from main @ 0x4008df`
  `│ └─> 0x004008e6 4883c438 add rsp, 0x38`
  `│ 0x004008ea 5b pop rbx`
  `│ 0x004008eb 5d pop rbp`
  `└ 0x004008ec c3 ret`
 
      

如果觉得看反汇编不过瘾也可以通过px命令查看十六进制内容


        
  `[0x00400756]> px`
  `- offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF`
  `0x00400756 5548 89e5 5348 83ec 3864 488b 0425 2800 UH..SH..8dH..%(.` 
  `0x00400766 0000 4889 45e8 31c0 c745 c000 0000 008b ..H.E.1..E......`
  `0x00400776 45c0 4863 d8bf a010 6000 e85b feff ff48 E.Hc....`..[...H`
  `0x00400786 39c3 733d 8b45 c08d 500a 8b45 c048 980f 9.s=.E..P..E.H..`
  `0x00400796 b680 a010 6000 89c1 8b45 c083 e001 85c0 ....`....E......`
  `0x004007a6 7407 b801 0000 00eb 05b8 ffff ffff 01c8 t...............`
  `0x004007b6 89c1 4863 c288 88e0 1060 0083 45c0 01eb ..Hc.....`..E...`
  `0x004007c6 ae48 b82f 746d 702f 666c 6148 8945 d0c7 .H./tmp/flaH.E..`
  `0x004007d6 45d8 672e 7478 66c7 45dc 7400 488d 45d0 E.g.txf.E.t.H.E.`
  `0x004007e6 be74 0940 0048 89c7 e85d feff ff48 8945 .t.@.H...]...H.E`
  `0x004007f6 c848 8b45 c8ba 2011 6000 be76 0940 0048 .H.E.. .`..v.@.H`
  `0x00400806 89c7 b800 0000 00e8 0efe ffff c745 c400 .............E..`
  `0x00400816 0000 008b 45c4 4863 d8bf e010 6000 e8b7 ....E.Hc....`...`
  `0x00400826 fdff ff48 39c3 0f83 8300 0000 8b45 c448 ...H9........E.H`
  `0x00400836 988b 0485 6011 6000 4863 c848 8b45 c8ba ....`.`.Hc.H.E..`
  `0x00400846 0000 0000 4889 ce48 89c7 e8eb fdff ff8b ....H..H........`
 
      

同时,为了能够更好的理解程序的功能,iz命令可以查看程序中的字符串


        
  `[0x00400756]> iz`
  `[Strings]`
  `nth paddr vaddr len size section type string`
  `―――――――――――――――――――――――――――――――――――――――――――――――――――――――`
  `0 0x000010a0 0x006010a0 32 33 .data ascii c61b68366edeb7bdce3c6820314b7498`
  `1 0x000010e0 0x006010e0 43 44 .data ascii SharifCTF{????????????????????????????????}`
  `2   0x00001120 0x00601120 43  44   .data   ascii *******************************************`
 
      

字符串和函数一样,可以使用axt命令查看是哪里把它打印出来的


        
  `[0x00400756]> axt 0x6010a0`
  `main 0x40077b [DATA] mov edi, obj.s`
  `main 0x400795 [DATA] movzx eax, byte [rax + obj.s]`
 
      

r2还提供了可视模式,可以更直观的分析函数的调用,vv命令进入

picture.image

以上是使用r2静态分析二进制文件,然后r2的功能不止于此,它还可以动态调试二进制文件甚至给我函数的伪代码

使用r2 -d -A ./program命令来进入调试器


        
  `$ r2 -d -A ./e3dd9674429f4ce1a25c08ea799fc027`
  `[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] Finding and parsing C++ vtables (avrr)`
  `[x] Skipping type matching analysis in debugger mode (aaft)`
  `[x] Propagate noreturn information (aanr)`
  `[x] Use -AA or aaaa to perform additional experimental analysis.`
  `[0x7f8186b18050]>`
 
      

动态调试的主要命令


        
  `db:断点,db后可以跟函数名或者地址`
  `dbi:查看已有断点`
  `dc:运行程序`
  `dbt:查看堆栈`
  `dr:查看寄存器`
 
      

        
  `$ r2 -d -A ./e3dd9674429f4ce1a25c08ea799fc027` 
  `[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] Finding and parsing C++ vtables (avrr)`
  `[x] Skipping type matching analysis in debugger mode (aaft)`
  `[x] Propagate noreturn information (aanr)`
  `[x] Use -AA or aaaa to perform additional experimental analysis.`
  `[0x7f53c8464050]> db main`
  `[0x7f53c8464050]> dbi`
  `0 0x00400756 E:1 T:0`
  `[0x7f53c8464050]> dc`
  `hit breakpoint at: 0x400756`
  `[0x00400756]> dbt`
  `0 0x400756 sp: 0x0 0 [main] main entry.init0+38`
  `[0x00400756]> dr`
  `rax = 0x00400756`
  `rbx = 0x004008f0`
  `rcx = 0x7f53c8443738`
  `rdx = 0x7ffcee042568`
  `r8 = 0x00000000`
  `r9 = 0x7f53c84731f0`
  `r10 = 0xfffffffffffffb8c`
  `r11 = 0x7f53c829c730`
  `r12 = 0x00400660`
  `r13 = 0x00000000`
  `r14 = 0x00000000`
  `r15 = 0x00000000`
  `rsi = 0x7ffcee042558`
  `rdi = 0x00000001`
  `rsp = 0x7ffcee042468`
  `rbp = 0x00000000`
  `rip = 0x00400756`
  `rflags = 0x00000246`
  `orax = 0xffffffffffffffff`
 
      

同时,r2可以通过插件实现反编译功能,使用r2pm -l命令查看当前插件,r2的插件有很多,这里使用r2dec反编译插件来实现对程序的反编译,r2pm -install r2dec来安装,安装完成后可以直接在r2中使用-A加载程序,然后使用r2dec反汇编程序,反汇编的命令是pdda


        
  `$ r2 -A ./e3dd9674429f4ce1a25c08ea799fc027`
  `[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.`
  `[0x00400660]> s main`
  `[0x00400756]> pdda`
  `; assembly | /* r2dec pseudo code output */`
  `| /* ./e3dd9674429f4ce1a25c08ea799fc027 @ 0x400756 */`
  `| #include <stdint.h>`
  `|` 
  `; (fcn) main () | int32_t main (void) {`
  `| int64_t var_40h;`
  `| int64_t var_3ch;`
  `| file* stream;`
  `| char * filename;`
  `| int64_t var_28h;`
  `| int64_t var_24h;`
  `| int64_t canary;`
  `0x00400756 push rbp |` 
  `0x00400757 mov rbp, rsp |` 
  `0x0040075a push rbx |` 
  `0x0040075b sub rsp, 0x38 |` 
  `0x0040075f mov rax, qword fs:[0x28] | rax = *(fs:0x28);`
  `0x00400768 mov qword [rbp - 0x18], rax | *((rbp - 0x18)) = rax;`
  `0x0040076c xor eax, eax | eax = 0;`
  `0x0040076e mov dword [rbp - 0x40], 0 | *((rbp - 0x40)) = 0;`
  `| do {`
  `0x00400775 mov eax, dword [rbp - 0x40] | eax = *((rbp - 0x40));`
  `0x00400778 movsxd rbx, eax | rbx = (int64_t) eax;`
  `0x0040077b mov edi, 0x6010a0 |` 
  `0x00400780 call 0x4005e0 | rax = strlen ("c61b68366edeb7bdce3c6820314b7498");`
  `0x00400785 cmp rbx, rax |` 
  `| if (rbx >= rax) {`
  `0x00400788 jae 0x4007c7 | goto label_0;`
  `| }`
  `0x0040078a mov eax, dword [rbp - 0x40] | eax = *((rbp - 0x40));`
  `0x0040078d lea edx, [rax + 0xa] | edx = rax + 0xa;`
  `0x00400790 mov eax, dword [rbp - 0x40] | eax = *((rbp - 0x40));`
  `0x00400793 cdqe | rax = (int64_t) eax;`
  `0x00400795 movzx eax, byte [rax + 0x6010a0] | eax = *((rax + obj.s));`
  `0x0040079c mov ecx, eax | ecx = eax;`
  `0x0040079e mov eax, dword [rbp - 0x40] | eax = *((rbp - 0x40));`
  `0x004007a1 and eax, 1 | eax &= 1;`
  `0x004007a4 test eax, eax |` 
  `| if (eax != 0) {`
  `0x004007a6 je 0x4007af |` 
  `0x004007a8 mov eax, 1 | eax = 1;`
  `0x004007ad jmp 0x4007b4 |` 
  `| } else {`
  `0x004007af mov eax, 0xffffffff | eax = 0xffffffff;`
  `| }`
  `0x004007b4 add eax, ecx | eax += ecx;`
  `0x004007b6 mov ecx, eax | ecx = eax;`
  `0x004007b8 movsxd rax, edx | rax = (int64_t) edx;`
  `0x004007bb mov byte [rax + 0x6010e0], cl | *((rax + obj.t)) = cl;`
  `0x004007c1 add dword [rbp - 0x40], 1 | *((rbp - 0x40))++;`
  `0x004007c5 jmp 0x400775 |` 
  `| } while (1);`
  `| label_0:`
  `0x004007c7 movabs rax, 0x616c662f706d742f | rax = 0x616c662f706d742f;`
  `0x004007d1 mov qword [rbp - 0x30], rax | *((rbp - 0x30)) = rax;`
  `0x004007d5 mov dword [rbp - 0x28], 0x78742e67 | *((rbp - 0x28)) = 0x78742e67;`
  `0x004007dc mov word [rbp - 0x24], 0x74 | *((rbp - 0x24)) = 0x74;`
  `0x004007e2 lea rax, [rbp - 0x30] | rax = rbp - 0x30;`
  `0x004007e6 mov esi, 0x400974 |` 
  `0x004007eb mov rdi, rax |` 
  `0x004007ee call 0x400650 | rax = fopen (rax, 0x400974);`
  `0x004007f3 mov qword [rbp - 0x38], rax | *((rbp - 0x38)) = rax;`
  `0x004007f7 mov rax, qword [rbp - 0x38] | rax = *((rbp - 0x38));`
  `0x004007fb mov edx, 0x601120 | edx = "*******************************************";`
  `0x00400800 mov esi, 0x400976 |` 
  `0x00400805 mov rdi, rax |` 
  `0x00400808 mov eax, 0 | eax = 0;`
  `0x0040080d call 0x400620 | fprintf (rax, 0x400976);`
  `0x00400812 mov dword [rbp - 0x3c], 0 | *((rbp - 0x3c)) = 0;`
  `| do {`
  `0x00400819 mov eax, dword [rbp - 0x3c] | eax = *((rbp - 0x3c));`
  `0x0040081c movsxd rbx, eax | rbx = (int64_t) eax;`
  `0x0040081f mov edi, 0x6010e0 |` 
  `0x00400824 call 0x4005e0 | rax = strlen ("SharifCTF{????????????????????????????????}");`
  `0x00400829 cmp rbx, rax |` 
  `| if (rbx >= rax) {`
  `0x0040082c jae 0x4008b5 | goto label_1;`
  `| }`
  `0x00400832 mov eax, dword [rbp - 0x3c] | eax = *((rbp - 0x3c));`
  `0x00400835 cdqe | rax = (int64_t) eax;`
  `0x00400837 mov eax, dword [rax*4 + 0x601160] | eax = *((rax*4 + obj.p));`
  `0x0040083e movsxd rcx, eax | rcx = (int64_t) eax;`
  `0x00400841 mov rax, qword [rbp - 0x38] | rax = *((rbp - 0x38));`
  `0x00400845 mov edx, 0 |` 
  `0x0040084a mov rsi, rcx |` 
  `0x0040084d mov rdi, rax |` 
  `0x00400850 call 0x400640 | fseek (rax, rcx, 0);`
  `0x00400855 mov eax, dword [rbp - 0x3c] | eax = *((rbp - 0x3c));`
  `0x00400858 cdqe | rax = (int64_t) eax;`
  `0x0040085a mov eax, dword [rax*4 + 0x601160] | eax = *((rax*4 + obj.p));`
  `0x00400861 cdqe | rax = (int64_t) eax;`
  `0x00400863 movzx eax, byte [rax + 0x6010e0] | eax = *((rax + obj.t));`
  `0x0040086a movsx eax, al | eax = (int32_t) al;`
  `0x0040086d mov rdx, qword [rbp - 0x38] | rdx = *((rbp - 0x38));`
  `0x00400871 mov rsi, rdx |` 
  `0x00400874 mov edi, eax |` 
  `0x00400876 call 0x400600 | fputc (eax, *((rbp - 0x38)));`
  `0x0040087b mov rax, qword [rbp - 0x38] | rax = *((rbp - 0x38));`
  `0x0040087f mov edx, 0 | edx = 0;`
  `0x00400884 mov esi, 0 |` 
  `0x00400889 mov rdi, rax |` 
  `0x0040088c call 0x400640 | fseek (rax, 0, edx);`
  `0x00400891 mov rax, qword [rbp - 0x38] | rax = *((rbp - 0x38));`
  `0x00400895 mov edx, 0x601120 | edx = "*******************************************";`
  `0x0040089a mov esi, 0x400976 |` 
  `0x0040089f mov rdi, rax |` 
  `0x004008a2 mov eax, 0 | eax = 0;`
  `0x004008a7 call 0x400620 | fprintf (rax, 0x400976);`
  `0x004008ac add dword [rbp - 0x3c], 1 | *((rbp - 0x3c))++;`
  `0x004008b0 jmp 0x400819 |` 
  `| } while (1);`
  `| label_1:`
  `0x004008b5 mov rax, qword [rbp - 0x38] | rax = *((rbp - 0x38));`
  `0x004008b9 mov rdi, rax |` 
  `0x004008bc call 0x4005d0 | fclose (*((rbp - 0x38)));`
  `0x004008c1 lea rax, [rbp - 0x30] | rax = rbp - 0x30;`
  `0x004008c5 mov rdi, rax |` 
  `0x004008c8 call 0x4005c0 | remove (rax);`
  `0x004008cd mov eax, 0 | eax = 0;`
  `0x004008d2 mov rbx, qword [rbp - 0x18] | rbx = *((rbp - 0x18));`
  `0x004008d6 xor rbx, qword fs:[0x28] | rbx ^= *(fs:0x28);`
  `| if (*((rbp - 0x3c)) != 0) {`
  `0x004008df je 0x4008e6 |` 
  `0x004008e1 call 0x4005f0 | stack_chk_fail ();`
  `| }`
  `0x004008e6 add rsp, 0x38 |` 
  `0x004008ea pop rbx |` 
  `0x004008eb pop rbp |` 
  `0x004008ec ret | return rax;`
  `| }`
 
      

这样可以清晰的对比观察汇编代码和反编译后的伪代码,更方便观察。

radare2还有很多插件可以使用,大家有兴趣的话可以在深入研究一下。

0x04 题目实例

getit这是攻防世界的一道re题,这道题拿到手是个elf文件,我首先是放到ida里看了看伪代码


        
  `int __cdecl main(int argc, const char **argv, const char **envp)`
  `{`
  `char v3; // al`
  `int i; // [rsp+0h] [rbp-40h]`
  `int j; // [rsp+4h] [rbp-3Ch]`
  `FILE *stream; // [rsp+8h] [rbp-38h]`
  `char filename[24]; // [rsp+10h] [rbp-30h] BYREF`
  `unsigned __int64 v9; // [rsp+28h] [rbp-18h]`
 
  `v9 = __readfsqword(0x28u);`
  `for ( i = 0; i < strlen(s); ++i )`
  `{`
  `if ( (i & 1) != 0 )`
  `v3 = 1;`
  `else`
  `v3 = -1;`
  `*(&t + i + 10) = s[i] + v3;`
  `}`
  `strcpy(filename, "/tmp/flag.txt");`
  `stream = fopen(filename, "w");`
  `fprintf(stream, "%s\n", u);`
  `for ( j = 0; j < strlen(&t); ++j )`
  `{`
  `fseek(stream, p[j], 0);`
  `fputc(*(&t + p[j]), stream);`
  `fseek(stream, 0LL, 0);`
  `fprintf(stream, "%s\n", u);`
  `}`
  `fclose(stream);`
  `remove(filename);`
  `return 0;`
  `}`
 
      

本来这道题目应该是写逆向算法得到flag,但是经过分析和与反汇编代码对比,发现flag应该是被存在了eax里面

picture.image

在调试程序的时候,我们可以ida配合gdb来说使用,虽然ida本身也有动态调试的功能,但是我推荐用ida来分析反汇编和伪代码,然后通过gdb或者r2来进行动态调试查看寄存器的值,或者使用r2反编译和反汇编代码对比分析,这样就可以方便不少,这里猜测flag应该存在eax中,可以通过gdb动态调试程序,在0x400832处下断点,让程序运行

picture.image

运行程序到断点处,查看寄存器存储的地址的值,就能得到flag

picture.image

这样通过动态调试的方式,省了很多事。

0x05 总结

本文简单介绍了ida、gdb和r2动态调试二进制文件的方法,也是自己最近在做ctf题目的时候使用的,之前只会用od和ida,使用gdb和r2很少,正好借此机会也学习了一下,对于我这种菜鸡来说,在分析二进制文件的时候,3种工具一起使用效果会好一些。


        
            

          参考文章:https://wizardforcel.gitbooks.io/100-gdb-tips/content/print-registers.htmlhttps://linuxtools-rst.readthedocs.io/zh\_CN/latest/tool/gdb.htmlhttps://linux.cn/article-13074-1.htm
        
      

如有侵权,请联系删除

推荐阅读

实战|记一次奇妙的文件上传getshell

「 超详细 | 分享 」手把手教你如何进行内网渗透

神兵利器 | siusiu-渗透工具管理套件

一款功能全面的XSS扫描器

实战 | 一次利用哥斯拉马绕过宝塔waf

BurpCrypto: 万能网站密码爆破测试工具

快速筛选真实IP并整理为C段 -- 棱眼

自动探测端口顺便爆破工具t14m4t

渗透工具|无状态子域名爆破工具(1秒扫160万个子域)

查看更多精彩内容,还请关注 橘猫学安全:

每日坚持学习与分享,觉得文章对你有帮助可在底部给点个“ 再看

0
0
0
0
关于作者

文章

0

获赞

0

收藏

0

相关资源
边缘云原生操作系统设计与思考
《火山引擎边缘云原生操作系统设计与思考》 徐广治 | 火山引擎边缘云资深架构师
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论