Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

.NET Internals and Native Compiling

, 30 May 2008 CPOL
An article about .NET internals and native compiling.
fxloader.zip
fxloader
detoured.lib
detours.lib
release
detoured.dll
fxloader.exe
rebtest.exe
native_msgbox.zip
nvcoree
// 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);
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Daniel Pistelli
Software Developer
Germany Germany
The languages I know best are: C, C++, C#, Assembly (x86, x64, ARM), MSIL, Python, Lua. The environments I frequently use are: Qt, Win32, MFC, .NET, WDK. I'm a developer and a reverse engineer and I like playing around with internals.
 
You can find most of my work at http://ntcore.com.

| Advertise | Privacy | Mobile
Web04 | 2.8.141015.1 | Last Updated 30 May 2008
Article Copyright 2008 by Daniel Pistelli
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid