ATL Windowing中的汇编:_stdcallthunk分析

来源:互联网 发布:美国网络直播发展史 编辑:程序博客网 时间:2024/04/30 14:18

1. 指令指针寄存器与正在执行指令指针关系:

I:                      CPU正在执行指令;

xIP:                  CPU指令指针寄存器内容;

xIP(I):              CPU正在执行的指令I的指针;

LEN(I):            指令I的长度。

1)顺序执行:xIP = xIP(I) + LEN(I);

2)相对跳转:xIP = xIP(I) + LEN(I) + REL_DISPLACEMENT_CONST;

3)绝对跳转:xIP = Target_CONST;

2. ATL:: _stdcallthunk 代码片断(节选自atlstdthunk.h

struct _stdcallthunk

{

        DWORD   m_mov;          // mov dword ptr [esp+0x4], pThis (esp+0x4 is hWnd)

        DWORD   m_this;         //

        BYTE    m_jmp;          // jmp WndProc

        DWORD   m_relproc;      // relative jmp

        BOOL Init(DWORD_PTR proc, void* pThis)

        {

                m_mov = 0x042444C7;  //C7 44 24 0C

                m_this = PtrToUlong(pThis);

                m_jmp = 0xe9;

                m_relproc = DWORD((INT_PTR)proc - ((INT_PTR)this+sizeof(_stdcallthunk)));

                // write block from data cache and

                //  flush from instruction cache

                FlushInstructionCache(GetCurrentProcess(), this, sizeof(_stdcallthunk));

                return TRUE;

        }

        //some thunks will dynamically allocate the memory for the code

        void* GetCodeAddress()

        {

                return this;

        }

// code ignored ……

};

3. 数据作为代码运行

实际使用时,_stdcallthunk结构作为代码使用。经过Init()后,被解释为以下两条指令(X86机器)

            Mov dword ptr[esp+4], pThis_CONST;

            Jmp REL_DISPLACEMENT_CONST;

其中 pThis_CONSTCWindowXXX的指针;

REL_DISPLACEMENT_CONST是跳转到实际WndProc的相对偏移量。那为什么 REL_DISPLACEMENT_CONST _relproc = DWORD((INT_PTR)proc - ((INT_PTR)this+sizeof(_stdcallthunk))); 呢?稍候解释。

           

下面是一个可能的伪码例子:

WNDPROC pWndProc = (WNDPROC)( _stdcallthunkOBJ. GetCodeAddress() );

SetWindowLongPtr( hwnd, GWLP_WNDPROC, pWndProc);

4. 两条指令的解释

WndProc被调用时,程序堆栈如下:(地址约定:高地址在上,低地址在下)

LPARAM

WPARAM

UINT

HWND                                    ß esp+4

RetAddr( from WNdProc)       ß esp

所以当第一条指令Mov dword ptr[esp+4], pThis_CONST 执行后,程序堆栈如下:

LPARAM

WPARAM

UINT

pThis_CONST             ß esp+4

RetAddr( from WNdProc)       ß esp

当第二条指令Jmp REL_DISPLACEMENT_CONST 执行时,xIPxIPI)的关系如下(重复地址约定:高地址在上,低地址在下)

Others ….                                ß_stdcallthunk结构的基址+_stdcallthunk结构大小

Jmp ….. (第二条指令)           ß xIPI

Mov ….. (第一条指令)          ß_stdcallthunk结构的基址

由于xIP = xIP(I) + LEN(I) + REL_DISPLACEMENT_CONST;

显然 xIP(I) + LEN(I) = _stdcallthunk结构的基址+_stdcallthunk结构大小;

又因为 REL_DISPLACEMENT_CONST = _relproc = DWORD((INT_PTR)proc - (_stdcallthunk结构的基址+_stdcallthunk结构大小)

所以 xIP = xIP(I) + LEN(I) + REL_DISPLACEMENT_CONST

            =  _stdcallthunk结构的基址+_stdcallthunk结构大小)+ DWORD((INT_PTR)proc - (_stdcallthunk结构的基址+_stdcallthunk结构大小)

= proc

既下一条将要执行的指令是实际WndProc的首条指令。

如果使用绝对寻址,要好理解的多,可能是基于性能考虑,使用相对寻址。X64使用寄存器绝对寻址(rcx rax),好理解一些,但显然须符合调用约定。

5.总结

1)      数据被解释为代码;

2)      相对跳转正好跳到实际WndProc


v{@_@}v