-
-
[原创]重载内核之三获取原始地址
-
发表于:
2014-5-19 01:09
13127
-
重载内核的相关文章实在是太多了,鉴于还是有很多初学者研究这一块,本文仅作为一个引导作用,文笔不好,见谅。
我的博客:http://blog.csdn.net/sidyhe
开发环境:VS2010 + WinDDK
测试环境:VirtualDDK + VMware + Win7 sp1 x86
第一部分链接:http://bbs.pediy.com/showthread.php?t=187863
第二部分链接:http://bbs.pediy.com/showthread.php?t=187919
小结与修正
目前已经实现了一份简单的重载内核代码,但是如果你也跟着我实现了此部分,会发现此代码根本不能使用,甚至不能拿到本机来测试,是的,新的内核还是有大量的问题,驱动加载后会导致一些程序打不开,但是并不蓝屏,有意思的现象。
写上一篇文章的时候没有测试的那么完善,但是我拿出我之前写的重载内核代码,并没有上述问题,仔细分析代码并回忆,问题还是出在了重定位以及需要额外的处理。那么关于修复重定位的部分就需要重新写了,把修复过程分为两部分,第一次全部重定位到新模块上,第二次有选择的重定位到原模块上,为什么需要那么麻烦?这就涉及到了原始地址的获取方式问题,原始地址都存储在一个叫KiServiceTable的变量中,详见WRK。为什么要获取原始地址?因为当驱动加载的时候你无法确定当前的SSDT表是否被HOOK,所以在第一次修复重定位之后去找KiServiceTable,然后再进行第二次重定位的修复(我无法保证第二次修复不会破坏KiServiceTable中的地址)。
重新写一份代码,当然大部分还是从原来的代码复制过来,这样有利于逻辑上的思考,先不进行HOOK,把重载部分先理顺清楚,重定位修复代码修改为这个样子:
PVOID ReloadNtModule(PKLDR_DATA_TABLE_ENTRY PsLoadedModuleList)
{
PVOID lpImageAddress = NULL;
PKLDR_DATA_TABLE_ENTRY NtLdr = (PKLDR_DATA_TABLE_ENTRY)PsLoadedModuleList->InLoadOrderLinks.Flink;
PVOID lpFileBuffer;
DbgPrint("Nt Module File is %wZ\n", &NtLdr->FullDllName);
if (lpFileBuffer = KeGetFileBuffer(&NtLdr->FullDllName))
{
PIMAGE_DOS_HEADER lpDosHeader = (PIMAGE_DOS_HEADER)lpFileBuffer;
PIMAGE_NT_HEADERS lpNtHeader = (PIMAGE_NT_HEADERS)((PCHAR)lpDosHeader + lpDosHeader->e_lfanew);
if (lpImageAddress = ExAllocatePool(NonPagedPool, lpNtHeader->OptionalHeader.SizeOfImage))
{
PUCHAR lpImageBytes = (PUCHAR)lpImageAddress;
IMAGE_SECTION_HEADER *lpSection = IMAGE_FIRST_SECTION(lpNtHeader);
ULONG i;
RtlZeroMemory(lpImageAddress, lpNtHeader->OptionalHeader.SizeOfImage);
RtlCopyMemory(lpImageBytes, lpFileBuffer, lpNtHeader->OptionalHeader.SizeOfHeaders);
for (i = 0; i < lpNtHeader->FileHeader.NumberOfSections; i++)
{
RtlCopyMemory(lpImageBytes + lpSection[i].VirtualAddress, (PCHAR)lpFileBuffer + lpSection[i].PointerToRawData, lpSection[i].SizeOfRawData);
}
if (KeFixIAT(PsLoadedModuleList, lpImageAddress))
{
KeFixReloc1(lpImageAddress, NtLdr->DllBase);
}
else
{
ExFreePool(lpImageAddress);
lpImageAddress = NULL;
}
}
ExFreePool(lpFileBuffer);
}
if (lpImageAddress) DbgPrint("ImageAddress:0x%p\n", lpImageAddress);
return lpImageAddress;
}
VOID KeFixReloc1(PVOID ImageBaseAddress)
{
IMAGE_DOS_HEADER *lpDosHeader = (IMAGE_DOS_HEADER*)ImageBaseAddress;
IMAGE_NT_HEADERS *lpNtHeader = (IMAGE_NT_HEADERS *)((PCHAR)lpDosHeader + lpDosHeader->e_lfanew);
IMAGE_BASE_RELOCATION *lpRelocateTable = (IMAGE_BASE_RELOCATION*)((PCHAR)ImageBaseAddress + lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
ULONG_PTR DifferOffset = (ULONG_PTR)ImageBaseAddress - lpNtHeader->OptionalHeader.ImageBase;
while (lpRelocateTable->SizeOfBlock)
{
ULONG NumberOfItems = (lpRelocateTable->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT);
USHORT *lpItem = (USHORT*)((PCHAR)lpRelocateTable + sizeof(IMAGE_BASE_RELOCATION));
ULONG i;
for (i = 0; i < NumberOfItems; i++)
{
switch (lpItem[i] >> 12)
{
case IMAGE_REL_BASED_HIGHLOW:
{
ULONG_PTR *lpFixAddress = (ULONG_PTR *)((PCHAR)ImageBaseAddress + lpRelocateTable->VirtualAddress + (lpItem[i] & 0x0FFF));
*lpFixAddress += DifferOffset;
}
break;
case IMAGE_REL_BASED_ABSOLUTE://do nothing
break;
default:
DbgPrint("KeFixReloc1:Found unknown type(%X).\n", (lpItem[i] >> 12));
break;
}
}
lpRelocateTable = (IMAGE_BASE_RELOCATION *)((PCHAR)lpRelocateTable + lpRelocateTable->SizeOfBlock);
}
lpNtHeader->OptionalHeader.ImageBase = (ULONG)ImageBaseAddress;
return;
}
VOID KeFixReloc2(PVOID New, PVOID Old)
{
IMAGE_DOS_HEADER *lpDosHeader = (IMAGE_DOS_HEADER*)New;
IMAGE_NT_HEADERS *lpNtHeader = (IMAGE_NT_HEADERS *)((PCHAR)lpDosHeader + lpDosHeader->e_lfanew);
IMAGE_BASE_RELOCATION *lpRelocateTable = (IMAGE_BASE_RELOCATION*)((PCHAR)New + lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
while (lpRelocateTable->SizeOfBlock)
{
ULONG NumberOfItems = (lpRelocateTable->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT);
USHORT *lpItem = (USHORT*)((PCHAR)lpRelocateTable + sizeof(IMAGE_BASE_RELOCATION));
ULONG i;
for (i = 0; i < NumberOfItems; i++)
{
switch (lpItem[i] >> 12)
{
case IMAGE_REL_BASED_HIGHLOW:
{
PVOID lpFixAddress = (PCHAR)New + lpRelocateTable->VirtualAddress + (lpItem[i] & 0x0FFF);
KeFixRelocEx(New, Old, lpFixAddress);
}
break;
case IMAGE_REL_BASED_ABSOLUTE://do nothing
break;
default:
break;
}
}
lpRelocateTable = (IMAGE_BASE_RELOCATION *)((PCHAR)lpRelocateTable + lpRelocateTable->SizeOfBlock);
}
return;
}
BOOLEAN KeIsExecutable(PVOID ImageBase, PVOID Address)
{
IMAGE_DOS_HEADER *lpDosHeader = (IMAGE_DOS_HEADER*)ImageBase;
IMAGE_NT_HEADERS *lpNtHeader = (IMAGE_NT_HEADERS *)((PCHAR)lpDosHeader + lpDosHeader->e_lfanew);
IMAGE_SECTION_HEADER *lpSecHdr = IMAGE_FIRST_SECTION(lpNtHeader);
ULONG_PTR Rva = (ULONG_PTR)Address - (ULONG_PTR)ImageBase;
USHORT i;
for (i = 0; i < lpNtHeader->FileHeader.NumberOfSections; i++)
{
if (Rva >= lpSecHdr[i].VirtualAddress && Rva < lpSecHdr[i].VirtualAddress + lpSecHdr[i].SizeOfRawData)
{
return ((lpSecHdr[i].Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0);
}
}
return FALSE;
}
VOID KeFixRelocEx(PVOID New, PVOID Old, PVOID FixAddress)
{
if (KeIsExecutable(New, FixAddress))
{
if (KeIsExecutable(New, *(PVOID*)FixAddress))
{
if (KeIsIAT(New, *(PVOID*)FixAddress))
{
NOTHING;
}
else
{
*(ULONG_PTR*)FixAddress = *(ULONG_PTR*)FixAddress - (ULONG_PTR)New + (ULONG_PTR)Old;
}
}
else
{
*(ULONG_PTR*)FixAddress = *(ULONG_PTR*)FixAddress - (ULONG_PTR)New + (ULONG_PTR)Old;
}
}
else
{
if (KeIsExecutable(New, *(PVOID*)FixAddress))
{
NOTHING;
}
else
{
*(ULONG_PTR*)FixAddress = *(ULONG_PTR*)FixAddress - (ULONG_PTR)New + (ULONG_PTR)Old;
}
}
return;
}
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!