目录

不调用内核API定位到NT内核基址

通用思路

  1. 明确一点,所有的内核模块基址,一定是4KB对齐的
  2. 所以我们可以想办法获取到处于NT内核中的一个函数地址,将其页面对齐后,以PAGE_SIZE为单位向前搜索MZ
  3. 搜索到MZ后,继续搜索NT头特征、可选头特征,都满足的话就可以认为是NT内核了

实现思路

  1. 在x64系统调用中,我们知道内核的落脚地为KiSystemCall64,这个函数地址是保存在MSR寄存器中的,即__readmsr(0xC0000082)
  2. 所以我们的思路就很清楚了,获取KiSystemCall64地址、页面对齐、向前搜索PE特征,代码如下:
PVOID
GetKernelBaseWithoutAPI(
	VOID
	)
{
	static ULONG64 KernelBase = 0;
	if (KernelBase != 0)
	{
		return (PVOID)KernelBase;
	}

	ULONG64 AddrAligned = __readmsr(0xC0000082) & ~(0xFFFull);
	while (AddrAligned > 0)
	{
		PIMAGE_DOS_HEADER Dos = (PIMAGE_DOS_HEADER)AddrAligned;
		if (Dos->e_magic == IMAGE_DOS_SIGNATURE)
		{
			LONG e_lfanew = Dos->e_lfanew;
			if (e_lfanew > 0 && e_lfanew <= 0x1000)
			{
				PIMAGE_NT_HEADERS64 Nt = (PIMAGE_NT_HEADERS64)(AddrAligned + (ULONG64)e_lfanew);
				if (Nt->Signature == IMAGE_NT_SIGNATURE &&
					Nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC &&
					Nt->OptionalHeader.ImageBase == AddrAligned &&
					Nt->OptionalHeader.SizeOfImage != 0)
				{
					KernelBase = AddrAligned;
					return (PVOID)KernelBase;
				}
			}
		}

		AddrAligned -= PAGE_SIZE;
	}

	return NULL;
}
Windows内核 内核基址 MSR Ntoskrnl 逆向工程