精准型消息断点

渗透技巧 11个月前 admin
126 0 0

前文作为系列的开篇,我们站在Notepad.exe的视角,看它接过系统传来的消息,交由Notepad的窗口处理函数(WndProc)进行处理的过程。


User32.dll!DispatchMessage API是前面”系统传来”中的一环,也是最靠近应用层的一环,将窗口消息传递给应用。本文从该API切入,逐渐远离熟悉的应用层。


原本本文想结合Ollydbg的消息断点演示,奈何消息断点存在各种限制,因此我在DispatchMessage上下条件断点,更精准的达到相同目的。


用过Ollydbg的读者一定对Ollydbg中的条件断点并不陌生,我先演示使用条件断点的标准流程。


1.1查找RegisterClassEx并下断


精准型消息断点

精准型消息断点


1.2 Notepad被断点中断后,分析调用RegisterClassExW时传入的窗口类:


精准型消息断点


上图Ollydbg的堆栈区窗口中:


a.ESP指向调用USER32.RegisterClassExW API的指令的返回地址 ;


b.ESP+4存放RegisterClassExW的参数WNDCLASSEX结构的地址,其结构定义如下,其中域变量lpfnWndProc位于结构体中的Offset 8 Byte处:


typedef struct tagWNDCLASSEXW {
    UINT        cbSize; // Offset 0
    /* Win 3.x */
    UINT        style; //  Offset 4
    WNDPROC     lpfnWndProc; //Offset 8 窗口过程地址
    int         cbClsExtra;
    int         cbWndExtra;
    HINSTANCE   hInstance;
    HICON       hIcon;
    HCURSOR     hCursor;
    HBRUSH      hbrBackground;
    LPCWSTR     lpszMenuName;
    LPCWSTR     lpszClassName;
    /* Win 4.0 */
    HICON       hIconSm;
} WNDCLASSEXW, *PWNDCLASSEXW, NEAR *NPWNDCLASSEXW, FAR *LPWNDCLASSEXW;


PS:虽然lpfnWndProc标注为窗口过程地址,但是只有少数CrackMe在lpfnWndProc指向的函数中进行消息处理。因此,只在此处未必是解决CrackMe的银弹。这才引出使用DispatchMessage追踪窗口函数的必要性。


在Ollydbg的堆栈区窗口中”ESP+4″处右键”Follow in dump”,即可在数据区查看WNDCLASSEX各个域变量的值。图中0x19FB64(WNDCLASSEX + 0x08)处存放Notepad窗口过程(WndProc)地址(0x401B90):


精准型消息断点


在Ollydbg数据区0x19FB64处右键”Follow DWORD in Disassembler”,即可在指令窗口显示Notepad窗口过程的反汇编。(我用LoadMapEx加载了Notepad的map文件,因此Comment区域会显示窗口过程的符号名_NpWndProc)Notepad的窗口过程位于0x0401B90(很明显该过程位于Notepad.exe 代码段内),先记录这个地址并在下断点


精准型消息断点


通过分析RegisterClassEx的参数,我们认为Notepad的窗口过程位于0x0401B90,然而,Ollydbg工具栏中”W”给出的窗口过程/ClsProc都没给出这个地址


精准型消息断点


1.3 给Notepad.exe窗口下条件断点.


对于CrackMe练习,一般下一步是在Edit窗口ClsProc上下消息断点,奈何消息断点在单文档窗口程序上似乎失效了(百度搜索”消息断点失效”,提问者不少解答者寥寥),于是变通为给DispatchMessageA/W下条件断点。DispatchMessage的唯一参数为MSG,结构如下:


typedef struct tagMSG {
    HWND        hwnd;
    UINT        message;
    WPARAM      wParam;
    LPARAM      lParam;
    DWORD       time;
    POINT       pt;
#ifdef _MAC
    DWORD       lPrivate;
#endif
} MSG, *PMSG, NEAR *NPMSG, FAR *LPMSG;


DispatchMessageA/W下条件断点的步骤如下:

a. 先给DispatchMessage下个普通断点(bp DisaptchMessageA/W),断下后结合堆栈来拼凑成条件断点;


精准型消息断点

简单说明以下,在Ollydbg堆栈区中:
"ESP ==>":指向返回地址;
"ESP+4":指向参数MSG的地址。

在ESP+4处右键"Follow in Dump"将在ollydbg数据区解析MSG各个成员:
MSG+0x00 (0x19FCD0):0x00307E4,为窗口句柄
MSG+0x04 (0x19FCD4):0x60,为消息值


据此,得到DispatchMessageW条件断点的表达式: 


精准型消息断点


1.4.设置内存访问断点


当Notepad收到按键抬起消息时,ollydbg会中断在条件断点处。一般为了追踪处理消息的窗口过程中,Cracker此时会在Ollydbg中对代码段下内存访问断点。对于本文就是对Notepad的代码段下内存访问断点。


点击Ollydbg工具栏的”M”,显示模块窗口:


精准型消息断点


再次运行ollydbg,程序马上会暂定在Notepad的代码段中,暂定处大概率是窗口过程。对于CrackMe,剩下的是分析注册码算法了,但是此处,我提出2个调试过程中遇到的值得深思的问题:


a.如果Notepad.exe的代码量极大,窗口过程恰好位于其他dll中,那么通过下内存访问断点来定位窗口过程的方式是不是失效了?


b.有别于练手的CrackMe程序,对于多线程程序,就如Notepad.exe,设置内存访问断点后,其他线程也会访问代码段(如访问网络读取数据),如何从中挑选出窗口过程?这无异于引入了大量的噪声,增加的分析的难度。(简单如Notepad.exe也有15个线程)


精准型消息断点


如何解决上述2个问题?让我们深入DispatchMessage函数。


