inline hook

Inline hook的步骤

1。获得要inline hook的函数在内存中的地址
2。实现T_MyFunc()与MyFunc函数,在该函数中将参数压栈并调用MyFunc函数处理。
3。HOOK。保存函数开头的指令到某个内存中,并在该内存末尾附加JMP指令到开头指令的后面的指令。并将开头的指令替换为JMP T_MyFunc地址。
4。在T_MyFunc执行完MyFunc之后,调用保存的指令,跳回去。


直接的jmp分3种 
Short Jump(短跳转)机器码 EB rel8 
只能跳转到256字节的范围内 
Near Jump(近跳转)机器码 E9 rel16/32 
可跳至同一个段的范围内的地址 
Far Jump(远跳转)机器码EA ptr 16:16/32 
可跳至任意地址,使用48位/32位全指针 


例子:

_declspec(naked) T_MyFunc(……)
{
	_asm
	{
		mov edi, edi
		push ebp
		mov ebp ,esp
		//参数压栈,传给MyFunc
		push [ebp+0ch]
		push [ebp+8]
		call MyFunc 
		//获得结果,并跳回原来的指令
		cmp eax,1
		jz end
		mov eax,FuncAddress 
		add eax,5 
		jmp eax
			
end:
		//恢复栈
		pop ebp
		retn 8
	}
}

Naked call
编译器不会给这种函数增加初始化和清理代码,不能用return返回返回值,只能用插入汇编返回结果。

//naked 调用约定。用户自己清理堆栈。不能进行原型声明,否则错误。
__declspec(naked) int add(int a,int b)
{
    __asm push ebp //必须加上两句修改栈帧,否则引用了错误的数据
    __asm mov ebp, esp
    __asm mov eax, a
    __asm add eax, b
    __asm pop ebp
    __asm ret
}

这个修饰是和__stdcall及cdecl结合使用的,前面是它和cdecl结合使用的代码,对于和stdcall结合的代码,则变成:
__declspec(naked) int __stdcall function(int a,int b) 
{
    __asm mov eax, a
    __asm add eax, b
    __asm ret 8 //注意后面的8
}
cdecl/fastcall/stdcall/thiscall/nakedcall
扩展阅读(重要):Calling convention: http://gccfeli.cn/tag/naked-call

例子:SwapContext inline hook

#include <ntddk.h>
#include <ntimage.h>
#include <ntdef.h>
#include "hash.h"
#include "xde.h"
#include "main.h"

typedef struct _BYTECODE
{
	BYTE *pAddress;
	SIZE_T size;
} BYTECODE, *PBYTECODE;

typedef struct _OFFSETS
{
	BYTE threadsProcess;
	BYTE CID;
	BYTE imageFilename;
	BYTE crossThreadFlags;
	unsigned  PID;
	unsigned PPID;

	unsigned pecreatetimeoff;
	unsigned peexittimeoff;
} OFFSETS, *POFFSETS;

#define JMP_SIZE 5
#define SIG_SIZE 20
#define HASHTABLE_SIZE 256
#define MAINTAG1 'NIAM'

// NOTICE: WinDbg gives offsets in BYTEs, we use DWORDS.
OFFSETS offsets;
// The beginning of the SwapContext function is stored here.
BYTE *pSwapContext = NULL;
// The trampoline function which executes the replaced code and
// passes control to the hooked function.
BYTECODE trampoline;
// Inline assembler does not support structures, so this points
// directly to the pCode of the _BYTECODE structure.
BYTE *pTrampoline = NULL;
// The hashtable where we store the data.
PHASHTABLE pHashTable = NULL;
DWORD num = 0;

extern  USHORT  *NtBuildNumber;

const WCHAR deviceLinkBuffer[]  = L"\\DosDevices\\SwapContextDrv";
const WCHAR deviceNameBuffer[]  = L"\\Device\\SwapContextDrv";

PDEVICE_OBJECT g_HookDevice;

ULONG gNameOffset = 0x174;
PsLookupThreadByThreadId(
        IN PVOID UniqueThreadId,
        OUT PETHREAD *ppEthread
);
KIRQL			OldIrql;
KSPIN_LOCK		DpcSpinLock;

