Click here to Skip to main content
15,885,546 members
Articles / Programming Languages / MSIL

.NET Internals and Code Injection

Rate me:
Please Sign up or sign in to vote.
4.91/5 (53 votes)
14 May 2008CPOL24 min read 144K   5.2K   188  
An article about .NET internals and code injection
#include "stdafx.h"
#include <tchar.h>
#include <CorHdr.h>
#include "corinfo.h"
#include "corjit.h"
#include "DisasMSIL.h"

HINSTANCE hInstance;

extern "C" __declspec(dllexport) void HookJIT();

VOID DisplayMethodAndCalls(ICorJitInfo *comp,
						   CORINFO_METHOD_INFO *info);


BOOL APIENTRY DllMain( HMODULE hModule,
					   DWORD  dwReason,
					   LPVOID lpReserved
					  )
{
	hInstance = (HINSTANCE) hModule;

	HookJIT();

	return TRUE;
}


//
// Hook JIT's compileMethod
//

BOOL bHooked = FALSE;

ULONG_PTR *(__stdcall *p_getJit)();
typedef int (__stdcall *compileMethod_def)(ULONG_PTR classthis, ICorJitInfo *comp, 
										   CORINFO_METHOD_INFO *info, unsigned flags,         
										   BYTE **nativeEntry, ULONG  *nativeSizeOfCode);
struct JIT
{
	compileMethod_def compileMethod;
};

compileMethod_def compileMethod;

int __stdcall my_compileMethod(ULONG_PTR classthis, ICorJitInfo *comp,
							   CORINFO_METHOD_INFO *info, unsigned flags,         
							   BYTE **nativeEntry, ULONG  *nativeSizeOfCode);

extern "C" __declspec(dllexport) void HookJIT()
{
	if (bHooked) return;

	LoadLibrary(_T("mscoree.dll"));

	HMODULE hJitMod = LoadLibrary(_T("mscorjit.dll"));

	if (!hJitMod)
		return;

	p_getJit = (ULONG_PTR *(__stdcall *)()) GetProcAddress(hJitMod, "getJit");

	if (p_getJit)
	{
		JIT *pJit = (JIT *) *((ULONG_PTR *) p_getJit());

		if (pJit)
		{
			DWORD OldProtect;
			VirtualProtect(pJit, sizeof (ULONG_PTR), PAGE_READWRITE, &OldProtect);
			compileMethod =  pJit->compileMethod;
			pJit->compileMethod = &my_compileMethod;
			VirtualProtect(pJit, sizeof (ULONG_PTR), OldProtect, &OldProtect);
			bHooked = TRUE;
		}
	}
}

//
// hooked compileMethod
//
/*__declspec (naked) */
int __stdcall my_compileMethod(ULONG_PTR classthis, ICorJitInfo *comp,
							   CORINFO_METHOD_INFO *info, unsigned flags,         
							   BYTE **nativeEntry, ULONG  *nativeSizeOfCode)
{
	// in case somebody hooks us (x86 only)
#ifdef _M_IX86
	__asm 
	{
		nop
			nop
			nop
			nop
			nop
			nop
			nop
			nop
			nop
			nop
			nop
			nop
			nop
			nop
	}
#endif

	// call original method
	// I'm not using the naked + jmp approach to avoid x64 incompatibilities
	int nRet = compileMethod(classthis, comp, info, flags, nativeEntry, nativeSizeOfCode);

	//
	// Displays the current method and its calls
	//

	DisplayMethodAndCalls(comp, info);

	return nRet;
}

VOID DisplayMethodAndCalls(ICorJitInfo *comp,
						   CORINFO_METHOD_INFO *info)
{
	const char *szMethodName = NULL;
	const char *szClassName = NULL;

	szMethodName = comp->getMethodName(info->ftn, &szClassName);

	char CurMethod[200];

	sprintf_s(CurMethod, 200, "%s::%s", szClassName, szMethodName);

	char Calls[0x1000];

	strcpy_s(Calls, 0x1000, "Methods called:\r\n\r\n");

	//
	// retrieve calls
	//

#define MAX_INSTR      100

	ILOPCODE_STRUCT ilopar[MAX_INSTR];

	DISASMSIL_OFFSET CodeBase = 0;

	BYTE *pCur = info->ILCode;
	UINT nSize = info->ILCodeSize;

	UINT nDisasmedInstr;

	while (DisasMSIL(pCur, nSize, CodeBase, ilopar, MAX_INSTR,
		&nDisasmedInstr))
	{
		//
		// check the instructions for calls
		//

		for (UINT x = 0; x < nDisasmedInstr; x++)
		{
			if (info->ILCode[ilopar[x].Offset] == ILOPCODE_CALL)
			{
				DWORD dwToken = *((DWORD *) &info->ILCode[ilopar[x].Offset + 1]);

				CORINFO_METHOD_HANDLE hCallHandle =
					comp->findMethod(info->scope, dwToken, info->ftn);

				szMethodName = comp->getMethodName(hCallHandle, &szClassName);

				strcat_s(Calls, 0x1000, szClassName);
				strcat_s(Calls, 0x1000, "::");
				strcat_s(Calls, 0x1000, szMethodName);
				strcat_s(Calls, 0x1000, "\r\n");
			}
		}

		//
		// end loop?
		//

		if (nDisasmedInstr < MAX_INSTR) break;

		//
		// next instructions
		//

		DISASMSIL_OFFSET next = ilopar[nDisasmedInstr - 1].Offset - CodeBase;
		next += ilopar[nDisasmedInstr - 1].Size;

		pCur += next;
		nSize -= next;
		CodeBase += next;
	}

	//
	// Show MessageBox
	//

	MessageBoxA(0, Calls, CurMethod, MB_ICONINFORMATION);
}

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)


Written By
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.

Comments and Discussions