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

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

0x01 ida动态调试

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

首先将ida/dbgsrv/路径下的linux_server/linux_serverx64文件复制到linux下,两个文件分别是调试32位和64位程序使用的:
在linux下启动对应的文件:
把我们要调试的文件放到相应的文件夹中,这里我放到/homt/test/文件夹中。
在ida中选择Debugger-Run-Remote linux debugger
在弹出的对话框中,Application填写文件存放的位置和文件名,Directory中填写文件存放的路径,Parameters是指传递的参数,如果程序运行需要传参的话可以在这填入,Hostname就是linux的ip地址,Port一般都是默认的23946,如果设置了password在下方填入,没有就空着:
进入ida动态调试界面,默认情况下界面大概分为6个区域(通用寄存器和标志寄存器窗口为1个),模块列表和线程列表我不怎么看,主要是看反汇编和寄存器还有堆栈。

ida在动态调试的时候和OD差不多,F9继续运行,F7步入,F8步过,F2下断点。
通过Debugger-Breakpoints-Breakpoint list或者Ctrl+Alt+B来查看已经下的断点:
也可以通过Debugger-Debugger windows-Stack trace或者Ctrl+Alt+S查看是谁调用了当前的函数:
虽然感觉没有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,设置断点infobreakpoints:简写为info b,查看断点delete*address:删除断点disable*address:暂停断点enable*address:开启断点deletebreakpoints:删除所有断点
查看
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 functioncalls (aac)[x] Analyzelenbytesofinstructionsforreferences (aar)[x] Checkforvtables[x] Typematchinganalysisforallfunctions (aaft)[x] Propagatenoreturninformation[x] Use -AAoraaaatoperformadditionalexperimentalanalysis.
也可以直接使用r2 -A ./program来直接分析程序
$ r2 -A ./e3dd9674429f4ce1a25c08ea799fc027 [x] Analyzeall flags startingwith sym. and entry0 (aa)[x] Analyzefunction calls (aac)[x] Analyzelenbytesof instructions forreferences (aar)[x] Checkfor vtables[x] Type matching analysis forall functions (aaft)[x] Propagate noreturn information[x] Use -AA or aaaa to perform additional experimental analysis.
在分析程序之前,r2的iI命令可以提供很多有用的信息
[0x00400660]>iIarchx86baddr0x400000binsz9449bintypeelfbits64canarytrueclassELF64compilerGCC: (Ubuntu 5.4.1-2ubuntu1~14.04) 5.4.1 20160904 GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4cryptofalseendianlittlehavecodetrueintrp/lib64/ld-linux-x86-64.so.2laddr0x0langclinenumtruelsymstruemachineAMD x86-64 architecturemaxopsz16minopsz1nxtrueoslinuxpcalign0picfalserelocstruerelropartialrpathNONEsanitizfalsestaticfalsestrippedfalsesubsyslinuxvatrue
在了解程序的基本信息后你还可以通过iiiE命令来看下程序的导入和导出函数,从而能够更好的了解程序实现的功能
[0x00400660]>ii[Imports]nthvaddr bind type lib name―――――――――――――――――――――――――――――――――――――10x004005c0 GLOBAL FUNC remove20x004005d0 GLOBAL FUNC fclose30x004005e0 GLOBAL FUNC strlen40x004005f0 GLOBAL FUNC __stack_chk_fail50x00400600 GLOBAL FUNC fputc60x00400610 GLOBAL FUNC __libc_start_main70x00400620 GLOBAL FUNC fprintf80x00400630 WEAK NOTYPE __gmon_start__90x00400640 GLOBAL FUNC fseek100x00400650 GLOBAL FUNC fopen[0x00400660]>iE[Exports]nthpaddr vaddr bind type size lib name――――――――――――――――――――――――――――――――――――――――――――――――――――――450x00000960 0x00400960 GLOBAL FUNC 2 __libc_csu_fini490x000010e0 0x006010e0 GLOBAL OBJ 44 t50---------- 0x0060120c GLOBAL NOTYPE 0 _edata510x00001160 0x00601160 GLOBAL OBJ 172 p530x00000964 0x00400964 GLOBAL FUNC 0 _fini580x00001080 0x00601080 GLOBAL NOTYPE 0 __data_start610x00001088 0x00601088 GLOBAL OBJ 0 __dso_handle620x00000970 0x00400970 GLOBAL OBJ 4 _IO_stdin_used630x000008f0 0x004008f0 GLOBAL FUNC 101 __libc_csu_init64---------- 0x00601210 GLOBAL NOTYPE 0 _end650x00000660 0x00400660 GLOBAL FUNC 0 _start670x000010a0 0x006010a0 GLOBAL OBJ 33 s680x00001120 0x00601120 GLOBAL OBJ 44 u69---------- 0x0060120c GLOBAL NOTYPE 0 __bss_start700x00000756 0x00400756 GLOBAL FUNC 407 main73---------- 0x00601210 GLOBAL OBJ 0 __TMC_END__750x00000590 0x00400590 GLOBAL FUNC 0 _init
你还可以通过afl命令查看程序存在的函数,从而找到main函数,定位到对应的位置,查看反汇编代码
[0x00400660]> afl0x00400660 1 41 entry00x00400610 1 6 sym.imp.__libc_start_main0x00400690 4 50 -> 41 sym.deregister_tm_clones0x004006d0 4 58 -> 55 sym.register_tm_clones0x00400710 3 28 sym.__do_global_dtors_aux0x00400730 4 38 -> 35 entry.init00x00400960 1 2 sym.__libc_csu_fini0x00400964 1 9 sym._fini0x004008f0 4 101 sym.__libc_csu_init0x00400756 12 407 main0x00400590 3 26 sym._init0x00400630 1 6 loc.imp.__gmon_start__0x004005c0 1 6 sym.imp.remove0x004005d0 1 6 sym.imp.fclose0x004005e0 1 6 sym.imp.strlen0x004005f0 1 6 sym.imp.__stack_chk_fail0x00400600 1 6 sym.imp.fputc0x00400620 1 6 sym.imp.fprintf0x00400640 1 6 sym.imp.fseek0x00400650 1 6 sym.imp.fopen
在找到程序内存在的函数后,可以使用axt命令来查看函数调用
[0x00400660]> axtmainentry0 0x40067d[DATA]movrdi, main
在找到main函数后,使用s命令定位到main函数,pdf命令来查看函数的反汇编代码,s命令后可以加地址或者函数名
[0x00400660]> s main[0x00400756]> pdf ; DATA XREF from entry0 @ 0x40067d407: intmain (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│ ; varchar *filename @ rbp-0x30│ ; var int64_t var_28h @ rbp-0x28│ ; var int64_t var_24h @ rbp-0x24│ ; var int64_t canary @ rbp-0x180x0040075655 push rbp0x004007574889e5 mov rbp, rsp0x0040075a53 push rbx0x0040075b4883ec38 sub rsp, 0x380x0040075f64488b042528. mov rax, qword fs:[0x28]0x00400768488945e8 mov qword [canary], rax0x0040076c31c0 xor eax, eax0x0040076e c745c0000000. mov dword [var_40h], 0│ ; CODE XREF from main @ 0x4007c5│ ┌─> 0x004007758b45c0 mov eax, dword [var_40h]│ ╎ 0x004007784863d8 movsxd rbx, eax│ ╎ 0x0040077b bfa0106000 mov edi, obj.s ; 0x6010a0 ; "c61b68366edeb7bdce3c6820314b7498" ; constchar *s│ ╎ 0x00400780 e85bfeffff call sym.imp.strlen ; size_t strlen(constchar *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"│ │╎ 0x0040079c89c1 mov ecx, eax│ │╎ 0x0040079e8b45c0 mov eax, dword [var_40h]│ │╎ 0x004007a183e001 and eax, 1│ │╎ 0x004007a485c0 test eax, eax│ ┌───< 0x004007a67407 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│ └────> 0x004007b401c8 add eax, ecx│ │╎ 0x004007b689c1 mov ecx, eax│ │╎ 0x004007b84863c2 movsxd rax, edx│ │╎ 0x004007bb8888e0106000 mov byte [rax + obj.t], cl ; [0x6010e0:1]=83 ; "SharifCTF{????????????????????????????????}"│ │╎ 0x004007c18345c001 add dword [var_40h], 1│ │└─< 0x004007c5 ebae jmp 0x400775│ │ ; CODE XREF from main @ 0x400788│ └──> 0x004007c748b82f746d70. movabs rax, 0x616c662f706d742f ; '/tmp/fla'0x004007d1488945d0 mov qword [filename], rax0x004007d5 c745d8672e74. mov dword [var_28h], 0x78742e67 ; 'g.tx'0x004007dc66c745dc7400 mov word [var_24h], 0x74 ; 't' ; 1160x004007e2488d45d0 lea rax, [filename]0x004007e6 be74094000 mov esi, 0x400974 ; constchar *mode0x004007eb4889c7 mov rdi, rax ; constchar *filename0x004007ee e85dfeffff call sym.imp.fopen ; file*fopen(constchar *filename, constchar *mode)0x004007f3488945c8 mov qword [stream], rax0x004007f7488b45c8 mov rax, qword [stream]0x004007fb ba20116000 mov edx, obj.u ; 0x601120 ; "*******************************************" ; ...0x00400800 be76094000 mov esi, 0x400976 ; constchar *format0x004008054889c7 mov rdi, rax ; FILE *stream0x00400808 b800000000 mov eax, 00x0040080d e80efeffff call sym.imp.fprintf ; intfprintf(FILE *stream, constchar *format, ...)│ 0x00400812 c745c4000000. mov dword [var_3ch], 0 ; CODE XREF from main @ 0x4008b0│ ┌─> 0x004008198b45c4 mov eax, dword [var_3ch]│ ╎ 0x0040081c4863d8 movsxd rbx, eax│ ╎ 0x0040081f bfe0106000 mov edi, obj.t ; 0x6010e0 ; "SharifCTF{????????????????????????????????}" ; constchar *s│ ╎ 0x00400824 e8b7fdffff call sym.imp.strlen ; size_t strlen(constchar *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│ │╎ 0x0040083e4863c8 movsxd rcx, eax│ │╎ 0x00400841488b45c8 mov rax, qword [stream]│ │╎ 0x00400845 ba00000000 mov edx, 0 ; int whence│ │╎ 0x0040084a4889ce mov rsi, rcx ; long offset│ │╎ 0x0040084d4889c7 mov rdi, rax ; FILE *stream│ │╎ 0x00400850 e8ebfdffff call sym.imp.fseek ; intfseek(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│ │╎ 0x004008614898 cdqe│ │╎ 0x004008630fb680e01060. movzx eax, byte [rax + obj.t] ; [0x6010e0:1]=83 ; "SharifCTF{????????????????????????????????}"│ │╎ 0x0040086a0fbec0 movsx eax, al│ │╎ 0x0040086d488b55c8 mov rdx, qword [stream]│ │╎ 0x004008714889d6 mov rsi, rdx ; FILE *stream│ │╎ 0x0040087489c7 mov edi, eax ; int c│ │╎ 0x00400876 e885fdffff call sym.imp.fputc ; intfputc(int c, FILE *stream)│ │╎ 0x0040087b 488b45c8 mov rax, qword [stream]│ │╎ 0x0040087f ba00000000 mov edx, 0 ; int whence│ │╎ 0x00400884 be00000000 mov esi, 0 ; long offset│ │╎ 0x004008894889c7 mov rdi, rax ; FILE *stream│ │╎ 0x0040088c e8affdffff call sym.imp.fseek ; intfseek(FILE *stream, long offset, int whence)│ │╎ 0x00400891 488b45c8 mov rax, qword [stream]│ │╎ 0x00400895 ba20116000 mov edx, obj.u ; 0x601120 ; "*******************************************" ; ...│ │╎ 0x0040089a be76094000 mov esi, 0x400976 ; constchar *format│ │╎ 0x0040089f4889c7 mov rdi, rax ; FILE *stream│ │╎ 0x004008a2 b800000000 mov eax, 0│ │╎ 0x004008a7 e874fdffff call sym.imp.fprintf ; intfprintf(FILE *stream, constchar *format, ...)│ │╎ 0x004008ac 8345c401 add dword [var_3ch], 1│ │└─< 0x004008b0 e964ffffff jmp 0x400819│ │ ; CODE XREF from main @ 0x40082c│ └──> 0x004008b5488b45c8 mov rax, qword [stream]0x004008b94889c7 mov rdi, rax ; FILE *stream0x004008bc e80ffdffff call sym.imp.fclose ; intfclose(FILE *stream)│ 0x004008c1 488d45d0 lea rax, [filename]│ 0x004008c5 4889c7 mov rdi, rax ; constchar *filename0x004008c8 e8f3fcffff call sym.imp.remove ; intremove(constchar *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│ └─> 0x004008e64883c438 add rsp, 0x380x004008ea5b pop rbx0x004008eb5d pop rbp0x004008ec c3 ret
如果觉得看反汇编不过瘾也可以通过px命令查看十六进制内容
[0x00400756]>px-offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF0x004007565548 89e5 5348 83ec 3864 488b 0425 2800 UH..SH..8dH..%(. 0x004007660000 4889 45e8 31c0 c745 c000 0000 008b ..H.E.1..E......0x0040077645c0 4863 d8bf a010 6000 e85b feff ff48 E.Hc....`..[...H0x0040078639c3 733d 8b45 c08d 500a 8b45 c048 980f 9.s=.E..P..E.H..0x00400796b680 a010 6000 89c1 8b45 c083 e001 85c0 ....`....E......0x004007a67407 b801 0000 00eb 05b8 ffff ffff 01c8 t...............0x004007b689c1 4863 c288 88e0 1060 0083 45c0 01eb ..Hc.....`..E...0x004007c6ae48 b82f 746d 702f 666c 6148 8945 d0c7 .H./tmp/flaH.E..0x004007d645d8 672e 7478 66c7 45dc 7400 488d 45d0 E.g.txf.E.t.H.E.0x004007e6be74 0940 0048 89c7 e85d feff ff48 8945 [email protected]...]...H.E0x004007f6c848 8b45 c8ba 2011 6000 be76 0940 0048 .H.E.. .`[email protected]0x0040080689c7 b800 0000 00e8 0efe ffff c745 c400 .............E..0x004008160000 008b 45c4 4863 d8bf e010 6000 e8b7 ....E.Hc....`...0x00400826fdff ff48 39c3 0f83 8300 0000 8b45 c448 ...H9........E.H0x00400836988b 0485 6011 6000 4863 c848 8b45 c8ba ....`.`.Hc.H.E..0x004008460000 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 c61b68366edeb7bdce3c6820314b74981 0x000010e0 0x006010e0 43 44 .data ascii SharifCTF{????????????????????????????????}2   0x00001120 0x00601120 43  44   .data   ascii *******************************************
字符串和函数一样,可以使用axt命令查看是哪里把它打印出来的
[0x00400756]> axt 0x6010a0main 0x40077b[DATA]movedi, obj.smain 0x400795[DATA]movzxeax, byte[rax + obj.s]
r2还提供了可视模式,可以更直观的分析函数的调用,vv命令进入
以上是使用r2静态分析二进制文件,然后r2的功能不止于此,它还可以动态调试二进制文件甚至给我函数的伪代码
使用r2 -d -A ./program命令来进入调试器
$ r2 -d -A ./e3dd9674429f4ce1a25c08ea799fc027[x] Analyzeall flags startingwith sym. and entry0 (aa)[x] Analyzefunction calls (aac)[x] Analyzelenbytesof instructions forreferences (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]> dbi0 0x00400756 E:1 T:0[0x7f53c8464050]> dchit breakpoint at: 0x400756[0x00400756]> dbt0 0x400756 sp: 0x0 0 [main] main entry.init0+38[0x00400756]> drrax = 0x00400756rbx = 0x004008f0rcx = 0x7f53c8443738rdx = 0x7ffcee042568r8 = 0x00000000r9 = 0x7f53c84731f0r10 = 0xfffffffffffffb8cr11 = 0x7f53c829c730r12 = 0x00400660r13 = 0x00000000r14 = 0x00000000r15 = 0x00000000rsi = 0x7ffcee042558rdi = 0x00000001rsp = 0x7ffcee042468rbp = 0x00000000rip = 0x00400756rflags = 0x00000246orax = 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;0x00400756push rbp | 0x00400757mov rbp, rsp | 0x0040075apush rbx | 0x0040075bsub rsp, 0x38 | 0x0040075fmov rax, qword fs:[0x28] | rax = *(fs:0x28);0x00400768mov qword [rbp - 0x18], rax | *((rbp - 0x18)) = rax;0x0040076cxor eax, eax | eax = 0;0x0040076emov dword [rbp - 0x40], 0 | *((rbp - 0x40)) = 0;|do {0x00400775mov eax, dword [rbp - 0x40] | eax = *((rbp - 0x40));0x00400778movsxd rbx, eax | rbx = (int64_t) eax;0x0040077bmov edi, 0x6010a0 | 0x00400780call 0x4005e0 | rax = strlen ("c61b68366edeb7bdce3c6820314b7498");0x00400785cmp rbx, rax | |if (rbx >= rax) {0x00400788jae 0x4007c7 | goto label_0;|}0x0040078amov eax, dword [rbp - 0x40] | eax = *((rbp - 0x40));0x0040078dlea edx, [rax + 0xa] | edx = rax + 0xa;0x00400790mov eax, dword [rbp - 0x40] | eax = *((rbp - 0x40));0x00400793cdqe | rax = (int64_t) eax;0x00400795movzx eax, byte [rax + 0x6010a0] | eax = *((rax + obj.s));0x0040079cmov ecx, eax | ecx = eax;0x0040079emov eax, dword [rbp - 0x40] | eax = *((rbp - 0x40));0x004007a1and eax, 1 | eax &= 1;0x004007a4test eax, eax | |if (eax != 0) {0x004007a6je 0x4007af | 0x004007a8mov eax, 1 | eax = 1;0x004007adjmp 0x4007b4 | |} else {0x004007afmov eax, 0xffffffff | eax = 0xffffffff;|}0x004007b4add eax, ecx | eax += ecx;0x004007b6mov ecx, eax | ecx = eax;0x004007b8movsxd rax, edx | rax = (int64_t) edx;0x004007bbmov byte [rax + 0x6010e0], cl | *((rax + obj.t)) = cl;0x004007c1add dword [rbp - 0x40], 1 | *((rbp - 0x40))++;0x004007c5jmp 0x400775 | |} while (1);|label_0:0x004007c7movabs rax, 0x616c662f706d742f | rax = 0x616c662f706d742f;0x004007d1mov qword [rbp - 0x30], rax | *((rbp - 0x30)) = rax;0x004007d5mov dword [rbp - 0x28], 0x78742e67 | *((rbp - 0x28)) = 0x78742e67;0x004007dcmov word [rbp - 0x24], 0x74 | *((rbp - 0x24)) = 0x74;0x004007e2lea rax, [rbp - 0x30] | rax = rbp - 0x30;0x004007e6mov esi, 0x400974 | 0x004007ebmov rdi, rax | 0x004007eecall 0x400650 | rax = fopen (rax, 0x400974);0x004007f3mov qword [rbp - 0x38], rax | *((rbp - 0x38)) = rax;0x004007f7mov rax, qword [rbp - 0x38] | rax = *((rbp - 0x38));0x004007fbmov edx, 0x601120 | edx = "*******************************************";0x00400800mov esi, 0x400976 | 0x00400805mov rdi, rax | 0x00400808mov eax, 0 | eax = 0;0x0040080dcall 0x400620 | fprintf (rax, 0x400976);0x00400812mov dword [rbp - 0x3c], 0 | *((rbp - 0x3c)) = 0;|do {0x00400819mov eax, dword [rbp - 0x3c] | eax = *((rbp - 0x3c));0x0040081cmovsxd rbx, eax | rbx = (int64_t) eax;0x0040081fmov edi, 0x6010e0 | 0x00400824call 0x4005e0 | rax = strlen ("SharifCTF{????????????????????????????????}");0x00400829cmp rbx, rax | |if (rbx >= rax) {0x0040082cjae 0x4008b5 | goto label_1;|}0x00400832mov eax, dword [rbp - 0x3c] | eax = *((rbp - 0x3c));0x00400835cdqe | rax = (int64_t) eax;0x00400837mov eax, dword [rax*4 + 0x601160] | eax = *((rax*4 + obj.p));0x0040083emovsxd rcx, eax | rcx = (int64_t) eax;0x00400841mov rax, qword [rbp - 0x38] | rax = *((rbp - 0x38));0x00400845mov edx, 0 | 0x0040084amov rsi, rcx | 0x0040084dmov rdi, rax | 0x00400850call 0x400640 | fseek (rax, rcx, 0);0x00400855mov eax, dword [rbp - 0x3c] | eax = *((rbp - 0x3c));0x00400858cdqe | rax = (int64_t) eax;0x0040085amov eax, dword [rax*4 + 0x601160] | eax = *((rax*4 + obj.p));0x00400861cdqe | rax = (int64_t) eax;0x00400863movzx eax, byte [rax + 0x6010e0] | eax = *((rax + obj.t));0x0040086amovsx eax, al | eax = (int32_t) al;0x0040086dmov rdx, qword [rbp - 0x38] | rdx = *((rbp - 0x38));0x00400871mov rsi, rdx | 0x00400874mov edi, eax | 0x00400876call 0x400600 | fputc (eax, *((rbp - 0x38)));0x0040087bmov rax, qword [rbp - 0x38] | rax = *((rbp - 0x38));0x0040087fmov edx, 0 | edx = 0;0x00400884mov esi, 0 | 0x00400889mov rdi, rax | 0x0040088ccall 0x400640 | fseek (rax, 0, edx);0x00400891mov rax, qword [rbp - 0x38] | rax = *((rbp - 0x38));0x00400895mov edx, 0x601120 | edx = "*******************************************";0x0040089amov esi, 0x400976 | 0x0040089fmov rdi, rax | 0x004008a2mov eax, 0 | eax = 0;0x004008a7call 0x400620 | fprintf (rax, 0x400976);0x004008acadd dword [rbp - 0x3c], 1 | *((rbp - 0x3c))++;0x004008b0jmp 0x400819 | |} while (1);|label_1:0x004008b5mov rax, qword [rbp - 0x38] | rax = *((rbp - 0x38));0x004008b9mov rdi, rax | 0x004008bccall 0x4005d0 | fclose (*((rbp - 0x38)));0x004008c1lea rax, [rbp - 0x30] | rax = rbp - 0x30;0x004008c5mov rdi, rax | 0x004008c8call 0x4005c0 | remove (rax);0x004008cdmov eax, 0 | eax = 0;0x004008d2mov rbx, qword [rbp - 0x18] | rbx = *((rbp - 0x18));0x004008d6xor rbx, qword fs:[0x28] | rbx ^= *(fs:0x28);|if (*((rbp - 0x3c)) != 0) {0x004008dfje 0x4008e6 | 0x004008e1call 0x4005f0 | stack_chk_fail ();|}0x004008e6add rsp, 0x38 | 0x004008eapop rbx | 0x004008ebpop rbp | 0x004008ecret | return rax;|}
这样可以清晰的对比观察汇编代码和反编译后的伪代码,更方便观察。
radare2还有很多插件可以使用,大家有兴趣的话可以在深入研究一下。

0x04 题目实例

getit这是攻防世界的一道re题,这道题拿到手是个elf文件,我首先是放到ida里看了看伪代码
int __cdecl main(int argc, constchar **argv, constchar **envp){char v3; // alint i; // [rsp+0h] [rbp-40h]int j; // [rsp+4h] [rbp-3Ch] FILE *stream; // [rsp+8h] [rbp-38h]char filename[24]; // [rsp+10h] [rbp-30h] BYREFunsigned __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);return0;}
本来这道题目应该是写逆向算法得到flag,但是经过分析和与反汇编代码对比,发现flag应该是被存在了eax里面
在调试程序的时候,我们可以ida配合gdb来说使用,虽然ida本身也有动态调试的功能,但是我推荐用ida来分析反汇编和伪代码,然后通过gdb或者r2来进行动态调试查看寄存器的值,或者使用r2反编译和反汇编代码对比分析,这样就可以方便不少,这里猜测flag应该存在eax中,可以通过gdb动态调试程序,在0x400832处下断点,让程序运行
运行程序到断点处,查看寄存器存储的地址的值,就能得到flag
这样通过动态调试的方式,省了很多事。

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.html
E
N
D
Tide安全团队正式成立于2019年1月,是新潮信息旗下以互联网攻防技术研究为目标的安全团队,团队致力于分享高质量原创文章、开源安全工具、交流安全技术,研究方向覆盖网络攻防、系统安全、Web安全、移动终端、安全开发、物联网/工控安全/AI安全等多个领域。
团队作为“省级等保关键技术实验室”先后与哈工大、齐鲁银行、聊城大学、交通学院等多个高校名企建立联合技术实验室。团队公众号自创建以来,共发布原创文章370余篇,自研平台达到26个,目有15个平台已开源。此外积极参加各类线上、线下CTF比赛并取得了优异的成绩。如有对安全行业感兴趣的小伙伴可以踊跃加入或关注我们
继续阅读
阅读原文