ULONG GetLocationOfProcessName(PEPROCESS CurrentProc)
{
    ULONG ul_offset;

	for(ul_offset = 0; ul_offset < PAGE_SIZE; ul_offset++) // This will fail if EPROCESS
												           // grows bigger than PAGE_SIZE
	{
		if( !strncmp( "System", (PCHAR) CurrentProc + ul_offset, strlen("System")))
		{
			return ul_offset;
		}
	}

	return (ULONG) 0;
}

// This function returns an MDL to an nonpaged virtual memory area.
// 
// IN pVirtualAddress Virtual address to the start of the memory area.
// IN length Length of the memory area in bytes.
//
// OUT PMDL Mdl to the nonpaged virtual memory area.
//
PMDL GetMdlForNonPagedMemory(PVOID pVirtualAddress, SIZE_T length)
{
	PMDL pMdl;

	if (length >= (PAGE_SIZE * (65535 - sizeof(MDL)) / sizeof(ULONG_PTR)))
	{
		DbgPrint("Size parameter passed to IoAllocateMdl is too big!\n");
		return NULL;
	}

	pMdl = IoAllocateMdl((PVOID)pVirtualAddress, length, FALSE, FALSE, NULL);
	if (NULL == pMdl)
	{
		DbgPrint("IoAllocateMdl returned NULL!\n");
		return NULL;
	}

	MmBuildMdlForNonPagedPool(pMdl);

	return pMdl;
}

// This function returns an MDL to a paged virtual memory area while
// making sure the pages are not paged out to the disk.
// 
// IN pVirtualAddress Virtual address to the start of the memory area.
// IN length Length of the memory area in bytes.
// IN operation Desired mode of operation.
//
// OUT PMDL Mdl to the locked and nonpaged memory area.
//
PMDL GetMdlForPagedMemory(PVOID pVirtualAddress, SIZE_T length, LOCK_OPERATION operation)
{
	PMDL pMdl;

	if (length >= (PAGE_SIZE * (65535 - sizeof(MDL)) / sizeof(ULONG_PTR)))
	{
		DbgPrint("Size parameter passed to IoAllocateMdl is too big!\n");
		return NULL;
	}

	pMdl = IoAllocateMdl((PVOID)pVirtualAddress, length, FALSE, FALSE, NULL);
	if (NULL == pMdl)
	{
		DbgPrint("IoAllocateMdl returned NULL!\n");
		return NULL;
	}

	// Make sure the memory is not paged on the disk.
	try
	{
		MmProbeAndLockPages(pMdl, KernelMode, operation);
	}
	except (EXCEPTION_EXECUTE_HANDLER)
	{
		DbgPrint("MmProbeAndLockPages caused an exception!\n");
		IoFreeMdl(pMdl);
		return NULL;
	}

	return pMdl;
}



// This function writes the given data to the given non-paged kernel memory location.
// It makes sure that no other instance can access it in any way until we have finished
// our job.
//
// IN pDestination Pointer to the kernel memory where we want to write.
// IN pSource Pointer to the data we want to write.
// IN length Length of data we want to write in bytes.
//
// OUT NTSTATUS return code.
//
NTSTATUS WriteKernelMemory(BYTE *pDestination, BYTE *pSource, SIZE_T length)
{
	KSPIN_LOCK spinLock;
	KLOCK_QUEUE_HANDLE lockHandle;
	PMDL pMdl;
	PVOID pAddress;

	pMdl = GetMdlForNonPagedMemory(pDestination, length);
	if (NULL == pMdl)
	{
		DbgPrint("GetMdlForSafeKernelMemoryArea returned NULL!\n");
		return STATUS_UNSUCCESSFUL;
	}

	pAddress = MmGetSystemAddressForMdlSafe(pMdl, HighPagePriority);

	if (pAddress == NULL)
	{
		IoFreeMdl(pMdl);
		DbgPrint("MmGetSystemAddressForMdlSafe returned NULL!\n");
		return STATUS_UNSUCCESSFUL;
	}

	KeInitializeSpinLock(&spinLock);
	// Only supported on XP and later. For Windows 2000 compatibility you can
	// use the older, less efficient and less reliable KeAcquireSpinLock function.
	KeAcquireInStackQueuedSpinLock (&spinLock, &lockHandle);
	// We have the spinlock, so we can safely overwrite the kernel memory.
	RtlCopyMemory(pAddress, pSource, length);
	KeReleaseInStackQueuedSpinLock(&lockHandle);

	IoFreeMdl(pMdl);

	return STATUS_SUCCESS;
}