2.USER32._InternalCallWinProc


借助前面RegisterClassExW给窗口过程下的断点,继续运行Ollydbg,Ollydbg中断。点击Ollydbg工具栏”K”,查看函数调用堆栈:


精准型消息断点


第一第四栈帧有点眼熟,它显示了窗口程序在User32模块中从DispatchMessage API进入窗口过程的全过程。借助IDA为User32.dll生成map文件/Ollydbg LoadMap插件加载新生成的Map文件,可以获得相对友好的调用堆栈:


2.1. IDA生成User32.Map


IDA加载User32.dll,点击File–Produce file–Create MAP file,生成User32.map:


精准型消息断点


2.2. Ollydbg加载Map


Ollydbg–Plugins–LoadMapEx–LoadMapEx加载IDA生成的MAP:

(注:一定要在User32.dll模块的地址空间中加载User32.map,否则会干扰ollydbg的分析功能.一旦干扰ollydbg的分析功能,只能通过移除分析结果来恢复)


精准型消息断点


再次打开调用堆栈,得到较为友好的调用堆栈:


精准型消息断点


虽然图中有部分函数地址没有解析出来,但是通过单步跟踪可以得到如下调用链:


DispatchMessageW
|-->DispatchMessageWorker
    |-->UserCallWinProcCheckWow
        |-->InternalCallWinProc


同时借助泄露的win xp源码一探究竟:UserCallWinProcCheckWow的实现位于NTwindowscorentuserclientclmsg.c


LRESULT
UserCallWinProcCheckWow(
    PACTIVATION_CONTEXT pActCtx,
    WNDPROC pfn,
    HWND hwnd,
    UINT msg,
    WPARAM wParam,
    LPARAM lParam,
    PVOID pww,
    BOOL fEnableLiteHooks)
{
    BOOL fInsideHook;
    LRESULT lRet = 0;
 
    BEGIN_CALLWINPROC(fInsideHook, lRet)
 
        BOOL fOverride = fInsideHook && fEnableLiteHooks && IsMsgOverride(msg, &guah.uoiWnd.mm);
 
        pfn = MapKernelClientFnToClientFn(pfn);
 
        if (fOverride) {
            /*
             * NOTE: It is important that the same lRet is passed to all three
             * calls, allowing the Before and After OWP's to examine the value.
             */
            void * pvCookie = NULL;
            if (guah.uoiWnd.pfnBeforeOWP(hwnd, msg, wParam, lParam, &lRet, &pvCookie)) {
                goto DoneCalls;
            }
 
            lRet = (IsWOWProc(pfn) ? (*pfnWowWndProcEx)(hwnd, msg, wParam, lParam, PtrToUlong(pfn), KPVOID_TO_PVOID(pww)) :
                InternalCallWinProc((WNDPROC)KPVOID_TO_PVOID(pfn), hwnd, msg, wParam, lParam));
 
            if (guah.uoiWnd.pfnAfterOWP(hwnd, msg, wParam, lParam, &lRet, &pvCookie)) {
                // Fall through and exit normally
            }
DoneCalls:
            ;
        } else {
            lRet = (IsWOWProc(pfn) ? (*pfnWowWndProcEx)(hwnd, msg, wParam, lParam, PtrToUlong(pfn), KPVOID_TO_PVOID(pww)) :
                InternalCallWinProc((WNDPROC)KPVOID_TO_PVOID(pfn), hwnd, msg, wParam, lParam));
        }
    END_CALLWINPROC(fInsideHook)
 
    return lRet;
#ifdef _WIN64
    UNREFERENCED_PARAMETER(pww);
#endif // _WIN64
}


InternalCallWinProc是宏,定义于NTwindowscorentuserclientcallproc.h 


#define InternalCallWinProc(winproc, hwnd, message, wParam, lParam)    
    (winproc)(hwnd, message, wParam, lParam)


其中winproc是函数指针,随之猜想,winproc可能会有机会指向Notepad.exe代码段中的某个地址。


3.精准型消息断点


先给前面猜想的结论,当UserCallWinProcCheckWow函数调用InternalCallWinProc时,winproc有机会(winproc还会指向ntdll中的回调函数)会指向Notepad的窗口过程:


精准型消息断点


如上图,调用InternalCallWinProc,EBX指向notepad.NPWndProc。既然如此,我可以在调用InternalCallWinProc时下条件断点(我就称它为精准型消息断点)


精准型消息断点


图中ebx的取值需要根据代码段的起始/结束位置做调整。


当ollydbg中断时,结合InternalCallWinProc的函数原型可知:


EBX指向真正的窗口过程–>这就是我提出的精准型消息断点,可以解决前面提出的问题。


ESI指向接受消息的窗口句柄。


EDI指向消息类型。


当然,我们还能进一步编辑条件断点的条件,过滤出特定的窗口消息WM_KEYUP消息。




精准型消息断点


看雪ID:hyjxiaobia

https://bbs.kanxue.com/user-home-399589.htm

*本文为看雪论坛优秀文章,由 hyjxiaobia 原创,转载请注明来自看雪社区

精准型消息断点

# 往期推荐

1、知乎 x-zse-96 字段破解

2、CVE-2022-37969 CLFS 提权漏洞

3、Chrome v8 Issue 1203122:IC类型混淆漏洞原理

4、高版本go语言符号还原

5、DASCTF 2023六月挑战赛 二进制专项 RE writeup

6、用 Qiling/Unicorn 框架来 dump il2cpp


精准型消息断点


精准型消息断点

球分享

精准型消息断点

球点赞

精准型消息断点

球在看

原文始发于微信公众号(看雪学苑):精准型消息断点

版权声明:admin 发表于 2023年6月12日 下午6:00。
转载请注明:精准型消息断点 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...