1、Win32应用程序入口识别
Ollydbg一进入程序停留的地方并不是我们自己定义的函数入口点,因此我们需要寻找EIP。
前面已经讲过入口函数参数的意义,再拿来复习复习
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
WinMain的第一个参数叫“实例句柄”。在Windows程序中,句柄无非就是一个数值,程序用他来标识某些东西在早期Windows程序中,当多路并发运行同一个程序时,就需要为那个程序创建多个实例。同一个程序的所有实例都共享代码以及只读存储(即菜单或对话框模板之类的资源)。一个程序可以通过查看hPrevInstance参数从而知道是否有它的其他实例正在运行。
在32位Windows中,这一概念已不再采用。因此WinMain的第二个参数通常总是NULL。
WinMain的第三个参数是用来运行程序的命令行。有些Windows程序在启动时用它来把文件装入内存。
WinMain的第四个参数用来指示程序最初如何显示:或正常显示,或最大化,或最小化。
WinMain入口函数需要有4个参数压入栈,所以我们先找压入4个参数的call
由于Win32应用程序的调用约定是stcall,参数传递是从右向左,且是内平栈
由于IAT表的关系,ollydbg可以帮我们识别很多系统函数
[<&KERNEL32.GetModuleHandleA ]其实就是得到WinMain中的第一个参数实例句柄,也就是WinMain中由于stcall被压入栈的第四个参数。
压入实例句柄的下一个call,应该就是我们的WinMain函数入口,我们再跟进去看看就能确定是不是我们的真正的WinMain函数入口了。
2、ESP寻址的特点
进入WinMain函数后,我们发现开栈操作并不是我们常见的EBP寻址(push ebp,move ebp,esb)
而是采用了sub esp,44这种方式开栈。
其实debug版本大多采用EBP+偏移开栈,release版本大多采用ESP-偏移的方式开栈。
相比较而言ESP开栈比EBP开栈更难逆,因为EBP开栈,它的栈底是保存着不会变的。而ESP寻址,每次push压栈、pop出栈都会引起ESP的变化,所以ESP寻址相比EBP寻址是变化的,对逆向人员要求更高。
每次push、pop后都需要计算ESP的值,如果人工计算的话难免会有纰漏,所以ollydbg帮我们做了这份工作,看右下角的堆栈窗口。
双击这个区域后,就会变成时刻以ESP为基址动态追踪的堆栈,举例如下
3、窗口回调函数的定位
我们了解了ESP寻址的操作,回归正题,来寻找窗口回调函数
窗口回调函数在WinMain函数中出现就是在函数开头构造wndclass类中,wndclass中的第二个参数就是窗口回调函数的指针。
而wndclass类可以通过RegisterClass函数得到,RegisterClass的唯一参数就是wndclass类的指针。
所以我们现在的首要任务就是找的RegisterClass函数。
RegisterClass函数基本上在WinMain函数开始处,所以一进入WinMain函数开始跟就行了。
得到winclass类的指针,由此得到回调函数的地址
4、具体事件的处理的定位
打个条件断点,因为会接受所有的事件,不做条件断点的话,会涌来很多响应。
底下这个条件断点的意思就是点击鼠标左键时断下
看看一看Windows定义的事件编号。
点击鼠标左键跟进断点
同理
总共有三种不同的事件被作者创建