void __stdcall ProcessData(DWORD *pEthread)
{
	DWORD	*pEprocess	= (DWORD *)*(pEthread + offsets.threadsProcess);
	DWORD	*pCid		= (DWORD *)(pEthread+offsets.CID);
	DWORD	key			= 0;
	DATA	data		= {0};
	
	data.processID = 0x0;
	data.threadID = 0x0;
	data.imageName = "NONE";

	key = (DWORD)pEthread;
	
	if (pCid != NULL)
	{
		data.processID = *pCid;
		data.threadID = *(pCid + 0x1);
	}
	
	if (pEprocess != NULL)
	{
		data.imageName = (BYTE *)(pEprocess+offsets.imageFilename);
		data.xlow = *(DWORD *)(pEprocess+offsets.peexittimeoff);
		data.xhigh = *(DWORD *)(pEprocess+offsets.peexittimeoff+4);
	}
	if (*(pEthread + offsets.crossThreadFlags) & 1)
	{
		KeAcquireSpinLock(&DpcSpinLock,&OldIrql);
		Remove(key, pHashTable);
		KeReleaseSpinLock(&DpcSpinLock,OldIrql);
	}
	else
	{
		KeAcquireSpinLock(&DpcSpinLock,&OldIrql);
		Insert(key, &data, pHashTable);
		KeReleaseSpinLock(&DpcSpinLock,OldIrql);
	}
}

void __declspec(naked) DetourFunction()
{
	__asm 
	{
		// Save parameters we will overwrite. We save all data to play it safe.
		pushad
		pushfd
		// Disable interrupts. Assume single processor machine.
		// cli
		// EDI holds the thread whose context we will switch out.
		push edi
		call ProcessData
		// ESI holds the thread whose context we will switch in.
		push esi
		call ProcessData
		// Enable interrupts.
		// sti
		// Restore the saved state.
		popfd
		popad

		// Jump to the trampoline function.
		jmp dword ptr pTrampoline
	}
}



BYTE * GetSwapAddr()
{
    BYTE		*res = 0;
    NTSTATUS	Status;
    PETHREAD	Thread;

    if (*NtBuildNumber <= 2195)
        Status = PsLookupThreadByThreadId((PVOID)4, &Thread);
    else
        Status = PsLookupThreadByThreadId((PVOID)8, &Thread);

    if (NT_SUCCESS(Status))
    {
        if (MmIsAddressValid(Thread))
            res = (BYTE *)(*(ULONG *)((BYTE *)(Thread)+0x28));
        if (MmIsAddressValid(res+8))
            res = (BYTE *)(*(ULONG *)(res+8));
        else
            res = 0;
    }

    return res;
}
ULONG GetFunctionAddr( IN PCWSTR FunctionName)
{
		UNICODE_STRING UniCodeFunctionName;
		
		RtlInitUnicodeString( &UniCodeFunctionName, FunctionName );
		return (ULONG)MmGetSystemRoutineAddress( &UniCodeFunctionName );    
		
}
VOID DoFindSwap(IN PVOID pContext)
	{
		NTSTATUS ret;
		PSYSTEM_MODULE_INFORMATION  module = NULL;
		ULONG n=0;
		void  *buf    = NULL;
		ULONG ntosknlBase;
		ULONG ntosknlEndAddr;
		ULONG curAddr;

		ULONG code1_sp1=0xc626c90a,code2_sp1=0x9c022d46,code3_sp1=0xbb830b8b,code4_sp1=0x00000994;


		ULONG code1,code2,code3,code4;
		ULONG i;
		
		NtQuerySystemInformation=(NTQUERYSYSTEMINFORMATION)GetFunctionAddr(L"NtQuerySystemInformation");
		if (!NtQuerySystemInformation) 
		{
			DbgPrint("Find NtQuerySystemInformation faild!");
			goto Ret;
		}
		ret=NtQuerySystemInformation(SystemModuleInformation,&n,0,&n);
		if (NULL==( buf=ExAllocatePoolWithTag(NonPagedPool, n, 'PAWS')))
		{
			DbgPrint("ExAllocatePool() failed\n" );
			goto Ret;
		}
		ret=NtQuerySystemInformation(SystemModuleInformation,buf,n,NULL);
		if (!NT_SUCCESS(ret))	{
			DbgPrint("NtQuerySystemInformation faild!");
			goto Ret;
		} 
		module=(PSYSTEM_MODULE_INFORMATION)((PULONG)buf+1);
		ntosknlEndAddr=(ULONG)module->Base+(ULONG)module->Size;
		ntosknlBase=(ULONG)module->Base;
		curAddr=ntosknlBase;
		ExFreePool(buf);

		code1 = code1_sp1;
		code2 = code2_sp1;
		code3 = code3_sp1;
		code4 = code4_sp1;
	
		for (i=curAddr;i<=ntosknlEndAddr;i++)
		{
			if (*((ULONG *)i)==code1) 
			{
				if (*((ULONG *)(i+4))==code2) 
				{
					if (*((ULONG *)(i+8))==code3) 
					{
						if (*((ULONG *)(i+12))==code4) 
						{
								
								pSwapContext=(BYTE *)i;
								break;
									
						}
					}
				}
			}
		}
Ret:
	PsTerminateSystemThread(STATUS_SUCCESS);
	}

