您的位置:首页 > 其它

利用thunk技术封装窗口类

2011-04-19 16:00 369 查看
TL 的思路是,每次在系统调用 WndProc 的时候,让它鬼使神差地先走到我们的另一处代码,让我们有机会修改堆栈中的 hWnd。这处代码可能是类似这样的:

__asm
{
mov dword ptr [esp+4], pThis ;调用 WndProc 时,堆栈结构为:RetAddr, hWnd, message, wParam, lParam, ... 故 [esp+4]
jmp WndProc
}

由于 pThis 和 WndProc 需要被事先修改(但又无法在编译前定好),所以我们需要运行的时候去修改这部分代码。先弄一个小程序探测下这两行语句的机器码:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return 0;
}

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
MessageBox(NULL, NULL, NULL, MB_OK);

__asm
{
mov dword ptr [esp+4], 1
jmp WndProc
}

return 0;
}

最前面的 MessageBox 是为了等下调试的时候容易找到进入点。

然后使用 OllyDbg,在 MessageBoxW 上设置断点,执行到该函数返回:





这里我们看到,mov dword ptr [esp+4] 的机器码为 C7 44 24 04,后面紧接着的一个 DWORD 是 mov 的第二个操作数。jmp 的机器码是 e9,后面紧接着的一个 DWORD 是跳转的相对地址。其中 00061000h - 0006102Bh = FFFFFFD5h。

于是定义这样一个结构:

#pragma pack(push,1)
typedef struct _StdCallThunk
{
DWORD m_mov; // = 0x042444C7
DWORD m_this; // = this
BYTE m_jmp; // = 0xe9
DWORD m_relproc; // = relative distance
} StdCallThunk;
#pragma pack(pop)

class CMyWindow
{
public:
CMyWindow():_hwnd(NULL){}
~CMyWindow(){VirtualFree(_pStdthunk, sizeof(StdCallThunk), MEM_RELEASE);}
bool Create();

protected:
LRESULT CALLBACK WndProc(UINT message, WPARAM wParam, LPARAM lParam);

protected:
MSG _msg;
HWND _hwnd;
StdCallThunk *_pStdthunk;

protected:
static LRESULT CALLBACK TempWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

static std::map<DWORD,CMyWindow*> _sWindow;

};

std::map<DWORD,CMyWindow*> CMyWindow::_sWindow;
bool CMyWindow::Create()
{
WNDCLASSEX wcex;
LPCTSTR lpszClassName = _T("ClassName");
wcex.cbSize = sizeof(WNDCLASSEX);
HINSTANCE hInstance = GetModuleHandle(NULL);
wcex.style			= CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc	= TempWndProc;
wcex.cbClsExtra		= 0;
wcex.cbWndExtra		= 0;
wcex.hInstance		= hInstance;
wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszClassName	= lpszClassName;
wcex.hIconSm		= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

RegisterClassEx(&wcex);

DWORD dw = GetCurrentThreadId();
_sWindow.insert(std::make_pair(dw,this));
_pStdthunk = (StdCallThunk *)VirtualAlloc(NULL, sizeof(StdCallThunk), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
_pStdthunk->m_mov = 0x042444c7;
_pStdthunk->m_jmp = 0xe9;

_hwnd = CreateWindow(lpszClassName, NULL, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

if (_hwnd == NULL)
{
MessageBox(NULL,TEXT("Error"),NULL,NULL);
return FALSE;
}

ShowWindow(_hwnd, SW_SHOW);
UpdateWindow(_hwnd);

return TRUE;
}

LRESULT CALLBACK CMyWindow::TempWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
DWORD dw = GetCurrentThreadId();
std::map<DWORD,CMyWindow*>::iterator it;
it = _sWindow.find(dw);
if(it == _sWindow.end() || it->second == NULL)
return false;
CMyWindow *pThis = it->second;
_sWindow.erase(it);
WNDPROC pWndProc = (WNDPROC)pThis->_pStdthunk;
pThis->_pStdthunk->m_this = (DWORD)pThis;
pThis->_pStdthunk->m_relproc = (DWORD)&CMyWindow::StaticWndProc - ((DWORD)pThis->_pStdthunk + sizeof(StdCallThunk));

pThis->_hwnd = hWnd;
SetWindowLong(hWnd, GWL_WNDPROC, (LONG)pWndProc);

return pWndProc( hWnd,  message, wParam, lParam);

}

LRESULT CALLBACK CMyWindow::StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{

return ((CMyWindow *)hWnd)->WndProc(message, wParam,  lParam);
}

LRESULT CALLBACK CMyWindow::WndProc(UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;

switch (message)
{

case WM_COMMAND:
wmId    = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// 分析菜单选择:
switch (wmId)
{
case IDM_ABOUT:
//DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
MessageBox(NULL,TEXT("AboutDlg"),TEXT("关于"),NULL);
break;
case IDM_EXIT:
DestroyWindow(_hwnd);
break;
}
break;
case WM_PAINT:
hdc = BeginPaint(_hwnd, &ps);
// TODO: 在此添加任意绘图代码...
EndPaint(_hwnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;

default:
DefWindowProc(_hwnd, message, wParam, lParam);
break;
}
return TRUE;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: