zoukankan      html  css  js  c++  java
  • 利用thunk技术封装窗口类

    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 上设置断点,执行到该函数返回:

    image

    这里我们看到,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;
    
    }
    

    点击这里给我发消息
  • 相关阅读:
    读懂Netty的高性能架构之道
    大型网站架构演变和知识体系(转载)
    SAX,功能强大的 API
    防雪崩利器:熔断器 Hystrix 的原理与使用
    分布式系统设计系列 -- 基本原理及高可用策略
    分布式系统的事务处理
    分布式服务框架之服务化最佳实践
    深入理解 Java 虚拟机:JVM 高级特性与最佳实践
    内存屏障
    IntelliJ IDEA 2016 破解旗舰版
  • 原文地址:https://www.cnblogs.com/charm/p/2021031.html
Copyright © 2011-2022 走看看