void FindSwapAddr()
{
		HANDLE	hThread		= NULL;
		PVOID	objtowait	= 0;

		NTSTATUS dwStatus = 
			PsCreateSystemThread(
			&hThread,
	              0,
		       NULL,
			(HANDLE)0,
	              NULL,
		       DoFindSwap,
			NULL
			);
		if ((KeGetCurrentIrql())!=PASSIVE_LEVEL)
		{
			KfRaiseIrql(PASSIVE_LEVEL);
		
		}
		if ((KeGetCurrentIrql())!=PASSIVE_LEVEL)
		{
			return;
		}
		
		ObReferenceObjectByHandle(
			hThread,
			THREAD_ALL_ACCESS,
			NULL,
			KernelMode,
			&objtowait,
			NULL
			); 

		KeWaitForSingleObject(objtowait,Executive,KernelMode,FALSE,NULL); //NULL表示无限期等待.
		return;

}

NTSTATUS InstallSwapContextHook()
{
	NTSTATUS rc;r
	int length = 0;
	int totalLength = 0;
	struct xde_instr instr;
	BYTE *pJmpCode = NULL;
	long displacement = 0;

	__asm
    {
			push    eax
			mov        eax, CR0
			and        eax, 0FFFEFFFFh
			mov        CR0, eax
			pop        eax
    }

	// Disassemble the code to get how many bytes we have to replace.
	// We use XDE v1.01 by Z0MBie (http://z0mbie.host.sk/).
	while (totalLength < 5)
	{
		length = xde_disasm(pSwapContext + totalLength, &instr);
		if (length == 0)
		{
			DbgPrint("xde_disasm returned 0!\n");
			return STATUS_UNSUCCESSFUL;
		}
		totalLength += length;
	}
	
	DbgPrint("Hook will replace the first %d bytes.\n", totalLength);

	// Allocate the required bytes for the trampoline function.
	pTrampoline = trampoline.pAddress = ExAllocatePoolWithTag(NonPagedPool, totalLength + 5, MAINTAG1);
	if (trampoline.pAddress == NULL)
	{
		DbgPrint("ExAllocatePoolWithTag returned NULL!\n");
		return STATUS_UNSUCCESSFUL;
	} 

	DbgPrint("Trampoline is at 0x%x\n", pTrampoline);

	// This tells how many bytes we replaced from the original function.
	trampoline.size = totalLength;
	RtlCopyMemory(trampoline.pAddress, pSwapContext, totalLength);

	// We are using JMP rel32 instruction to jump to the rest of the
	// swapcontext function, so we first calculate the 32bit displacement
	// and then create the five byte JMP instruction.
	displacement = (pSwapContext + totalLength) - (trampoline.pAddress + totalLength + JMP_SIZE);
	pJmpCode = trampoline.pAddress + totalLength;

	//直接的jmp分3种 
	//Short Jump(短跳转)机器码 EB rel8 
	//只能跳转到256字节的范围内 
	//Near Jump(近跳转)机器码 E9 rel16/32 
	//可跳至同一个段的范围内的地址 
	//Far Jump(远跳转)机器码EA ptr 16:16/32 
	//可跳至任意地址,使用48位/32位全指针 
	*pJmpCode = 0xe9;
	RtlCopyMemory(pJmpCode+1, &displacement, 4);

	// Allocate the required bytes for the jmp code to the detour function.
	pJmpCode = ExAllocatePoolWithTag(NonPagedPool, totalLength, MAINTAG1);
	if (pJmpCode == NULL)
	{
		DbgPrint("ExAllocatePoolWithTag returned NULL!\n");
		return STATUS_UNSUCCESSFUL;
	}

	// Initialize the jmp-code with NOPs.
	RtlFillMemory(pJmpCode, totalLength, 0x90);
	
	// We are using JMP rel32 instruction to jump to our hook function,
	// so we first calculate the 32bit displacement and then create the
	// five byte JMP instruction.
	displacement = ((BYTE *)&DetourFunction) - (pSwapContext + JMP_SIZE);
	*pJmpCode = 0xe9;
	RtlCopyMemory(pJmpCode+1, &displacement, 4);

	rc = WriteKernelMemory(pSwapContext, pJmpCode, totalLength);
	ExFreePoolWithTag(pJmpCode, MAINTAG1);
    __asm
    {
        push    eax
			mov        eax, CR0
			or        eax, NOT 0FFFEFFFFh
			mov        CR0, eax
			pop        eax
    }
	return rc;
}

