Click here to Skip to main content
15,891,943 members
Articles / Web Development / HTML

.NET CLR Injection: Modify IL Code during Run-time

Rate me:
Please Sign up or sign in to vote.
4.98/5 (240 votes)
7 Aug 2014LGPL310 min read 598K   18.4K   352  
Modify methods' IL codes on runtime even if they have been JIT-compiled, supports release mode / x64 & x86, and variants of .NET versions, from 2.0 to 4.5.
/*
    EasyHook - The reinvention of Windows API hooking
 
    Copyright (C) 2009 Christoph Husse

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

    Please visit http://www.codeplex.com/easyhook for more information
    about the project and latest updates.
*/

#ifndef _EASYHOOK_H_
#define _EASYHOOK_H_

#ifdef DRIVER

    #include <ntddk.h>
    #include <ntstrsafe.h>

	typedef int BOOL;
	typedef void* HMODULE;

#else

    #define NTDDI_VERSION           NTDDI_WIN2KSP4
    #define _WIN32_WINNT            0x500
    #define _WIN32_IE_              _WIN32_IE_WIN2KSP4

    #include <windows.h>
    #include <winnt.h>
    #include <winternl.h>

#endif


#ifdef __cplusplus
extern "C"{
#endif

#ifdef EASYHOOK_EXPORTS
    #define EASYHOOK_API						__declspec(dllexport) __stdcall
	#define DRIVER_SHARED_API(type, decl)		EXTERN_C type EASYHOOK_API decl
#else
    #ifndef DRIVER
        #define EASYHOOK_API					__declspec(dllimport) __stdcall
		#define DRIVER_SHARED_API(type, decl)	EXTERN_C type EASYHOOK_API decl
    #else
        #define EASYHOOK_API					__stdcall
		#define DRIVER_SHARED_API(type, decl)	typedef type EASYHOOK_API PROC_##decl; EXTERN_C type EASYHOOK_API decl
    #endif
#endif

/* 
    This is the typical sign that a defined method is exported...

    Methods marked with this attribute need special attention
    during parameter validation and documentation.
*/
#define EASYHOOK_NT_EXPORT          EXTERN_C NTSTATUS EASYHOOK_API
#define EASYHOOK_BOOL_EXPORT        EXTERN_C BOOL EASYHOOK_API

#define MAX_HOOK_COUNT              128
#define MAX_ACE_COUNT               128
#define MAX_THREAD_COUNT            128
#define MAX_PASSTHRU_SIZE           1024 * 64

typedef struct _LOCAL_HOOK_INFO_* PLOCAL_HOOK_INFO;

typedef struct _HOOK_TRACE_INFO_
{
    PLOCAL_HOOK_INFO        Link;
}HOOK_TRACE_INFO, *TRACED_HOOK_HANDLE;

DRIVER_SHARED_API(NTSTATUS, RtlGetLastError());

DRIVER_SHARED_API(PWCHAR, RtlGetLastErrorString());

DRIVER_SHARED_API(NTSTATUS, LhInstallHook(
            void* InEntryPoint,
            void* InHookProc,
            void* InCallback,
            TRACED_HOOK_HANDLE OutHandle));

DRIVER_SHARED_API(NTSTATUS, LhUninstallAllHooks());

DRIVER_SHARED_API(NTSTATUS, LhUninstallHook(TRACED_HOOK_HANDLE InHandle));

DRIVER_SHARED_API(NTSTATUS, LhWaitForPendingRemovals());

/*
    Setup the ACLs after hook installation. Please note that every
    hook starts suspended. You will have to set a proper ACL to
    make it active!
*/
#ifdef DRIVER

	DRIVER_SHARED_API(NTSTATUS, LhSetInclusiveACL(
				ULONG* InProcessIdList,
				ULONG InProcessCount,
				TRACED_HOOK_HANDLE InHandle));

	DRIVER_SHARED_API(NTSTATUS, LhSetExclusiveACL(
				ULONG* InProcessIdList,
				ULONG InProcessCount,
				TRACED_HOOK_HANDLE InHandle));

	DRIVER_SHARED_API(NTSTATUS, LhSetGlobalInclusiveACL(
				ULONG* InProcessIdList,
				ULONG InProcessCount));

	DRIVER_SHARED_API(NTSTATUS, LhSetGlobalExclusiveACL(
				ULONG* InProcessIdList,
				ULONG InProcessCount));

	DRIVER_SHARED_API(NTSTATUS, LhIsProcessIntercepted(
				TRACED_HOOK_HANDLE InHook,
				ULONG InProcessID,
				BOOL* OutResult));

#else

	EASYHOOK_NT_EXPORT LhSetInclusiveACL(
				ULONG* InThreadIdList,
				ULONG InThreadCount,
				TRACED_HOOK_HANDLE InHandle);

	EASYHOOK_NT_EXPORT LhSetExclusiveACL(
				ULONG* InThreadIdList,
				ULONG InThreadCount,
				TRACED_HOOK_HANDLE InHandle);

	EASYHOOK_NT_EXPORT LhSetGlobalInclusiveACL(
				ULONG* InThreadIdList,
				ULONG InThreadCount);

	EASYHOOK_NT_EXPORT LhSetGlobalExclusiveACL(
				ULONG* InThreadIdList,
				ULONG InThreadCount);

	EASYHOOK_NT_EXPORT LhIsThreadIntercepted(
				TRACED_HOOK_HANDLE InHook,
				ULONG InThreadID,
				BOOL* OutResult);

#endif // !DRIVER

/*
    The following barrier methods are meant to be used in hook handlers only!

    They will all fail with STATUS_NOT_SUPPORTED if called outside a
    valid hook handler...
*/
DRIVER_SHARED_API(NTSTATUS, LhBarrierGetCallback(PVOID* OutValue));

DRIVER_SHARED_API(NTSTATUS, LhBarrierGetReturnAddress(PVOID* OutValue));

DRIVER_SHARED_API(NTSTATUS, LhBarrierGetAddressOfReturnAddress(PVOID** OutValue));

DRIVER_SHARED_API(NTSTATUS, LhBarrierBeginStackTrace(PVOID* OutBackup));

DRIVER_SHARED_API(NTSTATUS, LhBarrierEndStackTrace(PVOID InBackup));

typedef struct _MODULE_INFORMATION_* PMODULE_INFORMATION;

typedef struct _MODULE_INFORMATION_
{	
	PMODULE_INFORMATION		Next;
	UCHAR*					BaseAddress;
	ULONG					ImageSize;
	CHAR					Path[256];
	PCHAR					ModuleName;
}MODULE_INFORMATION;

EASYHOOK_NT_EXPORT LhUpdateModuleInformation();

DRIVER_SHARED_API(NTSTATUS, LhBarrierPointerToModule(
			PVOID InPointer,
			MODULE_INFORMATION* OutModule));

DRIVER_SHARED_API(NTSTATUS, LhEnumModules(
			HMODULE* OutModuleArray, 
            ULONG InMaxModuleCount,
            ULONG* OutModuleCount));

DRIVER_SHARED_API(NTSTATUS, LhBarrierGetCallingModule(MODULE_INFORMATION* OutModule));

DRIVER_SHARED_API(NTSTATUS, LhBarrierCallStackTrace(
            PVOID* OutMethodArray, 
            ULONG InMaxMethodCount,
            ULONG* OutMethodCount));

#ifdef DRIVER

	#define DRIVER_EXPORT(proc)				PROC_##proc * proc

	#define EASYHOOK_INTERFACE_v_1			0x0001

	#define EASYHOOK_WIN32_DEVICE_NAME		L"\\\\.\\EasyHook"
	#define EASYHOOK_DEVICE_NAME			L"\\Device\\EasyHook"
	#define EASYHOOK_DOS_DEVICE_NAME		L"\\DosDevices\\EasyHook"
	#define FILE_DEVICE_EASYHOOK			0x893F

	typedef struct _EASYHOOK_INTERFACE_API_v_1_
	{
		DRIVER_EXPORT(RtlGetLastError);
		DRIVER_EXPORT(RtlGetLastErrorString);
		DRIVER_EXPORT(LhInstallHook);
		DRIVER_EXPORT(LhUninstallHook);
		DRIVER_EXPORT(LhWaitForPendingRemovals);
		DRIVER_EXPORT(LhBarrierGetCallback);
		DRIVER_EXPORT(LhBarrierGetReturnAddress);
		DRIVER_EXPORT(LhBarrierGetAddressOfReturnAddress);
		DRIVER_EXPORT(LhBarrierBeginStackTrace);
		DRIVER_EXPORT(LhBarrierEndStackTrace);
		DRIVER_EXPORT(LhBarrierPointerToModule);
		DRIVER_EXPORT(LhBarrierGetCallingModule);
		DRIVER_EXPORT(LhBarrierCallStackTrace);
		DRIVER_EXPORT(LhSetGlobalExclusiveACL);
		DRIVER_EXPORT(LhSetGlobalInclusiveACL);
		DRIVER_EXPORT(LhSetExclusiveACL);
		DRIVER_EXPORT(LhSetInclusiveACL);
		DRIVER_EXPORT(LhIsProcessIntercepted);
	}EASYHOOK_INTERFACE_API_v_1, *PEASYHOOK_INTERFACE_API_v_1;

	typedef struct _EASYHOOK_DEVICE_EXTENSION_
	{
		ULONG								MaxVersion;
		// enumeration of APIs
		EASYHOOK_INTERFACE_API_v_1			API_v_1;
	}EASYHOOK_DEVICE_EXTENSION, *PEASYHOOK_DEVICE_EXTENSION;

	static NTSTATUS EasyHookQueryInterface(
		ULONG InInterfaceVersion,
		PVOID OutInterface,
		PFILE_OBJECT* OutEasyHookDrv)
	{
	/*
		Description:
			
			Provides a convenient way to load the desired EasyHook interface.
			The method will only work if the EasyHook support driver is loaded, of course.
			If you don't need the interface anymore, you have to release the
			file object with ObDereferenceObject().

		Parameters:
			
			- InInterfaceVersion

				The desired interface version. Any future EasyHook driver will ALWAYS
				be backward compatible. This is the reason why I provide such a flexible
				interface mechanism. 

			- OutInterface

				A pointer to the interface structure to be filled with data. If you specify
				EASYHOOK_INTERFACE_v_1 as InInterfaceVersion, you will have to provide a
				pointer to a EASYHOOK_INTERFACE_API_v_1 structure, for example...

			- OutEasyHookDrv

				A reference to the EasyHook driver. Make sure that you dereference it if
				you don't need the interface any longer! As long as you keep this handle,
				the EasyHook driver CAN'T be unloaded...

	*/
		UNICODE_STRING				DeviceName;
		PDEVICE_OBJECT				hEasyHookDrv = NULL;
		NTSTATUS					NtStatus = STATUS_INTERNAL_ERROR;
		EASYHOOK_DEVICE_EXTENSION*	DevExt;

		/*
			Open log file...
		*/
		RtlInitUnicodeString(&DeviceName, EASYHOOK_DEVICE_NAME);

		if(!NT_SUCCESS(NtStatus = IoGetDeviceObjectPointer(&DeviceName, FILE_READ_DATA, OutEasyHookDrv, &hEasyHookDrv)))
			return NtStatus;

		__try
		{
			DevExt = (EASYHOOK_DEVICE_EXTENSION*)hEasyHookDrv->DeviceExtension;

			if(DevExt->MaxVersion < InInterfaceVersion)
				return STATUS_NOT_SUPPORTED;

			switch(InInterfaceVersion)
			{
			case EASYHOOK_INTERFACE_v_1: memcpy(OutInterface, &DevExt->API_v_1, sizeof(DevExt->API_v_1)); break;
			default: 
				return STATUS_INVALID_PARAMETER_1;
			}

			return STATUS_SUCCESS;
		}
		__except(EXCEPTION_EXECUTE_HANDLER)
		{
			ObDereferenceObject(*OutEasyHookDrv);

			return NtStatus;
		}
	}


#endif // DRIVER

#ifndef DRIVER
	/*
		Debug helper API.
	*/
	EASYHOOK_BOOL_EXPORT DbgIsAvailable();

	EASYHOOK_BOOL_EXPORT DbgIsEnabled();

	EASYHOOK_NT_EXPORT DbgAttachDebugger();

	EASYHOOK_NT_EXPORT DbgDetachDebugger();

	EASYHOOK_NT_EXPORT DbgGetThreadIdByHandle(
				HANDLE InThreadHandle,
				ULONG* OutThreadId);

	EASYHOOK_NT_EXPORT DbgGetProcessIdByHandle(
				HANDLE InProcessHandle,
				ULONG* OutProcessId);

	EASYHOOK_NT_EXPORT DbgHandleToObjectName(
				HANDLE InNamedHandle,
				UNICODE_STRING* OutNameBuffer,
				ULONG InBufferSize,
				ULONG* OutRequiredSize);


	/*
		Injection support API.
	*/
	typedef struct _REMOTE_ENTRY_INFO_
	{
		ULONG           HostPID;
		UCHAR*          UserData;
		ULONG           UserDataSize;
	}REMOTE_ENTRY_INFO;

	typedef void __stdcall REMOTE_ENTRY_POINT(REMOTE_ENTRY_INFO* InRemoteInfo);

	#define EASYHOOK_INJECT_DEFAULT				0x00000000
	#define EASYHOOK_INJECT_STEALTH				0x10000000 // (experimental)
	#define EASYHOOK_INJECT_NET_DEFIBRILLATOR	0x20000000 // USE THIS ONLY IN UNMANAGED CODE AND ONLY WITH CreateAndInject() FOR MANAGED PROCESSES!!

	EASYHOOK_NT_EXPORT RhCreateStealthRemoteThread(
				ULONG InTargetPID,
				LPTHREAD_START_ROUTINE InRemoteRoutine,
				PVOID InRemoteParam,
				HANDLE* OutRemoteThread);

	EASYHOOK_NT_EXPORT RhInjectLibrary(
				ULONG InTargetPID,
				ULONG InWakeUpTID,
				ULONG InInjectionOptions,
				WCHAR* InLibraryPath_x86,
				WCHAR* InLibraryPath_x64,
				PVOID InPassThruBuffer,
				ULONG InPassThruSize);

	EASYHOOK_NT_EXPORT RhCreateAndInject(
				WCHAR* InEXEPath,
				WCHAR* InCommandLine,
				ULONG InProcessCreationFlags,
				ULONG InInjectionOptions,
				WCHAR* InLibraryPath_x86,
				WCHAR* InLibraryPath_x64,
				PVOID InPassThruBuffer,
				ULONG InPassThruSize,
				ULONG* OutProcessId);

	EASYHOOK_BOOL_EXPORT RhIsX64System();

	EASYHOOK_NT_EXPORT RhIsX64Process(
				ULONG InProcessId,
				BOOL* OutResult);

	EASYHOOK_BOOL_EXPORT RhIsAdministrator();

	EASYHOOK_NT_EXPORT RhWakeUpProcess();

	EASYHOOK_NT_EXPORT RhInstallSupportDriver();

	EASYHOOK_NT_EXPORT RhInstallDriver(
			WCHAR* InDriverPath,
			WCHAR* InDriverName);

	typedef struct _GACUTIL_INFO_* HGACUTIL;


#endif // !DRIVER

#ifdef __cplusplus
};
#endif

#endif

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 GNU Lesser General Public License (LGPLv3)


Written By
Team Leader
China China
Jerry is from China. He was captivated by computer programming since 13 years old when first time played with Q-Basic.



  • Windows / Linux & C++
  • iOS & Obj-C
  • .Net & C#
  • Flex/Flash & ActionScript
  • HTML / CSS / Javascript
  • Gaming Server programming / video, audio processing / image & graphics


Contact: vcer(at)qq.com
Chinese Blog: http://blog.csdn.net/wangjia184

Comments and Discussions