它包含如下语句:
movw edx
xc031, 0x(%edx)
,其中objdump
包含语句的地址。使用断点,我可以停止并检查修改后的代码。我将其保存为二进制文件,然后使用gdb
进行反汇编,以查看新的语句。 逐行执行此操作有点慢。是否有更好的方法来反转此代码? q4312079q中可能还有其他我不知道的工具或功能。
#1 楼
只是为了踢一下,我下载了crackme并将其馈送到Windows窗口中的radare中,不需要动态分析即可解决此crackmeradare2方面
将此二进制文件字符串化
[0x080495e0]> iz
vaddr=0x080483d0 paddr=0x000003d0 ordinal=000 sz=41 len=40 section=.rodata type=
a string=run as ./prog a_number (e.g. ./prog 90)\n
vaddr=0x080483f9 paddr=0x000003f9 ordinal=001 sz=7 len=6 section=.rodata type=a
string=good.\n
vaddr=0x08048400 paddr=0x00000400 ordinal=002 sz=6 len=5 section=.rodata type=a
string=bad.\n
因此,该文件似乎采用单个参数作为输入,并根据字符串输出中的某些条件打印好坏
让我们继续前进并查看入口点的内容
[0x080495e0]> pd 14
;-- entry0:
;-- section..text:
0x080495e0 31ed xor ebp, ebp ; [19]
0x080495e2 5e pop esi
0x080495e3 89e1 mov ecx, esp
0x080495e5 83e4f0 and esp, 0xfffffff0
0x080495e8 50 push eax
0x080495e9 54 push esp
0x080495ea 52 push edx
0x080495eb 68a0980408 push 0x80498a0
0x080495f0 6840980408 push 0x8049840
0x080495f5 51 push ecx
0x080495f6 56 push esi
0x080495f7 6850970408 push 0x8049750
0x080495fc e86fedffff call sym.imp.__libc_start_main
^- 0x08048370(unk, unk, unk, unk, unk, unk, unk, unk) ; sym.imp._
0x08049601 f4 hlt
[0x080495e0]> pd 1 @0x8048370
;-- sym.imp.__libc_start_main:
0x08048370 ff25c8950408 jmp dword [reloc.__libc_start_main_200]
[0x080495e0]>
br />所以
__libc_start_main
必须是main的地址,让我们拆开它: > 8049750
并将其存储在本地var 中,并进一步阅读反汇编信息,我们可以推断出它检查
eax
是否等于2(即,仅向程序提供了一个参数),如果不等于2,则将其用于打印一些东西(__libc_start_main) (int (*main) (int, char **, char **),
int argc,
char *__unbounded *__unbounded ubp_av,
void (*init) (void),
void (*fini) (void),
void (*rtld_fini) (void),
void *__unbounded stack_end)
让我们看看打印到控制台上的内容
[0x080495e0]> pd @ 0x8049750
0x08049750 55 push ebp
0x08049751 89e5 mov ebp, esp
0x08049753 53 push ebx
0x08049754 83ec44 sub esp, 0x44
0x08049757 e800000000 call 0x804975c
^- 0x0804975c() ; entry0
0x0804975c 58 pop eax
0x0804975d 81c060feffff add eax, 0xfffffe60
,=< 0x0804977d 0f8422000000 je 0x80497a5 <--other_branch
--------------------
0x0804977a 8945e4 mov dword [ebp - 0x1c], eax
所以我们在字符串输出中看到了这个地址, ?
0x08049783 8b45e4 mov eax, dword [ebp - 0x1c]
0x08049786 8d8814eeffff lea ecx, [eax - 0x11ec]
0x0804978c 890c24 mov dword [esp], ecx
0x0804978f 89c3 mov ebx, eax
0x08049791 e8faebffff call sym.imp.printf
0x08049796 c745f8000000. mov dword [ebp - 8], 0
0x0804979d 8945e0 mov dword [ebp - 0x20], eax
0x080497a0 e983000000 jmp 0x8049828
[0x080495e0]> pd @ 0x8049828
0x08049828 8b45f8 mov eax, dword [ebp - 8]
0x0804982b 83c444 add esp, 0x44
0x0804982e 5b pop ebx
0x0804982f 5d pop ebp
0x08049830 c3 ret
所以我们可以将此分支称为
-1a0
eax- 0x11ec = 80483d0
遵循other_branch
,它看起来像接受从命令行传递来的参数,并使用
eax = 804975c + (-1a0 ) = 80495bc
将转换为数字并调用函数,如果返回值不为0,则打印好,不好。
[0x080495e0]> psz @0x80483d0
run as ./prog a_number (e.g. ./prog 90)
`11c3处的字符串很可能是个好男孩:
>让我们看看其余的功能:
if(argc != 2){ usage();return 0;}
11bc处的字符串
[0x080495e0]> pd @ 0x80497a5
0x080497a5 31c0 xor eax, eax
0x080497a7 b90a000000 mov ecx, 0xa
0x080497ac 8b55f0 mov edx, dword [ebp - 0x10] <- char* argv[]
0x080497af 8b5204 mov edx, dword [edx + 4] ; [0x4
0x080497b2 891424 mov dword [esp], edx
0x080497b5 c74424040000. mov dword [esp + 4], 0 ; [0x4
0x080497bd c74424080a00. mov dword [esp + 8], 0xa ; [0x8
0x080497c5 8b5de4 mov ebx, dword [ebp - 0x1c] this is 80495bc
0x080497c8 8945dc mov dword [ebp - 0x24], eax
0x080497cb 894dd8 mov dword [ebp - 0x28], ecx
0x080497ce e8cdebffff call sym.imp.strtol
^- 0x080483a0() ; sym.imp.strtol
0x080497d3 8945ec mov dword [ebp - 0x14], eax
0x080497d6 8b45ec mov eax, dword [ebp - 0x14]
0x080497d9 890424 mov dword [esp], eax
0x080497dc 8b5de4 mov ebx, dword [ebp - 0x1c]
0x080497df e8fcfeffff call 0x80496e0
0x080497e4 8945e8 mov dword [ebp - 0x18], eax
0x080497e7 837de800 cmp dword [ebp - 0x18], 0
,=< 0x080497eb 0f841b000000 je 0x804980c
| 0x080497f1 8b45e4 mov eax, dword [ebp - 0x1c]
| 0x080497f4 8d883deeffff lea ecx, [eax - 0x11c3]
| 0x080497fa 890c24 mov dword [esp], ecx
| 0x080497fd 89c3 mov ebx, eax
| 0x080497ff e88cebffff call sym.imp.printf
所以我们需要分析
argc
的功能[0x080495e0]> psz @0x80495bc - 0x11c3
good.
[0x080495e0]>
,因此,它将
usage()
写入strtol
并调用它(自修改代码)让我们在反向流上使用
0x80496e0
来获取将要执行的反汇编[0x080495e0]> pd 13 @ 0x804980c
0x0804980c 8b45e4 mov eax, dword [ebp - 0x1c]
0x0804980f 8d8844eeffff lea ecx, [eax - 0x11bc]
0x08049815 890c24 mov dword [esp], ecx
0x08049818 89c3 mov ebx, eax
0x0804981a e871ebffff call sym.imp.printf
^- 0x08048390() ; sym.imp.printf
0x0804981f 8945d0 mov dword [ebp - 0x30], eax
0x08049822 8b45e8 mov eax, dword [ebp - 0x18]
0x08049825 8945f8 mov dword [ebp - 8], eax
0x08049828 8b45f8 mov eax, dword [ebp - 8]
0x0804982b 83c444 add esp, 0x44
0x0804982e 5b pop ebx
0x0804982f 5d pop ebp
0x08049830 c3 ret
[0x080495e0]>
因此将返回地址移至
0xc324148b
(804974b
= rasm2
)edx
,因此edx
将变为0x080496ef
[0x080495e0]> psz @0x80495bc - 0x11bc
bad.
[0x080495e0]>
我希望您可以从此处继续执行,在流上从rade执行
edx+6 = 0x80496f65
以获取修改后的指令,并构造一个新的修改后的函数并进行分析。好的,这意味着您需要知道在命令行中传递给函数的内容
最有可能是
jmp 0x80496e0
,其伪代码为[0x08049644]> pdi @0x80496e0
0x080496e0 c7054b9704088b1424c3 mov dword [0x804974b], 0xc324148b
0x080496ea e85c000000 call 0x804974b
0x080496ef 66c7420631c0 mov word [edx + 6], 0xc031
0x080496f5 ebe9 jmp 0x80496e0
[0x08049644]>
感谢jvoisin进行编辑
发现了几分钟,可以使用雷达静态分析功能
[0x08049644]> !rasm2 -d 0x8b1424c3
mov edx, dword [esp]
ret
...
[0x08049644]> !rasm2 -d 31c0
xor eax, eax
[0x08049644]>
。
function selfie() { if ((argv[0] xor someconstant) == 0) {return 1} else { return 0; }
#2 楼
目前,处理自修改代码的最佳方法是使用动态分析。大多数静态分析技术将无法检测并找出代码的修改部分。该软件(我指的是逐条指令进行跟踪)。您可以考虑至少两种情况,该软件没有任何反调试保护,然后可以使用
gdb
Python API保存并显示每条指令的完整轨迹。或者,该软件具有一些防调试保护,您可以使用诸如Intel Pin框架之类的工具,该工具可以让您记录指令的跟踪记录。 。这是一个小脚本,它逐步执行程序,收集所有汇编指令,然后将其发送到gdb
的stdout
(我很快又非常肮脏,有很多方法可以改进它), /> import gdb
gdb.execute('break main')
gdb.execute('run')
while (True):
gdb.write (gdb.execute('x /i $pc', to_string=True).rstrip('\n'), gdb.STDOUT)
gdb.execute('stepi', to_string=False)
gdb.flush ()
然后,只需执行:
$> gdb -x ./script.py ./main 1> log.txt
我真的很想改善这种方式通过检测到
gdb
已到达程序结尾来结束while
循环。并且,为了更好地控制输出,以干净的方式将其写入文件(而不是在gdb
中丢弃)...但是,我没有多余的时间来完成它。有关所有内容的更多信息,请参见:
在
stdout
文档中使用Python扩展gdb
。gdb
文档中的Python API。 > Tom Tromey撰写的Python
gdb
教程。#3 楼
我通常建议使用Intel的PIN框架,但是,对于单个PE文件来说,它有些致命。为什么不使用Radare2调试功能?
您可以在这里看到如何将其用于解决裂纹。
评论
是啊!是我创造了这个骗子。感谢您的关注。您可能会在reddit上的该线程上找到有关此破解的有用信息:reddit.com/r/ReverseEngineering/comments/3oa3uu / ...