// This function removes our hook by restoring the bytes we have replaced
// from the original SwapContext function.
//
// OUT NTSTATUS return value.
//
NTSTATUS UninstallSwapContextHook()
{
	return WriteKernelMemory(pSwapContext, trampoline.pAddress, trampoline.size);
}

NTSTATUS OnUnload(IN PDRIVER_OBJECT DriverObject)
{
	NTSTATUS rc;
	UNICODE_STRING          deviceLinkUnicodeString;
	PDEVICE_OBJECT			p_NextObj;
	PPROCLIST pTemp = NULL, pt = NULL;
	PThreadData pTempT = NULL, pp = NULL;
	PDriverData pTempD = NULL, pd = NULL;
	PFileList pTempF = NULL, pf = NULL;

	DbgPrint("OnUnload called\n");

	rc = UninstallSwapContextHook();

	if (STATUS_SUCCESS == rc)
	{
		DbgPrint("UninstallSwapContextHook succeeded.\n");
	}
	else
	{
		DbgPrint("UninstallSwapContextHook failed!\n");
	}

	// Show the collected data and release all resources.
	//DumpTable(pHashTable);
	KeAcquireSpinLock(&DpcSpinLock,&OldIrql);
	DestroyTable(pHashTable);
	KeReleaseSpinLock(&DpcSpinLock,OldIrql);
	//num = 0;
	ExFreePoolWithTag(pTrampoline, MAINTAG1);

    // Delete the symbolic link for our device
	//
	RtlInitUnicodeString( &deviceLinkUnicodeString, deviceLinkBuffer );
	IoDeleteSymbolicLink( &deviceLinkUnicodeString );
	// Delete the device object
	//
	IoDeleteDevice( DriverObject->DeviceObject );
	//return STATUS_SUCCESS;
	return rc;
}


NTSTATUS DispatchCreate (
		IN PDEVICE_OBJECT	pDevObj,
		IN PIRP				pIrp			)
{

	pIrp->IoStatus.Status = STATUS_SUCCESS;
	pIrp->IoStatus.Information = 0;	// no bytes xfered
	IoCompleteRequest( pIrp, IO_NO_INCREMENT );
	return STATUS_SUCCESS;
}


NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
	
	RTL_OSVERSIONINFOW		osvi;
	NTSTATUS                ntStatus;
	UNICODE_STRING          deviceNameUnicodeString;
    UNICODE_STRING          deviceLinkUnicodeString;   
	RTL_OSVERSIONINFOEXW	VersionInfo;
	ULONGLONG				ConditionMask = 0;

	memset(&VersionInfo,0,sizeof(VersionInfo));

	VER_SET_CONDITION (
           ConditionMask,
            VER_SERVICEPACKMAJOR,
            VER_EQUAL
            );


	DbgPrint("DriverEntry called.\n");

	RtlZeroMemory(&osvi, sizeof(RTL_OSVERSIONINFOW));
	osvi.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOW);


	// Initialize the OS specific data.
