#include "Thunk.h"
//Implementation of class Thunk
Thunk::Thunk( void )
{
}
Thunk::~Thunk(void)
{
Destroy();
}
LPVOID Thunk::Create(DWORD dwThis, DWORD methodPtr, CallConversion methodConv, CallConversion cbConv)
{
//DWORD dwMethodAddr = union_cast<DWORD, TMethodPtr>(methodPtr);
PBYTE pThunkCode = NULL;
SYSTEM_INFO si = {0};
GetSystemInfo(&si);
// allocate one page memory and add EXECUTTION access right,
// just for DEP(Data Execution Erevention,Win XP,2003,Vista,7)
pThunkCode = (PBYTE)VirtualAlloc(
NULL,
si.dwPageSize, // at least one page size
MEM_COMMIT,
PAGE_EXECUTE_READWRITE );
if (NULL == pThunkCode)
{
return (LPVOID)0;
}
// 1. callback : __stdcall or __cdecl
// class method : __stdcall
//
// ------machine code----- ------asm code-----------------------
// FF 34 24 push dword ptr [esp]
// C7 44 24 04 44 33 22 00 mov dword ptr [esp+4],223344h[this]
// E9 33 22 11 00 jmp 0x00112233[method]
// ----------------------- -------------------------------------
if ( StdCall == methodConv && (StdCall == cbConv || CDecl == cbConv ) )
{
const SIZE_T MACHINE_CODE_SIZE = 16;
DWORD dwJmpOffset = (DWORD)((DWORD)methodPtr - (DWORD)&pThunkCode[MACHINE_CODE_SIZE] );
*((DWORD*)(&pThunkCode[0 ])) = 0x002434FF;
*((DWORD*)(&pThunkCode[3 ])) = 0x042444C7;
*((DWORD*)(&pThunkCode[7 ])) = dwThis;
*((BYTE *)(&pThunkCode[11])) = 0xE9;
*((DWORD*)(&pThunkCode[12])) = dwJmpOffset;
// Add to map container.
m_mapThunkItem[ methodPtr] = (pThunkCode);
}
// 2. callback : __stdcall
// class method : __thiscall
//
// ------machine code----- ------asm code-----------------------
// B9 00 11 22 33 mov ecx,33221100h[this pointer]
// E9 00 11 22 33 jmp 33221100h
// ------machine code----- ------asm code-----------------------
else if ( ThisCall == methodConv && StdCall == cbConv )
{
const SIZE_T MACHINE_CODE_SIZE = 10;
DWORD dwJmpOffset = (DWORD)((DWORD)methodPtr - (DWORD)&pThunkCode[MACHINE_CODE_SIZE] );
*((BYTE *)(&pThunkCode[0])) = 0xB9;
*((DWORD*)(&pThunkCode[1])) = dwThis;
*((BYTE *)(&pThunkCode[5])) = 0xE9;
*((DWORD*)(&pThunkCode[6])) = dwJmpOffset;
// Add to map container.
m_mapThunkItem[ methodPtr] = (pThunkCode);
}
else
{
if (pThunkCode != NULL)
{
VirtualFree(pThunkCode, si.dwPageSize, MEM_RELEASE);
}
(pThunkCode) = NULL;
}
return (LPVOID)pThunkCode;
}
LPVOID Thunk::operator[]( DWORD methodPtr )
{
return (m_mapThunkItem[methodPtr]);
}
void Thunk::Destroy()
{
SYSTEM_INFO si = {0};
GetSystemInfo(&si);
std::map<DWORD, LPVOID>::const_iterator iter = m_mapThunkItem.begin();
for ( ; iter != m_mapThunkItem.end(); iter++)
{
if ( iter->second != NULL )
VirtualFree( iter->second, si.dwPageSize, MEM_RELEASE );
}
}