偷换windows窗口过程

来源:互联网 发布:淘宝联盟用了红包丢单 编辑:程序博客网 时间:2024/05/21 06:25

    Window user32子动态库控件封装和消息分发浅析  这篇文章提到窗口程序在分发消息时会依次调用:UserCallWinProcCheckWow--->_InternalCallWinProc-->各个窗口程序的WndProc。各类控件的窗口程序不同,比如Button控件用的是Button_WndProc,程序通过_InternalCallWinProc最终进入Button_WndProc对Button事件处理。受到这篇文章的启示,我尝试用windbg修改calc.exe的窗口程序,并记录于此。

    网上一些文章提及万能消息断点时,无不例外的都会带到_InternalCallWinProc这个函数,综合各家所言和自己调试的过程,我得到如下结论:

1._InternalCallWinProc的函数接口可能为:

_InternalCallWinProc(WndProc*,Hwnd,UINT,WPARAM,LPARAM);
参数1是程序在调用RegisterClass(Ex)时注册的窗口过程,参数2是接收消息的窗口的句柄,参数3是消息号。从参数2到参数5,类似于传递给WndProc接口的参数。

2.在_InternalCallWinProc函数中会以参数1传入的函数指针作为消息的窗口过程,将参数2-5压栈传给它并跳转到该窗口过程。可能的实现如下(xp):

_InternalCallWinProc(){    (*WndProc)(Hwnd,UINT,WPARAM,LPARAM);}
(win7)
_InternalCallWinProc(){    push LPARAM    push WPARAM    push UINT    push Hwnd    jmp WndProc}
    回到我的正题上,我要做的是偷换窗口过程。xp到win7都没有检测函数指针WndProc的合法性(至少在windbg中是这样),所以,我们可以把这个指针值偷换为其他代码(可以通过注入代码的形式实现)。作为演示的目的,我把calc.exe按键7的WndProc替换为ExitProcess函数,以下为实现步骤:

1.用spy++定位按键7的句柄:


2.windbg attach到calc.exe,设置符号并查找符号_InternalCallWinProc

0:001> x *!*internalcall* @查找符号InternalCallWinProc地址77d1870c USER32!InternalCallWinProc = <no type information>0:001> x *!Button_* @查找Button控件符号地址771a7725 comctl32!Button_CalcRect = <no type information>0:001> bp USER32!InternalCallWinProc0:001> gBreakpoint 0 hitUSER32!InternalCallWinProc:77d1870c 55              push    ebp0:000> kbChildEBP RetAddr  Args to Child              00>0007fd30 77d18816 7365912a 000101b2 00000219 USER32!InternalCallWinProc01>0007fd98 77d189cd 00000000 7365912a 000101b2 USER32!UserCallWinProcCheckWow+0x15002>0007fdf8 77d18a10 0007fee8 00000000 0007ff1c USER32!DispatchMessageWorker+0x30603>0007fe08 010021a7 0007fee8 7c80b731 000a2348 USER32!DispatchMessageW+0xf...0007fff0 00000000 01012475 00000000 78746341 kernel32!BaseProcessStart+0x23@栈回溯00>处的0x7365912a是计算机窗口过程的函数指针0:000> ln 7365912a (7365912a)   msctfime!UIWndProc   |  (7365913a)   msctfime!CtfImeDestroyInputContextExact matches:    msctfime!UIWndProc (<no parameter info>)@查看地址0x7365912a附近的符号是msctfime!UIWndProc,有点像一个窗口过程
3.准备下条件断点。来分析一下断点要满足的需求:如果我们在Button控件(Button控件的窗口过程为comctl32!Button_CalcRect)"7"(spy++显示句柄值0x001016A判断)上按下左键(消息值为0x201)时,使windbg中断。把这段话转变为windbg能理解的命令:

0:000> bp comctl32!Button_WndProc ".if(dwo(esp+4)==0001016A&dwo(esp+8)==201){.echo Button7Down;}.else{gc;}"0:000> g
其中dwo(esp+4)用于判断按键7的窗口句柄值,dwo(esp+8)用于判断消息值是否为左键按下。我们看下断点的效果:


    当我按下7,windbg在输出窗口输出"Button7Down",看来断点生效了~再来看下调用堆栈:

0:000> kbChildEBP RetAddr  Args to Child              00> 0007fd04 77d18734 0001016a 00000201 00000001 comctl32!Button_WndProc01> 0007fd30 77d18816 771a8eb4 0001016a 00000201 USER32!InternalCallWinProc+0x2802> 0007fd98 77d189cd 00000000 771a8eb4 0001016a USER32!UserCallWinProcCheckWow+0x15003> 0007fdf8 77d18a10 0007fee8 00000000 0007ff1c USER32!DispatchMessageWorker+0x30604> 0007fe08 010021a7 0007fee8 7c80b731 000a2348 USER32!DispatchMessageW+0xf...0007ffc0 7c817067 00330039 00360037 7ffd3000 calc+0x125e90007fff0 00000000 01012475 00000000 78746341 kernel32!BaseProcessStart+0x23
按调用栈可以看到是USER32!InternalCallWinProc调用了comctl32!Button_WndProc,现在我们回过头来看下前面我得到的结论对不对----USER32!InternalCallWinProc的参数1存放了处理消息的窗口过程:

0:000> ln 771a8eb4 (771a8eb4)   comctl32!Button_WndProc   |  (771a99c9)   comctl32!InitButtonClassExact matches:    comctl32!Button_WndProc = <no type information>
果不其然,0x771a8eb4是Button控件的消息处理函数!

    既然USER32!InternalCallWinProc对参数1传入的值不加甄别,我完全可以对USER32!InternalCallWinProc下同样的条件断点,触发断点后在函数入口处修改参数1的值,把他指向进程空间中其他一段可执行代码,那就ExitProcess了:

0:000> x *!*ExitProcess*7c81cafa kernel32!ExitProcess = <no type information>0:000> bp USER32!InternalCallWinProc ".if(dwo(esp+8)==0001016A&dwo(esp+c)==201){.echo Button7Down;}.else{gc;}"0:000> gButton7Downeax=c0000000 ebx=00000000 ecx=40000000 edx=00000040 esi=771a8eb4 edi=0007fd6ceip=77d1870c esp=0007fd34 ebp=0007fd98 iopl=0         ov up ei ng nz na pe cycs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000a87USER32!InternalCallWinProc:77d1870c 55              push    ebp0:000> kbChildEBP RetAddr  Args to Child              0007fd30 77d18816 771a8eb4 0001016a 00000201 USER32!InternalCallWinProc0007fd98 77d189cd 00000000 771a8eb4 0001016a USER32!UserCallWinProcCheckWow+0x150@注意传入给InternalCallWinProc的函数指针位于参数2,所以要修改的是esp+80:000> ed 0007fd30+8 7c81cafa 0:000> geax=000000c0 ebx=00000102 ecx=77d2b401 edx=0007f720 esi=000000d4 edi=00000000eip=7c92e4f4 esp=00bfff24 ebp=00bfff88 iopl=0         nv up ei pl zr na pe nccs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246ntdll!KiFastSystemCallRet:    <--------------进程退出7c92e4f4 c3              ret
    修改参数2后,继续执行windbg马上就能看到进程退出,有意思吧?来看下任务栏的截图:


calc.exe已经不复存在,偷换成功~

本篇完~









0 0
原创粉丝点击