我正在学习反向学习,我正在学习修改自身的代码(实际上这是一个骗子)。

它包含如下语句:movw edxxc031, 0x(%edx),其中objdump包含语句的地址。使用断点,我可以停止并检查修改后的代码。我将其保存为二进制文件,然后使用gdb进行反汇编,以查看新的语句。

逐行执行此操作有点慢。是否有更好的方法来反转此代码? q4312079q中可能还有其他我不知道的工具或功能。

评论

是啊!是我创造了这个骗子。感谢您的关注。

您可能会在reddit上的该线程上找到有关此破解的有用信息:reddit.com/r/ReverseEngineering/comments/3oa3uu / ...

#1 楼

只是为了踢一下,我下载了crackme并将其馈送到Windows窗口中的radare中,不需要动态分析即可解决此crackme

radare2方面

将此二进制文件字符串化

[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]>


因此将返回地址移至0xc324148b804974b = 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框架之类的工具,该工具可以让您记录指令的跟踪记录。 。这是一个小脚本,它逐步执行程序,收集所有汇编指令,然后将其发送到gdbstdout(我很快又非常肮脏,有很多方法可以改进它), />

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调试功能?
您可以在这里看到如何将其用于解决裂纹。