我想开始学习逆向工程。 所以我决定开始简单。 我创建了这个简单的程序:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
printf ("Hello World!\n");
system("PAUSE");
return 0;
}
我在Ollydbg中将其分解。 所以我想尝试将printf更改为“World Hello”。 但我现在不知道该怎么做。 你能指导我,或者至少告诉我理论上应该做些什么吗?
答案 0 :(得分:11)
在这种情况下,您需要编辑传递给printf
的字符串,但首先我们需要获取其地址。通过查看printf
调用的代码,我们将看到类似的内容:
PUSH mymodule.1234567
CALL printf
ADD ESP,4
所以,如果我们通过 ctrl + g 转到地址0x1234567
,我们会看到:
01234567 48 65 6C 6C 6F 20 57 6F 72 6C 64 0A 00 00 00 00 Hello World.....
所以现在你可以编辑那个字符串到你想要的任何东西,只要你没有溢出可用空间并保留空终止符。
保存更改取决于您加载二进制文件的方式(通过附加或仅冷看),最简单的方法是通过冷查看(使用olly纯粹作为反汇编程序/汇编程序)。通过view -> file
进行访问,然后右键单击并从上下文菜单中选择disassemble
。在此模式下,通过右键单击并从上下文菜单中选择save file
来完成保存。
在调试器模式下(也称为连接时),使用右键单击完成保存,然后从copy to executable
上下文菜单选项中选择一个选项。
如果您正在调试GCC生成的代码,它通常会避免生成PUSH
并且有利于使用MOV [ESP+c],c/r/m
将变量直接放入堆栈中。使用GCC编译您的示例,您会看到类似于(对于main
)的代码:
00401AFC /$ PUSH EBP
00401AFD |. MOV EBP,ESP
00401AFF |. AND ESP,FFFFFFF0
00401B02 |. SUB ESP,10
00401B05 |. CALL GCCOllyT.0040182C
00401B0A |. MOV DWORD PTR SS:[ESP],GCCOllyT.00403024 ; ||ASCII "Hello World!"
00401B11 |. CALL <JMP.&msvcrt.puts> ; |\puts
00401B16 |. MOV DWORD PTR SS:[ESP],GCCOllyT.00403031 ; |ASCII "PAUSE"
00401B1D |. CALL <JMP.&msvcrt.system> ; \system
00401B22 |. XOR EAX,EAX
00401B24 |. LEAVE
00401B25 \. RETN
重要的是要注意GCC将对printf
的调用优化为对puts
的调用。在这种情况下你知道你正在寻找的字符串,你可以在调试器模式下使用olly,右键单击并选择search for -> all referenced text strings
,然后从列表中选择你想要的字符串以找到使用它的代码,或按照其地址查找其.data
部分条目,以便您可以更改它。找到它的更长的方法是使用右键单击上下文菜单中提供的二进制搜索,但这通常是文本字符串的浪费。
为了涵盖所有基础,我们假设我们需要从入口点获取代码。 如果我们从模块入口点导航到代码,我们将遵循这样的链:
GCCOllyT.<ModuleEntryPoint> 0> $ >PUSH EBP
0040126D . >MOV EBP,ESP
0040126F . >SUB ESP,18
00401272 . >MOV DWORD PTR SS:[ESP],1
00401279 . >CALL DWORD PTR DS:[<&msvcrt.__set_app_type>; msvcrt.__set_app_type
0040127F . >CALL GCCOllyT.00401000
00401284 . >PUSH EBP
00401285 . >MOV EBP,ESP
00401287 . >SUB ESP,18
0040128A . >MOV DWORD PTR SS:[ESP],2
00401291 . >CALL DWORD PTR DS:[<&msvcrt.__set_app_type>; msvcrt.__set_app_type
00401297 . >CALL GCCOllyT.00401000
0040129C $ >PUSH EBP
0040129D . >MOV EBP,ESP
0040129F . >SUB ESP,8
004012A2 . >MOV EAX,DWORD PTR DS:[<&msvcrt.atexit>]
004012A7 . >LEAVE
004012A8 . >JMP EAX
从这里我们看到唯一可行的呼叫为GCCOllyT.00401000
,然后,我们最终在这里(这是GCC mainCRTstartup
):
00401000 /$ >PUSH EBP
00401001 |. >MOV EBP,ESP
00401003 |. >PUSH EBX
00401004 |. >SUB ESP,34
00401007 |. >MOV EAX,DWORD PTR DS:[403038]
0040100C |. >TEST EAX,EAX
0040100E |. >JE SHORT GCCOllyT.0040102C
00401010 |. >MOV DWORD PTR SS:[ESP+8],0
00401018 |. >MOV DWORD PTR SS:[ESP+4],2
00401020 |. >MOV DWORD PTR SS:[ESP],0
00401027 |. >CALL EAX
00401029 |. >SUB ESP,0C
0040102C |> >MOV DWORD PTR SS:[ESP],GCCOllyT.00401110 ; |
00401033 |. >CALL <JMP.&KERNEL32.SetUnhandledExceptionFilter> ; \SetUnhandledExceptionFilter
00401038 |. >PUSH EAX
00401039 |. >CALL GCCOllyT.004013CC
0040103E |. >CALL GCCOllyT.004014AC
00401043 |. >MOV DWORD PTR SS:[EBP-10],0
0040104A |. >LEA EAX,DWORD PTR SS:[EBP-10]
0040104D |. >MOV DWORD PTR SS:[ESP+10],EAX
00401051 |. >MOV EAX,DWORD PTR DS:[402000]
00401056 |. >MOV DWORD PTR SS:[ESP+C],EAX
0040105A |. >LEA EAX,DWORD PTR SS:[EBP-C]
0040105D |. >MOV DWORD PTR SS:[ESP+8],EAX
00401061 |. >MOV DWORD PTR SS:[ESP+4],GCCOllyT.00404004
00401069 |. >MOV DWORD PTR SS:[ESP],GCCOllyT.00404000
00401070 |. >CALL <JMP.&msvcrt.__getmainargs>
00401075 |. >MOV EAX,DWORD PTR DS:[404018]
0040107A |. >TEST EAX,EAX
0040107C |. >JNZ SHORT GCCOllyT.004010C8
0040107E |> >CALL <JMP.&msvcrt.__p__fmode>
00401083 |. >MOV EDX,DWORD PTR DS:[402004]
00401089 |. >MOV DWORD PTR DS:[EAX],EDX
0040108B |. >CALL GCCOllyT.004015E4
00401090 |. >AND ESP,FFFFFFF0
00401093 |. >CALL GCCOllyT.0040182C
00401098 |. >CALL <JMP.&msvcrt.__p__environ>
0040109D |. >MOV EAX,DWORD PTR DS:[EAX]
0040109F |. >MOV DWORD PTR SS:[ESP+8],EAX
004010A3 |. >MOV EAX,DWORD PTR DS:[404004]
004010A8 |. >MOV DWORD PTR SS:[ESP+4],EAX
004010AC |. >MOV EAX,DWORD PTR DS:[404000]
004010B1 |. >MOV DWORD PTR SS:[ESP],EAX
004010B4 |. >CALL GCCOllyT.00401AFC
004010B9 |. >MOV EBX,EAX ; |
004010BB |. >CALL <JMP.&msvcrt._cexit> ; |[msvcrt._cexit
004010C0 |. >MOV DWORD PTR SS:[ESP],EBX ; |
004010C3 |. >CALL <JMP.&KERNEL32.ExitProcess> ; \ExitProcess
004010C8 |> >MOV DWORD PTR DS:[402004],EAX ; |||
004010CD |. >MOV DWORD PTR SS:[ESP+4],EAX ; |||
004010D1 |. >MOV EBX,DWORD PTR DS:[<&msvcrt._iob>] ; |||msvcrt._iob
004010D7 |. >MOV EAX,DWORD PTR DS:[EBX+10] ; |||
004010DA |. >MOV DWORD PTR SS:[ESP],EAX ; |||
004010DD |. >CALL <JMP.&msvcrt._setmode> ; ||\_setmode
004010E2 |. >MOV EAX,DWORD PTR DS:[404018] ; ||
004010E7 |. >MOV DWORD PTR SS:[ESP+4],EAX ; ||
004010EB |. >MOV EAX,DWORD PTR DS:[EBX+30] ; ||
004010EE |. >MOV DWORD PTR SS:[ESP],EAX ; ||
004010F1 |. >CALL <JMP.&msvcrt._setmode> ; |\_setmode
004010F6 |. >MOV EAX,DWORD PTR DS:[404018] ; |
004010FB |. >MOV DWORD PTR SS:[ESP+4],EAX ; |
004010FF |. >MOV EAX,DWORD PTR DS:[EBX+50] ; |
00401102 |. >MOV DWORD PTR SS:[ESP],EAX ; |
00401105 |. >CALL <JMP.&msvcrt._setmode> ; \_setmode
0040110A \.^>JMP GCCOllyT.0040107E
现在我们知道调用main
的签名需要3个args,我们也知道在应用程序清理和退出之前它将被称为,因此我们得到GCCOllyT.00401AFC
。如您所见,启用符号需要付出很大的代价,这可以从调试选项菜单的反汇编部分完成。