// 	gNameOffset = GetLocationOfProcessName(PsGetCurrentProcess());
// 	if (!gNameOffset)
// 		return STATUS_UNSUCCESSFUL;
	if (STATUS_SUCCESS == RtlGetVersion(&osvi))
	{
		if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) //Windows XP
		{
			offsets.pecreatetimeoff = 0x070;
			offsets.peexittimeoff = 0x078;
			offsets.CID = 0x7b;
			offsets.threadsProcess = 0x88;
			offsets.crossThreadFlags = 0x92;
			offsets.imageFilename = 0x5d;
		}

		//VersionInfo.wServicePackMajor = 3;
		//if( STATUS_SUCCESS==RtlVerifyVersionInfo(&VersionInfo,VER_SERVICEPACKMAJOR,ConditionMask))//sp3
		//{
		//
		//}
		
		else
		{
			//更多的调试
			DbgPrint("Unsupported OS version!\n");
			return STATUS_UNSUCCESSFUL;
		}
		
	}
	else
	{
		DbgPrint("RtlGetVersion failed!\n");
		return STATUS_UNSUCCESSFUL;
	}
	
	RtlInitUnicodeString (&deviceNameUnicodeString,
	                          deviceNameBuffer );
	RtlInitUnicodeString (&deviceLinkUnicodeString, deviceLinkBuffer);

	ntStatus = IoCreateDevice ( DriverObject,
	                                0, // For driver extension
	                                &deviceNameUnicodeString,
	                                FILE_DEVICE_UNKNOWN,
	                                0,
	                                TRUE,
	                                &g_HookDevice );

	if(! NT_SUCCESS(ntStatus))
	{
	        DbgPrint(("Failed to create device!\n"));
	        return ntStatus;
	}
	 
			
	ntStatus = IoCreateSymbolicLink (&deviceLinkUnicodeString,
	                                        &deviceNameUnicodeString );
	if(! NT_SUCCESS(ntStatus)) 
	{
		 IoDeleteDevice(DriverObject->DeviceObject);
	        DbgPrint("Failed to create symbolic link!\n");
	        return ntStatus;
	}

	DriverObject->DriverUnload  = OnUnload;

	pHashTable = InitializeTable(HASHTABLE_SIZE);
	if (pHashTable == NULL)
	{
		DbgPrint("InitializeTable failed!\n");
		return STATUS_UNSUCCESSFUL;
	}
	
	//pSwapContext = GetSwapAddr();

	FindSwapAddr();

	if(NULL==pSwapContext)
	{
	 	DbgPrint("SwapContext addr not found!\n");
		return STATUS_UNSUCCESSFUL;
	}
	else
	{
		DbgPrint("SwapContext found at 0x%x\n", pSwapContext);

		ntStatus = InstallSwapContextHook();
	}
	
	if (STATUS_SUCCESS == ntStatus)
	{
		DbgPrint("InstallSwapContextHook succeeded.\n");
		DbgPrint("DetourFunction is at 0x%x\n", DetourFunction);
	}
	else
	{
		DbgPrint("InstallSwapContextHook failed!\n");
		return STATUS_UNSUCCESSFUL;
	}

	return STATUS_SUCCESS;
	
}

两份inline hook NtOpenprocess保护进程的代码:

这份没有使用中间函数:

#include "ntddk.h"

#pragma pack(1)
#define IOCTL_HOOK CTL_CODE(FILE_DEVICE_UNKNOWN,0x801 , METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)  

