老规矩 附件从百度云下载

链接: http://pan.baidu.com/s/1cKkFiI 密码: 7hs4

这是一个很简单的win32窗口程序,在上面按键盘会弹出对话框,我们现在来逆向找找他的winmain和消息处理函数,看看他是怎么做的,在这之前,我们先看看MSDN winmain的特征

int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine,
                   int nCmdShow);

我们可以看到 WinMain有4个参数,也就是调用winmain应该有4次push winmain前面有个WINAPI 看起来跟语法有点冲突 除非是调用方式咯,我们查查看

#define WINAPI      __stdcall 

WINAPI是个宏 其实就是__stdcall  __stdcall 是内平栈 也就是在call的下面看不到add esp xxx这样的代码


好了 我们可以开始尝试分析了 OD附加

程序停留在入口,我们往下翻翻看 有没有什么线索


我们可以看到上图中OD给我注释出来的API调用,获取了模块句柄获取了命令行参数,我们可以猜测 WINMAIN应该在这附近了


我们看看下图箭头标出来的代码


0040132E  |> \50            push eax                                 ;  kernel32.BaseThreadInitThunk
0040132F  |.  FF75 9C       push dword ptr ss:[ebp-0x64]
00401332  |.  56            push esi
00401333  |.  56            push esi                                 ; /pModule = NULL
00401334  |.  FF15 2C604000 call dword ptr ds:[<&KERNEL32.GetModuleH>; \GetModuleHandleA
0040133A  |.  50            push eax                                 ;  kernel32.BaseThreadInitThunk
0040133B  |.  E8 C0FCFFFF   call ReverseT.00401000
00401340  |.  8945 A0       mov dword ptr ss:[ebp-0x60],eax          ;  kernel32.BaseThreadInitThunk
00401343  |.  50            push eax                                 ;  kernel32.BaseThreadInitThunk
00401344  |.  E8 110A0000   call ReverseT.00401D5A

箭头指向的40133b这个call 虽然上面有5次push 但是 push esi应该是调用GetMouduleHandleA产生的,我们进入这个call看看(401000)

我们直接到函数末尾处,可以看到 retn 0x10 内平栈 4个参数, 我们再看看函数开始的地方

 

没有保存ecx的情况下就直接用了,说明肯定不是__fastcall的调用方式

那么401000 应该就是WinMain没错了,我们分析分析winmain的代码 找到回调函数


00401010  |.  8D7C24 28     lea edi,dword ptr ss:[esp+0x28]
00401014  |.  C74424 24 000>mov dword ptr ss:[esp+0x24],0x0
0040101C  |.  68 8A7F0000   push 0x7F8A                                     ; /RsrcName = IDC_APPSTARTING
00401021  |.  F3:AB         rep stos dword ptr es:[edi]                     ; |
00401023  |.  50            push eax                                        ; |hInst = 74A53358
00401024  |.  8935 20994000 mov dword ptr ds:[0x409920],esi                 ; |
0040102A  |.  C74424 48 040>mov dword ptr ss:[esp+0x48],0x4                 ; |
00401032  |.  FF15 BC604000 call dword ptr ds:[<&USER32.LoadCursorA>]       ; \LoadCursorA
00401038  |.  C74424 28 F01>mov dword ptr ss:[esp+0x28],ReverseT.004010F0
00401040  |.  C74424 48 407>mov dword ptr ss:[esp+0x48],ReverseT.00407040   ;  ASCII "My First Window"
00401048  |.  894424 3C     mov dword ptr ss:[esp+0x3C],eax                 ;  kernel32.BaseThreadInitThunk
0040104C  |.  8D4424 24     lea eax,dword ptr ss:[esp+0x24]
00401050  |.  50            push eax                                        ; /pWndClass = kernel32.BaseThreadInitThunk
00401051  |.  897424 38     mov dword ptr ss:[esp+0x38],esi                 ; |
00401055  |.  FF15 C0604000 call dword ptr ds:[<&USER32.RegisterClassA>]    ; \RegisterClassA

我们可以看到这段代码有调用RegisterClassA,我们知道 这个函数接受一个结构体 其中毁掉函数的地址就在结构体里面 结果体是eax 而eax是 esp+0x24 看看上面赋值的代码 回调应该就是

00401038  |.  C74424 28 F01>mov dword ptr ss:[esp+0x28],ReverseT.004010F0

4010f0了,我们过去看看


进来就是个大大的switch 我们打个断点,发现一只会断下来 有win32基础的应该知道,消息回调函数会一直调用,好吧,我们如果要分析为什么按键弹出ERROR,如果基础比较好的话 其实直接看代码都能看出所以然来

这里我们用条件断点来处理这个问题

我们在开始处 点鼠标右键–>断点–>条件断点

或者直接按Shift+F2


在弹出的对话框中 输入 [esp+0x8]==WM_KEYDOWN


为什么是esp+8呢,我们可以看到 在这之前还没有提升堆栈,也就是说 esp还是保留的函数返回地址 esp+4是函数的第一个参数 也就是句柄,第二个参数就是我们的消息了 我们是要拦截键盘按下 然后单步分析,我们按下键盘的任意键 是不是断下来了?

switch里面比较简单 我就不分析了 大家可以自己分析,如果还不会分析switch的话 可以参考 http://www.dbgpro.com/archives/479.html

打赏