动态调试elf文件的几种方法
动态调试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
命令可以提供很多有用的信息iI
archx86
baddr0x400000
binsz9449
bintypeelf
bits64
canarytrue
classELF64
compilerGCC: (Ubuntu 5.4.1-2ubuntu1~14.04) 5.4.1 20160904 GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4
cryptofalse
endianlittle
havecodetrue
intrp/lib64/ld-linux-x86-64.so.2
laddr0x0
langc
linenumtrue
lsymstrue
machineAMD x86-64 architecture
maxopsz16
minopsz1
nxtrue
oslinux
pcalign0
picfalse
relocstrue
relropartial
rpathNONE
sanitizfalse
staticfalse
strippedfalse
subsyslinux
vatrue
在了解程序的基本信息后你还可以通过
ii
和iE
命令来看下程序的导入和导出函数,从而能够更好的了解程序实现的功能ii
[Imports]
nthvaddr bind type lib name
―――――――――――――――――――――――――――――――――――――
10x004005c0 GLOBAL FUNC remove
20x004005d0 GLOBAL FUNC fclose
30x004005e0 GLOBAL FUNC strlen
40x004005f0 GLOBAL FUNC __stack_chk_fail
50x00400600 GLOBAL FUNC fputc
60x00400610 GLOBAL FUNC __libc_start_main
70x00400620 GLOBAL FUNC fprintf
80x00400630 WEAK NOTYPE __gmon_start__
90x00400640 GLOBAL FUNC fseek
100x00400650 GLOBAL FUNC fopen
iE
[Exports]
nthpaddr vaddr bind type size lib name
――――――――――――――――――――――――――――――――――――――――――――――――――――――
450x00000960 0x00400960 GLOBAL FUNC 2 __libc_csu_fini
490x000010e0 0x006010e0 GLOBAL OBJ 44 t
50---------- 0x0060120c GLOBAL NOTYPE 0 _edata
510x00001160 0x00601160 GLOBAL OBJ 172 p
530x00000964 0x00400964 GLOBAL FUNC 0 _fini
580x00001080 0x00601080 GLOBAL NOTYPE 0 __data_start
610x00001088 0x00601088 GLOBAL OBJ 0 __dso_handle
620x00000970 0x00400970 GLOBAL OBJ 4 _IO_stdin_used
630x000008f0 0x004008f0 GLOBAL FUNC 101 __libc_csu_init
64---------- 0x00601210 GLOBAL NOTYPE 0 _end
650x00000660 0x00400660 GLOBAL FUNC 0 _start
670x000010a0 0x006010a0 GLOBAL OBJ 33 s
680x00001120 0x00601120 GLOBAL OBJ 44 u
69---------- 0x0060120c GLOBAL NOTYPE 0 __bss_start
700x00000756 0x00400756 GLOBAL FUNC 407 main
73---------- 0x00601210 GLOBAL OBJ 0 __TMC_END__
750x00000590 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]> axtmain
entry0 0x40067d[DATA]movrdi, main
在找到main函数后,使用
s
命令定位到main函数,pdf
命令来查看函数的反汇编代码,s
命令后可以加地址或者函数名[ ]> s main
[ ]> pdf
; DATA XREF from entry0 @ 0x40067d
┌ 407: 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-0x18
│ 0x0040075655 push rbp
│ 0x004007574889e5 mov rbp, rsp
│ 0x0040075a53 push rbx
│ 0x0040075b4883ec38 sub rsp, 0x38
│ 0x0040075f64488b042528. mov rax, qword fs:[0x28]
│ 0x00400768488945e8 mov qword [canary], rax
│ 0x0040076c31c0 xor eax, eax
│ 0x0040076e 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], rax
│ 0x004007d5 c745d8672e74. mov dword [var_28h], 0x78742e67 ; 'g.tx'
│ 0x004007dc66c745dc7400 mov word [var_24h], 0x74 ; 't' ; 116
│ 0x004007e2488d45d0 lea rax, [filename]
│ 0x004007e6 be74094000 mov esi, 0x400974 ; constchar *mode
│ 0x004007eb4889c7 mov rdi, rax ; constchar *filename
│ 0x004007ee e85dfeffff call sym.imp.fopen ; file*fopen(constchar *filename, constchar *mode)
│ 0x004007f3488945c8 mov qword [stream], rax
│ 0x004007f7488b45c8 mov rax, qword [stream]
│ 0x004007fb ba20116000 mov edx, obj.u ; 0x601120 ; "*******************************************" ; ...
│ 0x00400800 be76094000 mov esi, 0x400976 ; constchar *format
│ 0x004008054889c7 mov rdi, rax ; FILE *stream
│ 0x00400808 b800000000 mov eax, 0
│ 0x0040080d 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 *stream
│ 0x004008bc e80ffdffff call sym.imp.fclose ; intfclose(FILE *stream)
│ 0x004008c1 488d45d0 lea rax, [filename]
│ 0x004008c5 4889c7 mov rdi, rax ; constchar *filename
│ 0x004008c8 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, 0x38
│ 0x004008ea5b pop rbx
│ 0x004008eb5d pop rbp
└ 0x004008ec c3 ret
如果觉得看反汇编不过瘾也可以通过
px
命令查看十六进制内容px
offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
0x004007565548 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....`..[...H
0x0040078639c3 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.E
0x004007f6c848 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.H
0x00400836988b 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 c61b68366edeb7bdce3c6820314b7498
1 0x000010e0 0x006010e0 43 44 .data ascii SharifCTF{????????????????????????????????}
2 0x00001120 0x00601120 43 44 .data ascii *******************************************
字符串和函数一样,可以使用axt命令查看是哪里把它打印出来的
[0x00400756]> axt 0x6010a0
main 0x40077b[DATA]movedi, obj.s
main 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]> 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
Analyze all flags starting with sym. and entry0 (aa)
Analyze function calls (aac)
Analyze len bytes of instructions for references (aar)
Check for vtables
Type matching analysis for all functions (aaft)
Propagate noreturn information
Use -AA or aaaa to perform additional experimental analysis.
s main
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; // 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);
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.html
https://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/gdb.html
https://linux.cn/article-13074-1.html
E
N
D
关
于
我
们
Tide安全团队正式成立于2019年1月,是新潮信息旗下以互联网攻防技术研究为目标的安全团队,团队致力于分享高质量原创文章、开源安全工具、交流安全技术,研究方向覆盖网络攻防、系统安全、Web安全、移动终端、安全开发、物联网/工控安全/AI安全等多个领域。
团队作为“省级等保关键技术实验室”先后与哈工大、齐鲁银行、聊城大学、交通学院等多个高校名企建立联合技术实验室。团队公众号自创建以来,共发布原创文章370余篇,自研平台达到26个,目有15个平台已开源。此外积极参加各类线上、线下CTF比赛并取得了优异的成绩。如有对安全行业感兴趣的小伙伴可以踊跃加入或关注我们。
最新评论
推荐文章
作者最新文章
你可能感兴趣的文章
Copyright Disclaimer: The copyright of contents (including texts, images, videos and audios) posted above belong to the User who shared or the third-party website which the User shared from. If you found your copyright have been infringed, please send a DMCA takedown notice to [email protected]. For more detail of the source, please click on the button "Read Original Post" below. For other communications, please send to [email protected].
版权声明:以上内容为用户推荐收藏至CareerEngine平台,其内容(含文字、图片、视频、音频等)及知识版权均属用户或用户转发自的第三方网站,如涉嫌侵权,请通知[email protected]进行信息删除。如需查看信息来源,请点击“查看原文”。如需洽谈其它事宜,请联系[email protected]。
版权声明:以上内容为用户推荐收藏至CareerEngine平台,其内容(含文字、图片、视频、音频等)及知识版权均属用户或用户转发自的第三方网站,如涉嫌侵权,请通知[email protected]进行信息删除。如需查看信息来源,请点击“查看原文”。如需洽谈其它事宜,请联系[email protected]。