// fxloader.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "fxloader.h"
#include "detours.h"
#define ASSEMBLY_TO_LOAD _T("rebtest.exe")
#define ASSEMBLY_TO_LOAD_A "rebtest.exe"
#define ASSEMBLY_TO_LOAD_W L"rebtest.exe"
#define IS_FLAG(Value, Flag) ((Value & Flag) == Flag)
typedef ULONG_PTR THUNK;
VOID FixIAT(VOID *pBase, IMAGE_NT_HEADERS *pNtHeaders);
VOID FixReloc(VOID *pBase, IMAGE_NT_HEADERS *pNtHeaders);
HMODULE pMainBaseAddr = NULL;
CHAR MainAsmNameA[MAX_PATH];
WCHAR MainAsmNameW[MAX_PATH];
HMODULE (WINAPI *pGetModuleHandleA)(LPCSTR lpModuleName) = GetModuleHandleA;
HMODULE (WINAPI *pGetModuleHandleW)(LPCWSTR lpModuleName) = GetModuleHandleW;
DWORD (WINAPI *pGetModuleFileNameA)(HMODULE hModule, LPCH lpFilename,
DWORD nSize) = GetModuleFileNameA;
DWORD (WINAPI *pGetModuleFileNameW)(HMODULE hModule, LPWCH lpFilename,
DWORD nSize) = GetModuleFileNameW;
HMODULE WINAPI MyGetModuleHandleA(LPCSTR lpModuleName);
HMODULE WINAPI MyGetModuleHandleW(LPCWSTR lpModuleName);
DWORD WINAPI MyGetModuleFileNameA(HMODULE hModule, LPCH lpFilename, DWORD nSize);
DWORD WINAPI MyGetModuleFileNameW(HMODULE hModule, LPWCH lpFilename, DWORD nSize);
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
//////////////////////////////////////////////////////////////////////////
// TODO: hook registry and load library
//////////////////////////////////////////////////////////////////////////
HMODULE hMainAsm = LoadLibrary(ASSEMBLY_TO_LOAD);
if (hMainAsm == NULL) return 0;
pMainBaseAddr = hMainAsm;
GetModuleFileNameA(NULL, MainAsmNameA, MAX_PATH);
CHAR *cSlash = strrchr(MainAsmNameA, '\\') + 1;
strcpy(cSlash, ASSEMBLY_TO_LOAD_A);
GetModuleFileNameW(NULL, MainAsmNameW, MAX_PATH);
WCHAR *wSlash = wcsrchr(MainAsmNameW, '\\') + 1;
wcscpy(wSlash, ASSEMBLY_TO_LOAD_W);
//
// Hook GetModuleXXXX APIs
//
DetourRestoreAfterWith();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)pGetModuleFileNameA, MyGetModuleFileNameA);
DetourAttach(&(PVOID&)pGetModuleFileNameW, MyGetModuleFileNameW);
DetourAttach(&(PVOID&)pGetModuleHandleA, MyGetModuleHandleA);
DetourAttach(&(PVOID&)pGetModuleHandleW, MyGetModuleHandleW);
LONG err = DetourTransactionCommit();
if (err != NO_ERROR) return 0;
//
IMAGE_DOS_HEADER *pDosHeader = (IMAGE_DOS_HEADER *) hMainAsm;
IMAGE_NT_HEADERS *pNtHeaders = (IMAGE_NT_HEADERS *) (pDosHeader->e_lfanew +
(ULONG_PTR) pDosHeader);
if (pNtHeaders->OptionalHeader.ImageBase != (ULONG_PTR) pDosHeader)
FixReloc(pDosHeader, pNtHeaders);
FixIAT(pDosHeader, pNtHeaders);
// retrieve entry point
VOID *pEntryPoint = (VOID *) (pNtHeaders->OptionalHeader.AddressOfEntryPoint +
(ULONG_PTR) pDosHeader);
__asm
{
jmp pEntryPoint
}
return 0;
}
HMODULE WINAPI MyGetModuleHandleW(LPCWSTR lpModuleName)
{
if (lpModuleName == NULL)
return pMainBaseAddr;
return pGetModuleHandleW(lpModuleName);
}
HMODULE WINAPI MyGetModuleHandleA(LPCSTR lpModuleName)
{
if (lpModuleName == NULL)
return pMainBaseAddr;
return pGetModuleHandleA(lpModuleName);
}
DWORD WINAPI MyGetModuleFileNameA(HMODULE hModule, LPCH lpFilename, DWORD nSize)
{
if (hModule == NULL)
{
strcpy_s(lpFilename, nSize, MainAsmNameA);
return (DWORD) strlen(lpFilename);
}
return pGetModuleFileNameA(hModule, lpFilename, nSize);
}
DWORD WINAPI MyGetModuleFileNameW(HMODULE hModule, LPWCH lpFilename, DWORD nSize)
{
if (hModule == NULL)
{
wcscpy_s(lpFilename, nSize, MainAsmNameW);
return (DWORD) wcslen(lpFilename);
}
return pGetModuleFileNameW(hModule, lpFilename, nSize);
}
// x64 compatible
VOID FixIAT(VOID *pBase, IMAGE_NT_HEADERS *pNtHeaders)
{
if (pNtHeaders->OptionalHeader.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress == 0)
return;
IMAGE_IMPORT_DESCRIPTOR *pImpDescr = (IMAGE_IMPORT_DESCRIPTOR *)
(pNtHeaders->OptionalHeader.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress +
(ULONG_PTR) pBase);
DWORD dwOldIATProtect;
VOID *pIAT = NULL;
if (pNtHeaders->OptionalHeader.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress != 0)
{
VOID *pIAT = (VOID *) (pNtHeaders->OptionalHeader.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress +
(ULONG_PTR) pBase);
VirtualProtect(pIAT,
pNtHeaders->OptionalHeader.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IAT].Size,
PAGE_EXECUTE_READWRITE,
&dwOldIATProtect);
}
while (pImpDescr->Name != 0)
{
char *DllName = (char *) (pImpDescr->Name +
(ULONG_PTR) pBase);
HMODULE hImpDll = LoadLibraryA(DllName);
if (hImpDll == NULL) continue;
THUNK *pThunk;
if (pImpDescr->OriginalFirstThunk)
pThunk = (THUNK *)(pImpDescr->OriginalFirstThunk +
(ULONG_PTR) pBase);
else
pThunk = (THUNK *)(pImpDescr->FirstThunk +
(ULONG_PTR) pBase);
THUNK *pIATThunk = (THUNK *) (pImpDescr->FirstThunk +
(ULONG_PTR) pBase);
while (*pThunk)
{
if (IS_FLAG(*pThunk, IMAGE_ORDINAL_FLAG))
{
*pIATThunk = (THUNK) GetProcAddress(hImpDll,
(LPCSTR) (*pThunk ^ IMAGE_ORDINAL_FLAG));
}
else
{
char *pImpFunc = (char *) (sizeof (WORD) + ((ULONG_PTR) *pThunk) +
((ULONG_PTR) pBase));
*pIATThunk = (THUNK) GetProcAddress(hImpDll, pImpFunc);
}
pThunk++;
pIATThunk++;
}
pImpDescr++;
}
if (pIAT)
{
VirtualProtect(pIAT,
pNtHeaders->OptionalHeader.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IAT].Size,
dwOldIATProtect,
&dwOldIATProtect);
}
}
// x86 recycled code from an older article
VOID FixReloc(VOID *pBase, IMAGE_NT_HEADERS *pNtHeaders)
{
//
// Set first section to writeable in order to fix
// the relocations in the code
//
IMAGE_SECTION_HEADER *pCodeSect = (IMAGE_SECTION_HEADER *)
IMAGE_FIRST_SECTION(pNtHeaders);
VOID *pCode = (VOID *) (pCodeSect->VirtualAddress + (ULONG_PTR) pBase);
DWORD dwOldCodeProtect;
VirtualProtect(pCode,
pCodeSect->Misc.VirtualSize,
PAGE_READWRITE,
&dwOldCodeProtect);
//
// Relocate
//
DWORD Delta = (DWORD)(((ULONG_PTR) pBase) -
pNtHeaders->OptionalHeader.ImageBase);
DWORD RelocRva;
if (!(RelocRva = pNtHeaders->OptionalHeader.DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress))
return;
IMAGE_BASE_RELOCATION *ImgBaseReloc =
(IMAGE_BASE_RELOCATION *) (RelocRva + (ULONG_PTR) pBase);
WORD *wData;
do
{
if (!ImgBaseReloc->SizeOfBlock)
break;
UINT nItems = (ImgBaseReloc->SizeOfBlock -
IMAGE_SIZEOF_BASE_RELOCATION) / sizeof (WORD);
wData = (WORD *)(IMAGE_SIZEOF_BASE_RELOCATION +
(ULONG_PTR) ImgBaseReloc);
for (UINT i = 0; i < nItems; i++)
{
DWORD Offset = (*wData & 0xFFF) + ImgBaseReloc->VirtualAddress;
DWORD Type = *wData >> 12;
if (Type != IMAGE_REL_BASED_ABSOLUTE)
{
DWORD *pBlock = (DWORD *)(Offset + (ULONG_PTR) pBase);
*pBlock += Delta;
}
wData++;
}
ImgBaseReloc = (PIMAGE_BASE_RELOCATION) wData;
} while (*(DWORD *) wData);
//
// Restore memory settings
//
VirtualProtect(pCode,
pCodeSect->Misc.VirtualSize,
dwOldCodeProtect,
&dwOldCodeProtect);
}