一、资源文件
MAKEINTRESOURCE:这个宏用于将数字转换为char*类型
返回值
1.窗口程序:
已处理的消息返回0
未处理的消息用DesWindowProc()函数返回,交给操作系统处理
2.资源文件:
已处理的消息返回TRUE
未处理的消息返回FALSE
二、消息断点
1.方法一
将程序拖进x32dbg里面
往下走,找入口函数WinMain
WinMain函数有四个参数,其中第一个参数hInstance就是模块的句柄,在这里就是PE结构里面的Windows输出进程基址ImageBase
往下走到这儿,我们看到这个函数叫GetModuleHandleA,我们往Microsoft里面一查,发现这是一个用来获取模块句柄的函数
另外,我们发现这不是平时我们见到的E8 CALL,而是一个FF间接CALL,所以立马就想到了PE结构
输入dd命令查看00405010处的内存,发现里面刚好存储的就是这个函数的名称
由此我们可以想到这里就是一个IAT表,用IAT表将函数的名称读出来,就是我们反汇编窗口右边能看到的红色字符串了
往上验证一下,我们看到了WinMain另外的三个参数
回到GetModuleHandleA那行,我们看到它的下一行是一个push eax。一般情况下我们的返回值就是存在eax里面的
另外,_stdcall和_fastcall是内平栈,而cdecl用的是外平栈。显然,这里是个内平栈.我们跟进下面这个call 4010D0,发现它并没有用到寄存器传参,而且它的ret返回值刚好为0x10,也就是十进制的16,代表传了4个参数进去。也就是说,这个函数是_stdcall调用约定,而WinMain入口函数也恰好是_stdcall。所以我们可以初步判断这个函数是入口函数WinMain了
举一个例子:当A调用B时,假设有四个参数,就会push进去四个值,然后调用B。但是在执行call之前还会将执行调用语句时的下一行地址也压进栈里面
因此,上面这个DialogBoxParmA函数调用前会先执行五个push,最后一个push是调用DialogBoxParmA函数时的下一行地址,前面四个参数就是WinMain入口函数的四个参数
而WinMain函数用的是_stdcall调用约定,它执行参数压栈操作时是从右往左进行,而回调函数的地址存储在从左往右第三个参数,命令行参数里面,反过来一数就是下面这个DlgProc存储的401000
然后我们ctrl+g跳转到401000,F2下断。切记不能直接运行,因为消息事件是一直都在发生的,如果现在下一个断点直接运行,程序一检测到消息就下断,导致在这里不停下断,无法继续调试
所以我们需要下一个消息断点。我们将断点重新编辑,给它添加一个条件
由于消息处理函数存在下面这样一个机制:按钮产生的消息,最后都会传到父窗口的消息处理函数中,而消息的类型最后都会转换为WM_COMMAND类型
再加上MSG消息队列里面的第二个成员才是消息的标识符,这里的[esp+0]存储的是MSG结构体的this指针,也就是说,[esp+8]才是第二个成员
所以写入的条件就是当[esp+8]里面存储的消息类型为WM_COMMAND的时候,程序下断
现在就成功下断,并且不会连续下断了
并且程序的运行界面也弹出来了
2.方法二(当程序很复杂的时候)
把程序拽进去后直接运行,然后点进上面的Windows窗口(红色下划线处),右键刷新
我们可以看到有一项叫ClsProc,很明显这些地址都是7开头的。学过PE我们知道,7开头的地址已经到了系统DLL的领空。也就是说这个是系统DLL给我们指定的消息处理函数,并不是我们这个程序自己写的消息处理函数
我们尝试点击窗口上的按钮,发现它仍然能弹出程序自己写的消息处理函数的处理结果,也就是说,这些系统DLL指定的消息处理函数最终都会调用程序自己写的消息处理函数
我们可以右键右键Follow ClsProc,跟到几个按钮的地址处下消息断点
或者直接右键Message breakpoint on access,让OD直接帮我们下一个消息断点
而经过我们测试,发现鼠标左键按下没反应,释放鼠标左键时消息弹出,因此判断这个断点类型为202 WM_LBUTTONUP,这个是鼠标释放的消息
成功下断!
我们转到断点,重新编辑该断点,发现和我们之前手动写的条件断点如出一辙。所以消息断点其实就是条件断点
单击按钮让事件发生,我们发现这个下断的地址下在了系统的DLL领空,但是不知道真正的处理函数在哪里
于是,我们点击上面这个大写的M,来到Memory map
学过PE之后一眼就能看出来节表的位置
我们在.text段下一个Set memory breakpoint access访问断点,程序执行系统DLL指定的消息处理函数,最终都会调用程序自己写的消息处理函数,一调用就会立马下断
F9运行,我们发现程序已经断下来了
但是存在一个问题,就是消息事件是不断发生的,可能下断的时候传的消息并不是我们想要找的鼠标释放事件。如果我们一直单步往下走,可能直接就不知道跟到哪里去了
学过消息回调函数后,我们知道,回调函数堆栈里面,最上面是调用地址,第二个是句柄,然后是Message消息类型
我们看到右下角堆栈窗口,发现第三个并不是我们想要的111 WM_COMMAND消息
于是我们单步往下走,执行完retn 0x10后又跳回到了另一个DLL领空
我们再次F9运行,跑到下一个断点停下。一直循环这几个步骤,直到堆栈窗口的消息类型变成111为止
一直往下单步,最后就找到了我们下断时点击的Button 1的MessageBoxA了
本文为滴水三期的学习笔记