//thunk 的安全实现, 废话我就少说可,下面用代码说明吧
//WinX.h
#ifndef _WINX_H_
#define _WINX_H_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
//此代码在XP到Win7系统测试可正常执行
//函数模版用到的标记宏
#ifndef FUN_END_FLAG
//函数结束标记
#define FUN_END_FLAG(X) \
DWORD WINAPI X##_END() \
{\
return (DWORD)X##_END;\
}
//头部声明使用
#define DEF_END_FUN(X) DWORD WINAPI X##_END();
//数组使用
#define ITEM_FUN(X) X##_END,
//根据函数名获取结束函数名
#define GET_END_FUN(X) X##_END
// 局部变量的宏定义
#define DEF_THIS_VAL 0x00000000
#define VAR_LOCAL(TYPE,NAME,VALUE) TYPE NAME; __asm{MOV NAME,VALUE};
#endif
//如果定义此宏
//则使用 TemplateWinProcCode[] 作为函数模版, 其内容是通过反汇编TemplateWndProc获得
//否则根据 TemplateWndProc 生成函数模版, TemplateWndProc 是编译器生成的代码
#define USE_CODE_ARRAY
#ifdef _DEBUG
#ifndef USE_CODE_ARRAY
#define USE_CODE_ARRAY //在调试模式下,强制使用USE_CODE_ARRAY宏
#endif
#endif
//动态分配一个TemplateWndProc函数,并让函数内部变量指针指向pThis
LPVOID NewTemplateWndProc(DWORD pThis);
const unsigned char TemplateWinProcCode[]={
0x55,0x8B,0xEC,0x51,0x56,0xC7,0x45,0xFC,0x00,0x00,0x00,0x00,0x8B,0x75,0x14,0x8B,
0x4D,0xFC,0x8B,0x45,0x08,0x56,0x8B,0x75,0x10,0x89,0x41,0x04,0x8B,0x11,0x56,0x8B,
0x75,0x0C,0x56,0x50,0xFF,0x52,0x04,0x5E,0x8B,0xE5,0x5D,0xC2,0x10,0x00,0x90,0x90,
};
class CThunk
{
public:
HWND m_hWnd;
LPVOID m_WndProc;
CThunk()
{
m_hWnd=NULL;
m_WndProc=NewTemplateWndProc((DWORD)this);
}
virtual ~CThunk()
{
if (m_WndProc)
{
VirtualFree(m_WndProc,NULL,MEM_RELEASE);
}
}
virtual LRESULT WindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)=0;
};
class CWinX : public CThunk
{
public:
WNDPROC m_SubclassProc;
private:
char szclass[16];
public:
CWinX(HWND hWnd = NULL)
{
m_hWnd = hWnd;
m_SubclassProc=NULL;
szclass[0]=NULL;
}
virtual ~CWinX()
{
if (szclass[0] && m_hWnd)
{
UnregisterClass(szclass,GetModuleHandle(NULL));
}
}
CWinX& operator=(HWND hWnd)
{
m_hWnd = hWnd;
return *this;
}
inline operator HWND() const { return m_hWnd; }
inline HWND GetSafeHwnd()
{
return m_hWnd;
}
void Attach(HWND hWndNew)
{
m_hWnd = hWndNew;
}
HWND Detach()
{
HWND hWnd = m_hWnd;
m_hWnd = NULL;
return hWnd;
}
virtual LRESULT WindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
if (Msg==WM_DESTROY)
{
::PostQuitMessage(0);
return 0;
}
if (m_SubclassProc)
{
return CallWindowProc(m_SubclassProc, hWnd,Msg,wParam,lParam);
}else{
return ::DefWindowProc(hWnd,Msg,wParam,lParam);
}
}
HWND Create(LPCTSTR lpszWndClass, HWND hWndParent, int x, int y, int cx, int cy, LPCTSTR lpszWindowName = NULL, DWORD dwCsStyle=0, DWORD dwStyle = WS_OVERLAPPEDWINDOW, DWORD dwExStyle = 0, LPCTSTR lpIcon=NULL, UINT nID = 0, LPVOID lpCreateParam = NULL)
{
HINSTANCE hInstance=GetModuleHandle(NULL);
if (lpszWndClass==NULL)
{
WNDCLASSEX wceClass = {0};
wceClass.lpfnWndProc = (WNDPROC)(void *)m_WndProc;
wceClass.cbSize = sizeof(WNDCLASSEX);
wceClass.style = dwCsStyle;
wceClass.hInstance = hInstance;
wceClass.lpszMenuName=LPCSTR((dwStyle&WS_CHILD)?0:nID);
if (lpIcon) wceClass.hIcon = (HICON)LoadImage(hInstance, lpIcon, IMAGE_ICON, 32, 32, LR_CREATEDIBSECTION);
wceClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wceClass.hbrBackground = (HBRUSH) COLOR_BTNSHADOW;
if (lpIcon) wceClass.hIconSm = (HICON)LoadImage(hInstance, lpIcon, IMAGE_ICON, 16, 16, LR_CREATEDIBSECTION);
sprintf(szclass,"WinX:%08X", wceClass.lpfnWndProc);
wceClass.lpszClassName = szclass;
ATOM atm=RegisterClassEx(&wceClass);
if (atm)
{
m_hWnd=CreateWindowEx(dwExStyle, szclass, _T(lpszWindowName), dwStyle, x, y, cx, cy, hWndParent, HMENU((dwStyle&WS_CHILD)?nID:0), hInstance , NULL);
}else{
szclass[0]=NULL;
}
}else{
m_hWnd=CreateWindowEx(dwExStyle, _T(lpszWndClass), _T(lpszWindowName), dwStyle, x, y, cx, cy, hWndParent, HMENU((dwStyle&WS_CHILD)?nID:0), hInstance , NULL);
/*
if (SubclassWindow(m_hWnd))
{
ModifyStyle(0,dwStyle);
ModifyStyleEx(0,dwExStyle);
OnCreate(NULL);
}
*/
}
return m_hWnd;
}
static int MessageLoop(UINT AccelID=NULL)
{
HACCEL hAccelTable = ::LoadAccelerators(::GetModuleHandle(NULL), (LPCTSTR)AccelID);
MSG msg;
while (::GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
return msg.wParam;
}
};
//窗口函数模版
LRESULT CALLBACK TemplateWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
VAR_LOCAL(CThunk *, pThunk, DEF_THIS_VAL)
pThunk->m_hWnd=hWnd;
return pThunk->WindowProc(hWnd,message,wParam,lParam);
}
FUN_END_FLAG(TemplateWndProc) //函数结束标记
//设置函数局部变量值
BOOL SetLocalVar(void *lpFun, unsigned int size, unsigned int val, unsigned int new_val)
{
if (lpFun==NULL || size<5) return -1;
unsigned char *ptr=(unsigned char *)lpFun;
for (unsigned int i=0;i<size-4;i++)
{
if ( ptr[i]==0xC7 && ptr[i+1]==0x45 )
{
if ( *(unsigned int*)(ptr+i+3) == val )
{
*(unsigned int*)(ptr+i+3)=new_val;
return TRUE;
}
}
}
return FALSE;
}
//判断第一个函数是否跳转
DWORD GetFunTrueAddress(LPVOID pFun)
{
unsigned char *ptr=(unsigned char *)pFun;
while ( *ptr == 0xE9 )
{
int add=*(int *)(ptr+1);
ptr+=5;
ptr+=add;
}
return (DWORD)ptr;
}
//动态分配一个TemplateWndProc函数,并让函数内部变量指针指向pThis
LPVOID NewTemplateWndProc(DWORD pThis)
{
#ifdef USE_CODE_ARRAY
DWORD AllocSize=sizeof(TemplateWinProcCode);
#else
DWORD AddressStart = GetFunTrueAddress(TemplateWndProc);
DWORD AddressEnd = GetFunTrueAddress(GET_END_FUN(TemplateWndProc));
DWORD AllocSize=AddressEnd-AddressStart;
#endif
LPVOID m_WndProc=VirtualAlloc(NULL,AllocSize,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE);
if (m_WndProc)
{
#ifdef USE_CODE_ARRAY
memcpy(m_WndProc, TemplateWinProcCode, AllocSize);
*(DWORD *)((char *)m_WndProc+8)=pThis;
::FlushInstructionCache(NULL,m_WndProc,AllocSize);
return m_WndProc;
#else
memcpy(m_WndProc, (void *)AddressStart, AllocSize);
if (SetLocalVar(m_WndProc,AllocSize,DEF_THIS_VAL,pThis))
{
::FlushInstructionCache(NULL,m_WndProc,AllocSize);
return m_WndProc;
}
#endif
}
return NULL;
}
#endif //(_WINX_H_)
/*
//测试代码
#include "stdafx.h"
#include "WinX.h"
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
CWinX win;
if (win.Create(NULL,NULL,0,0,500,500,"hello"))
{
ShowWindow(win,SW_SHOW);
win.MessageLoop(IDC_MY);
}
return 0;
}
*/