今天就来一段现在比较流行的,也算是有人藏着掖着的,能反反调试的一种手段之一,重载内核。一共两个函数,放在驱动程序里直接调用即可。废话不多说,上代码。

////////////////////////////////////////////////////////////////////////////////////////////////////
//
//		函数名称:	LoadKernel
//		函数作用:	将内核文件载入内存
//		参数:		newKernelBasePtrPtr[OUT]:	接收新内核基址的指针
//					oldKernelBasePtrPtr[OUT]:	接收旧内核基址的指针
//		作者:		葛世超
//		时间:		2012年8月14日22:37
//
////////////////////////////////////////////////////////////////////////////////////////////////////
NTSTATUS LoadKernel(OUT PUCHAR * newKernelBasePtrPtr, OUT PUCHAR * oldKernelBasePtrPtr)
{
	ULONG rtlProcessModulesSize = 0;
	
	//获取枚举系统模块所需内存尺寸
	NTSTATUS status = ZwQuerySystemInformation(SystemModuleInformation, NULL, 0, &rtlProcessModulesSize);

	//以获取的内存尺寸作为判断函数成功的依据是由于rtlProcessModulesSize为0时函数一定不能返回STATUS_SUCCESS
	if (!rtlProcessModulesSize)
	{
		return status;
	}

	//为系统模块分配内存空间
	PRTL_PROCESS_MODULES rtlProcessModulesPtr = (PRTL_PROCESS_MODULES)ExAllocatePoolWithTag(PagedPool, rtlProcessModulesSize, 'NIMS');

	if (!rtlProcessModulesPtr)
	{
		return STATUS_NO_MEMORY;
	}

	RtlZeroMemory(rtlProcessModulesPtr, rtlProcessModulesSize);

	//第二次调用该函数且rtlProcessModulesSize不为0时可返回有效内核模块信息
	status = ZwQuerySystemInformation(SystemModuleInformation, rtlProcessModulesPtr, rtlProcessModulesSize, &rtlProcessModulesSize);

	//因rtlProcessModulesSize足够大且rtlProcessModulesPtr有效, 则可以使用函数返回值判断函数执行结果
	if (!NT_SUCCESS(status))
	{
		ExFreePoolWithTag(rtlProcessModulesPtr, 'NIMS');
		return status;
	}

	UNICODE_STRING kernelFilePath;

	RtlZeroMemory(&kernelFilePath, sizeof(kernelFilePath));

	PUCHAR oldKernelBasePtr = NULL;

	for (int i = 0; i < rtlProcessModulesPtr->NumberOfModules; ++i)
	{
		if (strstr(rtlProcessModulesPtr->Modules[i].FullPathName, "ntoskrnl.exe"))
		{
			RtlInitUnicodeString(&kernelFilePath, L"\\SystemRoot\\System32\\ntoskrnl.exe");
			oldKernelBasePtr = (PUCHAR)rtlProcessModulesPtr->Modules[i].ImageBase;
			break;
		}

		if (strstr(rtlProcessModulesPtr->Modules[i].FullPathName, "ntkrnlpa.exe"))
		{
			RtlInitUnicodeString(&kernelFilePath, L"\\SystemRoot\\System32\\ntkrnlpa.exe");
			oldKernelBasePtr = (PUCHAR)rtlProcessModulesPtr->Modules[i].ImageBase;
			break;
		}

		if (strstr(rtlProcessModulesPtr->Modules[i].FullPathName, "ntkrnlmp.exe"))
		{
			RtlInitUnicodeString(&kernelFilePath, L"\\SystemRoot\\System32\\ntkrnlmp.exe");
			oldKernelBasePtr = (PUCHAR)rtlProcessModulesPtr->Modules[i].ImageBase;
			break;
		}

		if (strstr(rtlProcessModulesPtr->Modules[i].FullPathName, "ntkrpamp.exe"))
		{
			RtlInitUnicodeString(&kernelFilePath, L"\\SystemRoot\\System32\\ntkrpamp.exe");
			oldKernelBasePtr = (PUCHAR)rtlProcessModulesPtr->Modules[i].ImageBase;
			break;
		}
	}

	ExFreePoolWithTag(rtlProcessModulesPtr, 'NIMS');

	//oldKernelBasePtr等于NULL时没有找到内核文件路径
	if (!oldKernelBasePtr)
	{
		return STATUS_NOT_FOUND;
	}

	//将内核文件内容读入内存
	OBJECT_ATTRIBUTES objectAttributes;

	RtlZeroMemory(&objectAttributes, sizeof(objectAttributes));

	InitializeObjectAttributes
		(
		&objectAttributes,
		&kernelFilePath,
		OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
		NULL,
		NULL
		);

	IO_STATUS_BLOCK ioStatusBlock;

	RtlZeroMemory(&ioStatusBlock, sizeof(ioStatusBlock));

	HANDLE kernelFileHandle = NULL;

	status = ZwOpenFile
		(
		&kernelFileHandle,
		GENERIC_READ,
		&objectAttributes,
		&ioStatusBlock,
		FILE_SHARE_READ,
		FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
		);

	if (!NT_SUCCESS(status))
	{
		return status;
	}

	FILE_STANDARD_INFORMATION fileStandardInformation;

	RtlZeroMemory(&fileStandardInformation, sizeof(fileStandardInformation));

	status = ZwQueryInformationFile
		(kernelFileHandle,
		&ioStatusBlock,
		&fileStandardInformation,
		sizeof(fileStandardInformation),
		FileStandardInformation
		);

	if (!NT_SUCCESS(status))
	{
		ZwClose(kernelFileHandle);

		return status;
	}

	ULONG kernelFileSize = fileStandardInformation.EndOfFile.QuadPart;

	PUCHAR kernelFileContentPtr = (PUCHAR)ExAllocatePoolWithTag(PagedPool, kernelFileSize, 'TNTC');

	if (!kernelFileContentPtr)
	{
		ZwClose(kernelFileHandle);

		return STATUS_NO_MEMORY;
	}

	RtlZeroMemory(kernelFileContentPtr, kernelFileSize);

	status = ZwReadFile(
		kernelFileHandle,
		NULL,
		NULL,
		NULL,
		&ioStatusBlock,
		kernelFileContentPtr,
		kernelFileSize,
		NULL,
		NULL
		);

		ZwClose(kernelFileHandle);

	if (!NT_SUCCESS(status))
	{
		ExFreePoolWithTag(kernelFileContentPtr, 'TNTC');

		return status;
	}

	//IMAGE_DOS_HEADER
	PIMAGE_DOS_HEADER imageDosHeaderPtr = (PIMAGE_DOS_HEADER)kernelFileContentPtr;

	if (imageDosHeaderPtr->e_magic != IMAGE_DOS_SIGNATURE)
	{
		ExFreePoolWithTag(kernelFileContentPtr, 'TNTC');

		return STATUS_INVALID_IMAGE_FORMAT;
	}

	//IMAGE_NT_HEADER
	PIMAGE_NT_HEADERS imageNtHeadersPtr = (PIMAGE_NT_HEADERS)(kernelFileContentPtr + imageDosHeaderPtr->e_lfanew);

	if (imageNtHeadersPtr->Signature != IMAGE_NT_SIGNATURE)
	{
		ExFreePoolWithTag(kernelFileContentPtr, 'TNTC');

		return STATUS_INVALID_IMAGE_FORMAT;
	}

	ULONG kernelMemorySize = imageNtHeadersPtr->OptionalHeader.SizeOfImage;

	//为新内核分配内存空间(非分页内存)
	PUCHAR newKernelBasePtr = (PUCHAR)ExAllocatePoolWithTag(NonPagedPool, kernelMemorySize, 'LNRK');

	if (!newKernelBasePtr)
	{
		ExFreePoolWithTag(kernelFileContentPtr, 'TNTC');

		return STATUS_NO_MEMORY;
	}

	RtlZeroMemory(newKernelBasePtr, kernelFileSize);

	//将文件内容中PE头复制到内存区
	RtlCopyMemory(newKernelBasePtr, kernelFileContentPtr, imageNtHeadersPtr->OptionalHeader.SizeOfHeaders);

	//按顺序装载各节
	PIMAGE_SECTION_HEADER imageSectionHeaderPtr = (PIMAGE_SECTION_HEADER)(kernelFileContentPtr + imageDosHeaderPtr->e_lfanew + sizeof(IMAGE_NT_HEADERS));

	for (int i = 0; i < imageNtHeadersPtr->FileHeader.NumberOfSections; ++i)
	{
		ULONG sectionVirtualAddress = imageSectionHeaderPtr[i].VirtualAddress;
		ULONG sectionFileOffset = imageSectionHeaderPtr[i].PointerToRawData;

		//只映射有效区域
		ULONG sectionSize = imageSectionHeaderPtr[i].SizeOfRawData <= imageSectionHeaderPtr[i].Misc.VirtualSize ? imageSectionHeaderPtr[i].SizeOfRawData : imageSectionHeaderPtr[i].Misc.VirtualSize;

		if (sectionSize)
		{
			RtlCopyMemory(newKernelBasePtr + sectionVirtualAddress, kernelFileContentPtr + sectionFileOffset, sectionSize);
		}
	}

	//以旧内核基址为参考基址对新内核进行基址重定位
	PIMAGE_BASE_RELOCATION imageBaseRelocationPtr = (PIMAGE_BASE_RELOCATION)(newKernelBasePtr + imageNtHeadersPtr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);

	while (imageBaseRelocationPtr->SizeOfBlock)
	{
		PUSHORT relocationDataPtr = (PUSHORT)((PUCHAR)imageBaseRelocationPtr + sizeof(IMAGE_BASE_RELOCATION));

		for (int i = 0; i < (imageBaseRelocationPtr->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT); ++i)
		{
			if (relocationDataPtr[i] >> 12 == IMAGE_REL_BASED_HIGHLOW)
			{
				PULONG relocationAddressPtr = (PULONG)(newKernelBasePtr + imageBaseRelocationPtr->VirtualAddress + (relocationDataPtr[i] & 0x0fff));
				*relocationAddressPtr = *relocationAddressPtr - imageNtHeadersPtr->OptionalHeader.ImageBase + (ULONG)oldKernelBasePtr;
			}
		}

		imageBaseRelocationPtr = (PIMAGE_BASE_RELOCATION)((PUCHAR)imageBaseRelocationPtr + imageBaseRelocationPtr->SizeOfBlock);
	}

	//修复被重定位过的系统服务分发表(SSDT), 将其指回新内核对应分发函数入口
	PSYSTEM_SERVICE_DESCRIPTOR_TABLE systemServiceDescriptorTable = (PSYSTEM_SERVICE_DESCRIPTOR_TABLE)(newKernelBasePtr + (ULONG)KeServiceDescriptorTable - (ULONG)oldKernelBasePtr);

	systemServiceDescriptorTable->NTOSKRNL.NumberOfService = KeServiceDescriptorTable->NTOSKRNL.NumberOfService;

	if (KeServiceDescriptorTable->NTOSKRNL.CounterTableBase)
	{
		systemServiceDescriptorTable->NTOSKRNL.CounterTableBase = (PULONG)(newKernelBasePtr + (ULONG)KeServiceDescriptorTable->NTOSKRNL.CounterTableBase - (ULONG)oldKernelBasePtr);
	}

	if (KeServiceDescriptorTable->NTOSKRNL.ParameterTableBase)
	{
		systemServiceDescriptorTable->NTOSKRNL.ParameterTableBase = (PUCHAR)(newKernelBasePtr + (ULONG)KeServiceDescriptorTable->NTOSKRNL.ParameterTableBase - (ULONG)oldKernelBasePtr);
	}

	if (KeServiceDescriptorTable->NTOSKRNL.ServiceTableBase)
	{
		systemServiceDescriptorTable->NTOSKRNL.ServiceTableBase = (PULONG)(newKernelBasePtr + (ULONG)KeServiceDescriptorTable->NTOSKRNL.ServiceTableBase - (ULONG)oldKernelBasePtr);

		for (int i = 0; i < systemServiceDescriptorTable->NTOSKRNL.NumberOfService; ++i)
		{
			systemServiceDescriptorTable->NTOSKRNL.ServiceTableBase[i] += (ULONG)newKernelBasePtr - (ULONG)oldKernelBasePtr;
		}
	}

	ExFreePoolWithTag(kernelFileContentPtr, 'TNTC');

	*newKernelBasePtrPtr = newKernelBasePtr;
	*oldKernelBasePtrPtr = oldKernelBasePtr;

	return STATUS_SUCCESS;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
//
//		函数名称:	FreeKernel
//		函数作用:	释放加载的内核
//		参数:		kernelBasePtr[IN]:		新内核基址
//
////////////////////////////////////////////////////////////////////////////////////////////////////
VOID FreeKernel(IN PUCHAR kernelBasePtr)
{
	ExFreePoolWithTag(kernelBasePtr, 'LNRK');
}

转载于:https://my.oschina.net/ImageBreaker/blog/72839

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