[驱动开发] windows内核重载(xp3) 完整代码

1 了解PE结构

2 懂HOOK KiFastCallEntry

3 理解SSDT表 (需要修复SSDT表)


其实操作不算太复杂, 需要有一定的基础


完整测试的实例代码


#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
	{
		ULONG           TimeDateStamp;
		PVOID           LoadedImports;
	};
	PVOID               EntryPointActivationContext;
	PVOID               PatchInformation;
} 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
);


//全局变量的定义
PVOID	g_lpVirtualPointer = 0;
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() + 0x174, "Ollydbg") != 0)
		{
			//用新的NtCreateFile来处理
			return g_pNewSeviceTable->ServiceTableBase[FuncIndex];

			//针对inlineHook
			//return (OrigFuncAddress+g_NewKernelInc);
		}
	}

	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[37] = (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[37];
	PageProtectOff();
	KeServiceDescriptorTable.ServiceTableBase[37] = (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;
	//DbgPrint("pOrigImage -- %x,  uRelocOffset -- %x", pOrigImage, uRelocOffset);

	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;
	LARGE_INTEGER FileOffset;
	HANDLE hFile;
	OBJECT_ATTRIBUTES ObjAttr;
	IO_STATUS_BLOCK IoStatusBlock;
	UNICODE_STRING usFileName;
	IMAGE_DOS_HEADER ImageDosHeader;
	IMAGE_NT_HEADERS ImageNtHeader;
	IMAGE_SECTION_HEADER *pImageSectionHeader;

	PVOID lpVirtualPointer;
	ULONG SecVirtualAddress, SizeOfSection;
	ULONG PointerToRawData;

	ULONG uIndex = 0;

	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))
	{
		DbgPrint("ZwCreateFile Error --- %#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))
	{
		DbgPrint("ZwReadFile  ImageDosHeader  Error --- %#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))
	{
		DbgPrint("ZwReadFile  ImageNtHeader  Error --- %#X", Status);
		ZwClose(hFile);
		return Status;
	}

	pImageSectionHeader = ExAllocatePool(NonPagedPool, sizeof(IMAGE_SECTION_HEADER)*ImageNtHeader.FileHeader.NumberOfSections);
	if (pImageSectionHeader == NULL)
	{
		DbgPrint("ExAllocatePool  pImageSectionHeader Error --- ");
		return STATUS_UNSUCCESSFUL;
	}

	FileOffset.QuadPart = ImageDosHeader.e_lfanew + 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))
	{
		DbgPrint("ZwReadFile  ImageSectionHeader  Error --- %#X", Status);
		ExFreePool(pImageSectionHeader);
		ZwClose(hFile);
		return Status;
	}

	lpVirtualPointer = ExAllocatePool(NonPagedPool, ImageNtHeader.OptionalHeader.SizeOfImage);
	if (lpVirtualPointer == NULL)
	{
		DbgPrint("ExAllocatePool    Error ");
		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))
		{
			DbgPrint("ZwReadFile  ImageSectionHeader  Error --- %#X", Status);
			ExFreePool(pImageSectionHeader);
			ExFreePool(lpVirtualPointer);
			ZwClose(hFile);
			return Status;
		}

	}

	//基址重定位
	RelocModule(lpVirtualPointer, pOrigImage);
	SetNewSSDT(lpVirtualPointer, pOrigImage, &g_pNewSeviceTable);
	//DbgPrint("RelocModule ok!");

	//释放内存
	ExFreePool(pImageSectionHeader);
	*lpVirtualAddress = lpVirtualPointer;
	DbgPrint("文件内存复制成功");

	ZwClose(hFile);
	
	return STATUS_SUCCESS;
}



PLDR_DATA_TABLE_ENTRY SearchDriver(PDRIVER_OBJECT pDriverObject, wchar_t *strDriverName)
{
	
	ULONG Base = 0;//模块基地址
	LDR_DATA_TABLE_ENTRY* SectionBase = 0;
	LIST_ENTRY* Entry = 0;
	LIST_ENTRY InLoadOrderLinks = { 0 };
	UNICODE_STRING			usModuleName;

	RtlInitUnicodeString(&usModuleName, strDriverName);
	Entry = ((LIST_ENTRY*)pDriverObject->DriverSection)->Flink;


	do{
		SectionBase = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);//得到这个Entry所属的Section的地址,此方法经过验证可行
		if (SectionBase->EntryPoint &&
			SectionBase->BaseDllName.Buffer &&
			SectionBase->FullDllName.Buffer &&
			SectionBase->LoadCount
			)
		{
			//KdPrint(("%wZ", &SectionBase->BaseDllName));
			//DbgPrint("模块名称:%wZ,地址:%x\n",  &(SectionBase->FullDllName), SectionBase->DllBase);
			if (0 == RtlCompareUnicodeString(&SectionBase->BaseDllName, &usModuleName, FALSE))
			{
				KdPrint(("----%wZ-----", &SectionBase->BaseDllName));
				return SectionBase;
			}
			//DbgPrint("方法一遍历模块名称:%wZ,地址:%x\n",  &(SectionBase->FullDllName), SectionBase->DllBase);
		}
		Entry = Entry->Flink;
	} while (Entry != ((LIST_ENTRY*)pDriverObject->DriverSection)->Flink);//直到遍历回来

	return 0;
}	



VOID DriverUnload(IN PDRIVER_OBJECT pDriverObject)
{
	DbgPrint("DriverUnload");

	if (g_lpVirtualPointer)
	{
		ExFreePool(g_lpVirtualPointer);
		UnHookKiFastCallEntry();
	}
}



NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING RegistryPath)
{
	//C:\WINDOWS\system32\ntkrnlpa.exe
	//ReadFileToMemory(L"\\??\\C:\\WINDOWS\\system32\\ntkrnlpa.exe", &g_lpVitutalPointer, (PVOID)0x804D8000);
	//Method1(pDriverObject);
	PLDR_DATA_TABLE_ENTRY pLdrDataTableEntry;
	pLdrDataTableEntry = SearchDriver(pDriverObject, L"ntoskrnl.exe");
	//g_lpVitutalPointer
	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 = DriverUnload;
	DbgPrint("DriverEntry");
	
	return STATUS_SUCCESS;
}

原文链接: [驱动开发] windows内核重载(xp3) 完整代码 版权所有,转载时请注明出处,违者必究。
注明出处格式:流沙团 ( http://gyarmy.com/post-498.html )

发表评论

0则评论给“[驱动开发] windows内核重载(xp3) 完整代码”