typedef struct ServiceDescriptorEntry {
	unsigned int *ServiceTableBase;
	unsigned int *ServiceCounterTableBase; //仅适用于checked build版本
	unsigned int NumberOfServices;
	unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
#pragma pack()

__declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable;

//global
ULONG   OpenprocessAddress;
ULONG   JmpOldAddress;
UCHAR	OldCode[5];
HANDLE  MyPID;
HANDLE  PID;

int *MyPIDEx;
void IninleHookOpenProcess(int *PID);

NTSTATUS __declspec(naked)(__stdcall MyNtOpenProcess)(
	                                            PHANDLE ProcessHandle,
												ACCESS_MASK DesiredAccess,
												POBJECT_ATTRIBUTES ObjectAttributes,
												PCLIENT_ID ClientId) 
{
	__asm
	{
		push eax
		mov eax,[esp+0x14]  //获取ClientId,因为是第四个参数所以【esp+10】,但上面有push eax 所以再加4
		mov eax,[eax]
		mov PID,eax          //不能在naked函数里定义局部变量,会破坏本来的局部变量
		pop eax
	}

	if(PID==MyPID)
		{
			__asm
				{
					mov [esp+4],0 //返回空句柄
					mov eax,0xC0000022L  //返回值STATUS_ACCESS_DENIED 无法发现进程
					retn 0x10   //执行保护后的返回
				}
		}

	/*__asm
	{
		push  0x0C4
		mov edx,RealNtOpenProcess
		add edx,5
		jmp edx
	}*/
	
	__asm
	{
		mov  edi,edi
		push ebp
		mov ebp,esp
		jmp JmpOldAddress
	}

}

void PageProtectOn()
{
	__asm{//恢复内存保护  
		mov  eax,cr0
		or   eax,10000h
		mov  cr0,eax
		sti
	}
}

void PageProtectOff()
{
	__asm{//去掉内存保护
		cli
		mov  eax,cr0
		and  eax,not 10000h
		mov  cr0,eax
	}
}


NTSTATUS IODispatch(PDEVICE_OBJECT pDeviceObject, PIRP Irp)
{
	Irp->IoStatus.Status = STATUS_SUCCESS;
	IoCompleteRequest(Irp,IO_NO_INCREMENT);
	return STATUS_SUCCESS;
}


NTSTATUS IOManager(PDEVICE_OBJECT pDeviceObject, PIRP Irp)
{   
	PIO_STACK_LOCATION StackLocation = IoGetCurrentIrpStackLocation(Irp);
	ULONG IRPcode = StackLocation->Parameters.DeviceIoControl.IoControlCode;  
	char outText[]="保护成功";
	ULONG  returnSize;
	UCHAR *oubuffer;
	Irp->IoStatus.Status = STATUS_SUCCESS; 

	switch(IRPcode)
	{
	case IOCTL_HOOK:
		KdPrint(("IOCTL_HOOK  \n"));
	MyPIDEx	=(int*)Irp->AssociatedIrp.SystemBuffer;//得到传入数据地址

	oubuffer = (UCHAR*)Irp->AssociatedIrp.SystemBuffer;

	strcpy((char*)oubuffer,outText);

	returnSize=strlen(outText);  

	IninleHookOpenProcess(MyPIDEx);
		break;
	}
	
	Irp->IoStatus.Information=returnSize;
	Irp->IoStatus.Status= STATUS_SUCCESS;
	
	IoCompleteRequest(Irp,IO_NO_INCREMENT);
	return STATUS_SUCCESS;
}

void IninleHookOpenProcess(int *PID)
{
	UCHAR jmpcode[5];
	ULONG jmp_tmp_code;
	
	jmpcode[0]=0xE9;
	
	 OpenprocessAddress = KeServiceDescriptorTable.ServiceTableBase[190];

	 jmp_tmp_code = (ULONG)MyNtOpenProcess - OpenprocessAddress - 5; 

	 *(ULONG*)&jmpcode[1]=jmp_tmp_code;

	 JmpOldAddress = OpenprocessAddress + 5;
	 MyPID = (HANDLE)*PID;
	 PageProtectOff();

	 RtlCopyMemory(OldCode,(PVOID)OpenprocessAddress,5);
	 RtlCopyMemory((PVOID)OpenprocessAddress,jmpcode,5);

	 PageProtectOn();

}

void UnHookOpenprocess()
{
	 PageProtectOff();

	 RtlCopyMemory((PVOID)OpenprocessAddress,OldCode,5);

	 PageProtectOn();
}

NTSTATUS CreateDevice(PDRIVER_OBJECT pDriverObject)
{
	NTSTATUS Status;
	PDEVICE_OBJECT	pDevObj;
	UNICODE_STRING	usDevName;
	UNICODE_STRING	usSymName;

	RtlInitUnicodeString(&usDevName,L"\\Device\\MyDevice");

	Status = IoCreateDevice(pDriverObject,\
		0,\
		&usDevName,\
		FILE_DEVICE_UNKNOWN,\
		0,\
		TRUE,\
		&pDevObj);
	if (!NT_SUCCESS(Status))
	{
		return Status;
	}

	pDevObj->Flags |= DO_BUFFERED_IO;


	RtlInitUnicodeString(&usSymName,L"\\??\\MyDevice");

	Status = IoCreateSymbolicLink(&usSymName,&usDevName);
	if (!NT_SUCCESS(Status))
	{
		IoDeleteDevice(pDevObj);
		return Status;
	}

	return STATUS_SUCCESS;
}

void UnloadDriver(PDRIVER_OBJECT pDriverObject)
{
	UNICODE_STRING usSymName;

	RtlInitUnicodeString(&usSymName,L"\\??\\MyDevice");

	if (pDriverObject->DeviceObject!=NULL)
	{
		IoDeleteSymbolicLink(&usSymName);
		IoDeleteDevice(pDriverObject->DeviceObject);
		KdPrint(("删除设备成功."));
	}
	UnHookOpenprocess();
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING pRegString)
{
	NTSTATUS Status;
	Status = CreateDevice(pDriverObject);
	if (!NT_SUCCESS(Status))
	{
		KdPrint(("创建设备失败."));
	}else{
		KdPrint(("创建设备成功."));
	}
	
	pDriverObject->MajorFunction[IRP_MJ_CREATE] = IODispatch;
	pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IOManager; 
	pDriverObject->DriverUnload = UnloadDriver;
	return STATUS_SUCCESS;
}


另外一份使用了中间函数 这才是真正意义上inline hook

//为什么一个是esp+0x34 一个是esp+14  原因是下面这份使用了

pushad
pushfd
保护了现场 这将栈提高了0x24字节
#include "ntddk.h"

#pragma pack(1)
typedef struct ServiceDescriptorEntry {
	unsigned int *ServiceTableBase;
	unsigned int *ServiceCounterTableBase; //仅适用于checked build版本
	unsigned int NumberOfServices;
	unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
#pragma pack()

__declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable;

NTSTATUS
PsLookupProcessByProcessId(
    IN HANDLE ProcessId,
    OUT PEPROCESS *Process
    );

//global
ULONG	gfn_ntopenprocess;
ULONG	g_jmp_origfunc;
UCHAR	gs_origfunc_code[5];

void PageProtectOn()
{
	__asm{//恢复内存保护  
		mov  eax,cr0
		or   eax,10000h
		mov  cr0,eax
		sti
	}
}

void PageProtectOff()
{
	__asm{//去掉内存保护
		cli
		mov  eax,cr0
		and  eax,not 10000h
		mov  cr0,eax
	}
}

ULONG FilterNtOpenProcess(PCLIENT_ID ClientId)
{
	NTSTATUS	status;
	PEPROCESS	process_obj;
	status = PsLookupProcessByProcessId(ClientId->UniqueProcess,&process_obj);
	if (!NT_SUCCESS(status))
	{
		return 0;
	}

	if (strstr((char*)process_obj+0x16c,"VistaLKD")!=0)
	{
		return 1;
	}

	return 0;
}

__declspec(naked)
NTSTATUS NewNtOpenProcess()
{
	__asm{
		pushad
		pushfd
		push	[esp+0x34]
		call	FilterNtOpenProcess
		test	eax,eax
		je		__Exit
		popfd
		popad
		mov		eax,0
		ret		0x10
__Exit:
		popfd
		popad
		mov		edi,edi
		push	ebp
		mov		ebp,esp
		jmp		g_jmp_origfunc
	}
}

void UnHookNtOpenProcess()
{
	PageProtectOff();

	RtlCopyMemory((PVOID)gfn_ntopenprocess,gs_origfunc_code,5);

	PageProtectOn();
}

void HookNtOpenProcess()
{
	ULONG	u_jmp_address;
	UCHAR	str_jmp_code[5];
	
	gfn_ntopenprocess = KeServiceDescriptorTable.ServiceTableBase[190];
	RtlCopyMemory(gs_origfunc_code,(PVOID)gfn_ntopenprocess,5);
	
	str_jmp_code[0] = 0xE9;

	u_jmp_address = (ULONG)NewNtOpenProcess - gfn_ntopenprocess - 5;
	*(ULONG*)(&str_jmp_code[1]) = u_jmp_address;

	PageProtectOff();

	RtlCopyMemory((PVOID)gfn_ntopenprocess,str_jmp_code,5);

	PageProtectOn();

	g_jmp_origfunc = gfn_ntopenprocess + 5;
}

VOID MyUnload(PDRIVER_OBJECT pDriverObject)
{
	UnHookNtOpenProcess();
}

NTSTATUS DriverEntry(PDRIVER_OBJECT	pDriverObject,PUNICODE_STRING Reg_Path)
{
	HookNtOpenProcess();
	pDriverObject->DriverUnload = MyUnload;
	return STATUS_SUCCESS;
}


问:为什么一个esp+14 一个是esp+38


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值