1.Hello World!程序
这个程序想必大家都是非常熟悉的,第一个接触的程序一个就是他了,这里就不多加解释,用Visual C++编写
1 |
|
2.调试Hello World.exe程序
调试目的
通过调试Hello World.exe可执行文件,在转换得到的汇编语言中找到main()函数。
开始调试
首先用OllyDbg调试工具打开Hello World.exe程序
入口点
调试器停止的地方即为Hello World.exe执行的初始地址,它是一段EP(入口)代码,最重要的就是call 和jmp两个指令。call指令的作用是调用40270C地址处的函数,再跳转至40104F地址处。
跟踪40270C函数
在4011A0地址处F7进去40270C函数
可以看到它并不是main函数,在注释的API被调用的函数可以看到。
跟踪40104F跳转语句
看到这一段代码是非常复杂的,他们是Visual C++的启动函数。跟踪这些代码就可以找到我们需要寻找的main()函数。
接下来一步步调试,先进入到402524函数
这个函数也没有main()函数的特征,并没有在代码中发现调用MessageBox()API的代码。直接Ctrl+F9跳到retn,F7回到之前的地址继续按相同的方法走,
这里走到了401144这个地方,跳转进401000函数,发现401000函数内部出现了调用MessageBox()API的代码,该API函数的参数为“www.reversecore.com”与“Helloworld!”两个字符串。与源码的内容一样,这就是要找的main函数
大本营
每次重新运行调试器时,调试都会返同到EP处,并从此处开始新的调试,使用起来相当不方便。经验丰富的代码逆向分析专家需要在调试代码时设置某个重要的点(地址),使调试能快速转到设置点上。在代码中设置好这样的点后,再次调试时,调试流能够经过这些指定的点,快速达到目标。这些在代码中设置的点就像在登山途中设置的营帐样,以登喜马拉雅山为例,登顶过程中需要设置多个营帐充当据点,如“大木营”一“前进营1”一“前进营2”-“最终突击营”一“峰顶”。同样,调试代码量非常巨大时,整个调试过程可能需要好几天时间,那么在相应位置上设置这些“据点”将非常方便调试。下面向大家介绍几种在代码中设置“据点”的方法,并学习如何快速转到这些“据点”。首先运行OllyDbg,打开HelloWorld.exe可执行文件并调试,将40104F地址设置为basecamp (大本营)。
设置方法
1.Goto命令
请记住,我们要设置为“大本营”的地址为40104F。执行Go to(Ctrl+G)命令,打开一个Enterexpression to follow (输人跟踪表达式)对话框,如图2-11所示,在文本框中输人“40104F”,然后单击OK按钮。Enter expression to fllow
输人地址单击OK按钮后,光标自动定位到40104F地址处,执行Execute till cursor(F4)命令,让调试流运行到该处,然后从40104F处开始调试代码就变得非常方便了。
2.设置断点
调试代码时,还可以设置BP ( Break Point,断点)(快捷键F2)让调试流转到“大本营”
3.注释
4.标签
快速查找指定代码的方法
1代码执行法
我们需要查找的是main)函数中调用MessageBox(函数的代码。在调试器中调试HelloWorld.exe ( Step Over(F8))时,main0函数的MessageBox(函数在某个时刻就会被调用执行,弹出消息对话框,显示“Hello World!”这条信息。以上就是代码执行法的基本原理,程序功能非常明确时,逐条执行指令来查找需要查找的位置。代码执行法仅适用于被调试的代码量不大、且程序功能明确的情况。倘若被调试的代码量很大且比较复杂时,此种方法就不再适用了。下面使用代码执行法来查找代码中的main0函数。从“大本营”( 40104F )开始,按F8键逐行执行命令,在某个时刻弹出消息对话框,显示”Hello World!”信息。按Ctrl+F2键再次载入待调试的可执行文件并重新调试,不断按F8键,某个时刻- -定会弹出消息对话框。弹出消息对话框时调用的函数即为main()函数。就是上面查找的方法。
2.字符串检索法
鼠标右键菜单- Search for - All referenced text strings
在程序中查找指定字符串的方法很多,这里向大家介绍OllyDbg中提供的字符串检索法。OllyDbg初次载入待调试的程序时,都会先经历-一个预分析过程。此过程中会查看进程内存,程序中引用的字符串和调用的API都会被摘录出来,整理到另外-一个列表中,这样的列表对调试是相当有用的。使用All referenced text strings命令会弹出一个窗口,其中列出了程序代码引用的字符串
如图,地址401007处有个PUSH 004092A0的指令,通过该指令就可以到达字符串的位置。
3 API检索法(1); 在调用代码中设置断点
鼠标右键菜单- Search for - All intermodular calls
Windows编程中,若想向显示器显示内容,则需要使用Win 32 API向OS请求显示输出。换言之,应用程序向显示器画面输出内容时,需要在程序内部调用Win32 API。认真观察-一个程序的功能后,我们能够大致推测出它在运行时调用的Win32 API,若能进一步 查找到调用的Win32 API,则会为程序调试带来极大便利。以HelloWorld.exe为例, 它在运行时会弹出- -个消息窗口, 由此我们可以推断出该程序调用了user32.MessageBoxW0 API。
可以看到MessageBoxW()的代码,该函数位于40100E地址处,它是user32.MessageBoxW()的API。
4.API检索法(2):在API代码中设置断点
这种情况下,DLL代码库被加载到进程内存后,我们可以直接向DLL代码库添加断点。API是操作系统对用户应用程序提供的一系列函数, 它们实现于C:\Windowslsystems32文件夹中的dIl文件(如kermel32.dIl、user32.dl1、gdi32.dll、 advapi32.dI1、 ws2_ 32.dI等) 内部。简言之,我们编写的应用程序执行某种操作时(如各种I/O操作),必须使用OS提供的API向OS提出请求,然后与被调用API对应的系统DLL文件就会被加载到应用程序的进程内存。在OllyDbg菜单栏中依次选择View Memory菜单(快捷键Alt+M),打开内存映射窗口。如图所示,内存映射窗口中显示了- -部分HelloWorld.exe进程内存。在图底部的方框中可以看到,USER32库被加载到了内存。
使用OllyDbg中的Name in all modules命令可以列出被加载的DLL文件中提供的所有API。使用Name in all modules命令打开All names窗口,单击Name栏目按名称排序,通过键盘敲出MessageBoxW后,光标会自动定位到MessageBoxW上。
USER32模块中有一个Export类型的MessageBoxW函数(不同系统环境下函数地址不同)。双击MessageBoxW函数后就会显示其代码,它实现于USER32.d1l库中,如图所示。
观察MessageBoxW函数的地址空间可以发现,它与HelloWorld.exe使用的地址空间完全不同。在函数起始地址上按F2键,设置好断点后按F9继续执行.
可以看到栈窗口中的信息和预测的一样,寄存器中的ESP的地址为19FF18
3.利用“打补丁”修改字符串
先在我们之前找到的大本营处下断点,按F9运行程序,到大本营这
修改字符串的方法
(1)直接修改字符串缓冲区
MessageBoxW函数的字符串参数”Hello World!” 保存在地址4092A0处的一段缓冲区中, 只要修改这段内容,就可以修改MessageBoxW 函数显示出的字符串。在Dump窗口中按CtrI+G快捷键执行Go to命令,在弹出窗口中输人4092A0进人字符串缓冲区。然后使用鼠标选中4092A0地址处的字符串,按Ctrl+E快捷键打开编辑窗口,
在返回去看断点的地方,已经被修改了
(2).在其他内存区域新建字符串并传递给消息函数
401007地址处有- - 条PUSH 004092A0命令,它把4092A0地址处的“Hello World!”字符串以参数形式传递给MessageBoxW(函数。向MessageBox W0函数传递字符串参数时,传递的是字符串所在区域的首地址。如果改变了字符串地址,消息框就会显示变更后的字符串。在内存的某个区域新建一个长字符串, 并把新字符串的首地址传递给MessageBoxW0函数,可以认为传递的是完全不同的字符串地址。