#include <ntddk.h>
#include <ntimage.h>

#define	__Max(a,b)	a>b?a:b

#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;


typedef struct _LDR_DATA_TABLE_ENTRY {
	LIST_ENTRY InLoadOrderLinks;
	LIST_ENTRY InMemoryOrderLinks;
	LIST_ENTRY InInitializationOrderLinks;
	PVOID DllBase;
	PVOID EntryPoint;
	ULONG SizeOfImage;
	UNICODE_STRING FullDllName;
	UNICODE_STRING BaseDllName;
	ULONG Flags;
	USHORT LoadCount;
	USHORT TlsIndex;
	union {
		LIST_ENTRY HashLinks;
		struct {
			PVOID SectionPointer;
			ULONG CheckSum;
		};
	};
	union {
		struct {
			ULONG TimeDateStamp;
		};
		struct {
			PVOID LoadedImports;
		};
	};
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;

typedef NTSTATUS 
(*NTCREATEFILE) (
    __out PHANDLE FileHandle,
    __in ACCESS_MASK DesiredAccess,
    __in POBJECT_ATTRIBUTES ObjectAttributes,
    __out PIO_STATUS_BLOCK IoStatusBlock,
    __in_opt PLARGE_INTEGER AllocationSize,
    __in ULONG FileAttributes,
    __in ULONG ShareAccess,
    __in ULONG CreateDisposition,
    __in ULONG CreateOptions,
    __in_bcount_opt(EaLength) PVOID EaBuffer,
    __in ULONG EaLength
    );

//global
PVOID	g_lpVirtualPointer;

ULONG	g_ntcreatefile;
ULONG	g_fastcall_hookpointer;
ULONG	g_goto_origfunc;
ULONG	g_NewKernelInc;

ServiceDescriptorTableEntry_t	*g_pNewSeviceTable;

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 SearchHookPointer(ULONG StartAddress)
{
	ULONG	u_index;

	UCHAR	*p = (UCHAR*)StartAddress;

	for (u_index = 0;u_index < 200;u_index++)
	{
		if (*p==0x2B&&
			*(p+1)==0xE1&&
			*(p+2)==0xC1&&
			*(p+3)==0xE9&&
			*(p+4)==0x02)
		{
			return (ULONG)p;
		}

		p--;
	}

	return 0;
}

ULONG FilterKiFastCallEntry(ULONG ServiceTableBase,ULONG FuncIndex,ULONG OrigFuncAddress)
{
	if (ServiceTableBase==(ULONG)KeServiceDescriptorTable.ServiceTableBase)
	{
		if (strstr((char*)PsGetCurrentProcess()+0x16c,"Ollydbg")!=0)
		{
			return g_pNewSeviceTable->ServiceTableBase[FuncIndex];
		}
	}

	return OrigFuncAddress;
}

__declspec(naked)
void NewKiFastCallEntry()
{
	__asm{
		pushad
		pushfd
		
		push	edx
		push	eax
		push	edi
		call	FilterKiFastCallEntry
		
		mov		[esp+0x18],eax

		popfd
		popad

		sub     esp,ecx
		shr     ecx,2
		jmp		g_goto_origfunc
	}
}

void UnHookKiFastCallEntry()
{
	UCHAR	str_origfuncode[5] = {0x2B,0xE1,0xC1,0xE9,0x02};

	if (g_fastcall_hookpointer==0)
	{	return;	}

	PageProtectOff();
	RtlCopyMemory((PVOID)g_fastcall_hookpointer,str_origfuncode,5);
	PageProtectOn();
}

void HookKiFastCallEntry(ULONG HookPointer)
{
	ULONG	u_temp;
	UCHAR	str_jmp_code[5];

	str_jmp_code[0] = 0xE9;

	u_temp = (ULONG)NewKiFastCallEntry - HookPointer - 5;
	*(ULONG*)&str_jmp_code[1] = u_temp;

	PageProtectOff();

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

	PageProtectOn();

}

NTSTATUS NewNtCreateFile (
    __out PHANDLE FileHandle,
    __in ACCESS_MASK DesiredAccess,
    __in POBJECT_ATTRIBUTES ObjectAttributes,
    __out PIO_STATUS_BLOCK IoStatusBlock,
    __in_opt PLARGE_INTEGER AllocationSize,
    __in ULONG FileAttributes,
    __in ULONG ShareAccess,
    __in ULONG CreateDisposition,
    __in ULONG CreateOptions,
    __in_bcount_opt(EaLength) PVOID EaBuffer,
    __in ULONG EaLength
    )
{
	ULONG	u_call_retaddr;

	__asm{
		pushad
		mov		eax,[ebp+0x4]
		mov		u_call_retaddr,eax
		popad
	}

	g_fastcall_hookpointer = SearchHookPointer(u_call_retaddr);
	if (g_fastcall_hookpointer==0)
	{
		KdPrint(("search failed."));
	}else{
		KdPrint(("search success."));
	}

	g_goto_origfunc = g_fastcall_hookpointer + 5;
	HookKiFastCallEntry(g_fastcall_hookpointer);

	PageProtectOff();
	KeServiceDescriptorTable.ServiceTableBase[66] = (unsigned int)g_ntcreatefile;
	PageProtectOn();

	return ((NTCREATEFILE)g_ntcreatefile)(
		FileHandle,\
		DesiredAccess,\
		ObjectAttributes,\
		IoStatusBlock,\
		AllocationSize,\
		FileAttributes,\
		ShareAccess,\
		CreateDisposition,\
		CreateOptions,\
		EaBuffer,\
		EaLength);
}


void SearchKiFastCallEntry()
{
	HANDLE				hFile;
	NTSTATUS			Status;
	OBJECT_ATTRIBUTES	ObjAttr;
	UNICODE_STRING		usFileName;
	IO_STATUS_BLOCK		IoStatusBlock;

	RtlInitUnicodeString(&usFileName,L"\\??\\C:\\Windows\\System32\\ntkrnlpa.exe");
	InitializeObjectAttributes(\
		&ObjAttr,\
		&usFileName,\
		OBJ_CASE_INSENSITIVE,\
		NULL,\
		NULL);

	g_ntcreatefile = KeServiceDescriptorTable.ServiceTableBase[66];
	PageProtectOff();
	KeServiceDescriptorTable.ServiceTableBase[66] = (unsigned int)NewNtCreateFile;
	PageProtectOn();

	Status = ZwCreateFile(\
		&hFile,\
		FILE_ALL_ACCESS,\
		&ObjAttr,\
		&IoStatusBlock,\
		NULL,\
		FILE_ATTRIBUTE_NORMAL,\
		FILE_SHARE_READ,\
		FILE_OPEN,\
		FILE_NON_DIRECTORY_FILE,\
		NULL,\
		0);
	if (NT_SUCCESS(Status))
	{
		ZwClose(hFile);
	}
}

VOID SetNewSSDT(\
	PVOID pNewImage,\
	PVOID pOrigImage,\
	ServiceDescriptorTableEntry_t **pNewSeviceTable)
{
	ULONG							uIndex;
	ULONG							uNewKernelInc,uOffset;
	ServiceDescriptorTableEntry_t	*pNewSSDT;
	

	uNewKernelInc = (ULONG)pNewImage - (ULONG)pOrigImage;
	pNewSSDT = (ServiceDescriptorTableEntry_t *)((ULONG)&KeServiceDescriptorTable + uNewKernelInc);
	
	if (!MmIsAddressValid(pNewSSDT))
	{
		KdPrint(("pNewSSDT"));
		return;
	}

	pNewSSDT->NumberOfServices = KeServiceDescriptorTable.NumberOfServices;

	uOffset = (ULONG)KeServiceDescriptorTable.ServiceTableBase - (ULONG)pOrigImage;
	pNewSSDT->ServiceTableBase = (unsigned int*)((ULONG)pNewImage + uOffset);
	if (!MmIsAddressValid(pNewSSDT->ServiceTableBase))
	{
		KdPrint(("pNewSSDT->ServiceTableBase:%X",pNewSSDT->ServiceTableBase));
		return;
	}
	
	for (uIndex = 0;uIndex<pNewSSDT->NumberOfServices;uIndex++)
	{
		pNewSSDT->ServiceTableBase[uIndex] += uNewKernelInc;
	}

	uOffset = (ULONG)KeServiceDescriptorTable.ParamTableBase - (ULONG)pOrigImage;
	pNewSSDT->ParamTableBase = (unsigned char*)((ULONG)pNewImage + uOffset);
	if (!MmIsAddressValid(pNewSSDT->ParamTableBase))
	{
		KdPrint(("pNewSSDT->ParamTableBase"));
		return;
	}
	RtlCopyMemory(pNewSSDT->ParamTableBase,KeServiceDescriptorTable.ParamTableBase,pNewSSDT->NumberOfServices*sizeof(char));
	
	*pNewSeviceTable = pNewSSDT;
	KdPrint(("set new ssdt success."));
}

void RelocModule(PVOID pNewImage,PVOID pOrigImage)
{
	ULONG					uIndex;
	ULONG					uRelocTableSize;
	USHORT					TypeValue;
	USHORT					*pwOffsetArrayAddress;
	ULONG					uTypeOffsetArraySize;

	ULONG					uRelocOffset;

	ULONG					uRelocAddress;

	PIMAGE_DOS_HEADER		pImageDosHeader;
	PIMAGE_NT_HEADERS		pImageNtHeader;
	IMAGE_DATA_DIRECTORY	ImageDataDirectory;
	IMAGE_BASE_RELOCATION	*pImageBaseRelocation;

	pImageDosHeader = (PIMAGE_DOS_HEADER)pNewImage;
	pImageNtHeader = (PIMAGE_NT_HEADERS)((ULONG)pNewImage + pImageDosHeader->e_lfanew);

	uRelocOffset = (ULONG)pOrigImage - pImageNtHeader->OptionalHeader.ImageBase;

	ImageDataDirectory = pImageNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
	
	pImageBaseRelocation = (PIMAGE_BASE_RELOCATION)(ImageDataDirectory.VirtualAddress + (ULONG)pNewImage);
	uRelocTableSize = ImageDataDirectory.Size;
	
	while(uRelocTableSize)
	{
		uTypeOffsetArraySize = (pImageBaseRelocation->SizeOfBlock - sizeof(ULONG)*2) / sizeof(USHORT);

		pwOffsetArrayAddress = pImageBaseRelocation->TypeOffset;
		for (uIndex = 0;uIndex<uTypeOffsetArraySize;uIndex++)
		{
			TypeValue = pwOffsetArrayAddress[uIndex];
			if (TypeValue>>12==IMAGE_REL_BASED_HIGHLOW)
			{
				uRelocAddress = (TypeValue&0xfff)+pImageBaseRelocation->VirtualAddress + (ULONG)pNewImage;
				if (!MmIsAddressValid((PVOID)uRelocAddress))
				{
					continue;
				}

				*(ULONG*)uRelocAddress += uRelocOffset;
			}
		}
		
		uRelocTableSize -= pImageBaseRelocation->SizeOfBlock;
		pImageBaseRelocation = (IMAGE_BASE_RELOCATION *)(\
			(ULONG)pImageBaseRelocation + pImageBaseRelocation->SizeOfBlock);
	}
}

NTSTATUS ReadFileToMemory(wchar_t *strFileName,PVOID *lpVirtualAddress,PVOID pOrigImage)
{
	NTSTATUS				Status;
	HANDLE					hFile;
	LARGE_INTEGER			FileOffset;
	UNICODE_STRING			usFileName;
	OBJECT_ATTRIBUTES		ObjAttr;
	IO_STATUS_BLOCK			IoStatusBlock;
	
	IMAGE_DOS_HEADER		ImageDosHeader;
	IMAGE_NT_HEADERS		ImageNtHeader;
	IMAGE_SECTION_HEADER	*pImageSectionHeader;

	ULONG					uIndex;
	PVOID					lpVirtualPointer;
	ULONG					SecVirtualAddress,SizeOfSection;
	ULONG					PointerToRawData;

	if (!MmIsAddressValid(strFileName))
	{
		return STATUS_UNSUCCESSFUL;
	}

	RtlInitUnicodeString(&usFileName,strFileName);

	InitializeObjectAttributes(\
		&ObjAttr,\
		&usFileName,\
		OBJ_CASE_INSENSITIVE,\
		NULL,\
		NULL);

	Status = ZwCreateFile(\
		&hFile,\
		FILE_ALL_ACCESS,\
		&ObjAttr,\
		&IoStatusBlock,\
		NULL,\
		FILE_ATTRIBUTE_NORMAL,\
		FILE_SHARE_READ,\
		FILE_OPEN,\
		FILE_NON_DIRECTORY_FILE,\
		NULL,\
		0);
	if (!NT_SUCCESS(Status))
	{
		KdPrint(("ZwCreateFile failed:%X",Status));
		return Status;
	}

	FileOffset.QuadPart = 0;
	Status = ZwReadFile(\
		hFile,\
		NULL,\
		NULL,\
		NULL,\
		&IoStatusBlock,\
		&ImageDosHeader,\
		sizeof(IMAGE_DOS_HEADER),\
		&FileOffset,\
		NULL);
	if (!NT_SUCCESS(Status))
	{
		KdPrint(("read iamge_dos_header failed:%X",Status));
		ZwClose(hFile);
		return Status;
	}

	FileOffset.QuadPart = ImageDosHeader.e_lfanew;
	Status = ZwReadFile(\
		hFile,\
		NULL,\
		NULL,\
		NULL,\
		&IoStatusBlock,\
		&ImageNtHeader,\
		sizeof(IMAGE_NT_HEADERS),\
		&FileOffset,\
		NULL);
	if (!NT_SUCCESS(Status))
	{
		KdPrint(("read IMAGE_NT_HEADERS failed:%X",Status));
		ZwClose(hFile);
		return Status;
	}
	
	pImageSectionHeader = ExAllocatePool(\
		NonPagedPool,\
		sizeof(IMAGE_SECTION_HEADER)*ImageNtHeader.FileHeader.NumberOfSections);
	if (pImageSectionHeader==0)
	{
		KdPrint(("pImageSectionHeader is null."));
		ZwClose(hFile);
		return STATUS_UNSUCCESSFUL;
	}

	FileOffset.QuadPart += sizeof(IMAGE_NT_HEADERS);
	Status = ZwReadFile(\
		hFile,\
		NULL,\
		NULL,\
		NULL,\
		&IoStatusBlock,\
		pImageSectionHeader,\
		sizeof(IMAGE_SECTION_HEADER)*ImageNtHeader.FileHeader.NumberOfSections,\
		&FileOffset,\
		NULL);
	if (!NT_SUCCESS(Status))
	{
		KdPrint(("read IMAGE_SECTION_HEADER failed:%X",Status));
		ExFreePool(pImageSectionHeader);
		ZwClose(hFile);
		return Status;
	}

	lpVirtualPointer = ExAllocatePool(NonPagedPool,ImageNtHeader.OptionalHeader.SizeOfImage);
	if (lpVirtualPointer==0)
	{
		KdPrint(("lpVirtualPointer is null"));
		ExFreePool(pImageSectionHeader);
		ZwClose(hFile);
		return STATUS_UNSUCCESSFUL;
	}

	memset(lpVirtualPointer,0,ImageNtHeader.OptionalHeader.SizeOfImage);
	RtlCopyMemory(\
		lpVirtualPointer,\
		&ImageDosHeader,\
		sizeof(IMAGE_DOS_HEADER));
	RtlCopyMemory(\
		(PVOID)((ULONG)lpVirtualPointer+ImageDosHeader.e_lfanew),\
		&ImageNtHeader,\
		sizeof(IMAGE_NT_HEADERS));
	RtlCopyMemory(\
		(PVOID)((ULONG)lpVirtualPointer+ImageDosHeader.e_lfanew+sizeof(IMAGE_NT_HEADERS)),\
		pImageSectionHeader,
		sizeof(IMAGE_SECTION_HEADER)*ImageNtHeader.FileHeader.NumberOfSections);

	for (uIndex = 0;uIndex<ImageNtHeader.FileHeader.NumberOfSections;uIndex++)
	{
		SecVirtualAddress = pImageSectionHeader[uIndex].VirtualAddress;
		SizeOfSection = __Max(pImageSectionHeader[uIndex].SizeOfRawData,\
			pImageSectionHeader[uIndex].Misc.VirtualSize);

		PointerToRawData = pImageSectionHeader[uIndex].PointerToRawData;

		FileOffset.QuadPart = PointerToRawData;
		Status = ZwReadFile(\
			hFile,\
			NULL,\
			NULL,\
			NULL,\
			&IoStatusBlock,\
			(PVOID)((ULONG)lpVirtualPointer+SecVirtualAddress),\
			SizeOfSection,\
			&FileOffset,\
			NULL);
		if (!NT_SUCCESS(Status))
		{
			KdPrint(("read failed is pImageSectionHeader[%d]",uIndex));
			ExFreePool(pImageSectionHeader);
			ExFreePool(lpVirtualPointer);
			ZwClose(hFile);
			return Status;
		}
	}
	
	RelocModule(lpVirtualPointer,pOrigImage);
	SetNewSSDT(lpVirtualPointer,pOrigImage,&g_pNewSeviceTable);
	
	KdPrint(("ok!"));

	ExFreePool(pImageSectionHeader);
	*lpVirtualAddress = lpVirtualPointer;
	ZwClose(hFile);
	return STATUS_SUCCESS;
}

PLDR_DATA_TABLE_ENTRY SearchDriver(PDRIVER_OBJECT pDriverObject,wchar_t *strDriverName)
{
	LDR_DATA_TABLE_ENTRY	*pDataTableEntry,*pTempDataTableEntry;
	PLIST_ENTRY				pList;
	UNICODE_STRING			usModuleName;

	RtlInitUnicodeString(&usModuleName,strDriverName);

	pDataTableEntry = (LDR_DATA_TABLE_ENTRY*)pDriverObject->DriverSection;
	if (!pDataTableEntry)
	{
		return 0;
	}
	
	pList = pDataTableEntry->InLoadOrderLinks.Flink;

	while(pList!= &pDataTableEntry->InLoadOrderLinks)
	{
		pTempDataTableEntry = (LDR_DATA_TABLE_ENTRY *)pList;

		KdPrint(("%wZ",&pTempDataTableEntry->BaseDllName));
		if (0==RtlCompareUnicodeString(&pTempDataTableEntry->BaseDllName,&usModuleName,FALSE))
		{
			return pTempDataTableEntry;
		}

		pList = pList->Flink;
	}

	return 0;
}

VOID MyUnload(PDRIVER_OBJECT	pDriverObject)
{
	if (g_lpVirtualPointer)
	{
		ExFreePool(g_lpVirtualPointer);
		UnHookKiFastCallEntry();
	}
}

NTSTATUS DriverEntry(PDRIVER_OBJECT	pDriverObject,PUNICODE_STRING Reg_Path)
{
	LDR_DATA_TABLE_ENTRY	*pLdrDataTableEntry;

	pLdrDataTableEntry = SearchDriver(pDriverObject,L"ntoskrnl.exe");
	if (pLdrDataTableEntry)
	{
		ReadFileToMemory(L"\\??\\C:\\Windows\\System32\\ntkrnlpa.exe",&g_lpVirtualPointer,pLdrDataTableEntry->DllBase);
		KdPrint(("g_lpVirtualPointer:%X",g_lpVirtualPointer));
		g_NewKernelInc = (ULONG)g_lpVirtualPointer - (ULONG)pLdrDataTableEntry->DllBase;

		SearchKiFastCallEntry();
	}
	pDriverObject->DriverUnload = MyUnload;
	return STATUS_SUCCESS;
}
打赏