X86重载内核
测试系统:WinXp, 环境:vs2017
内核重载
一、内核重载简述
涉及PE文件,驱动程序编写, 对X86内核的了解
内核重载其实就是让所有的SSDT函数全部走自己写入的一块新内核内核重载不是什么高端技术,但对于学习驱动编程的新手而言,还是有学习参考价值的
二、实现步骤(部分代码)
1.打开内核文件存为buffer,拉伸PE,修重定向表,IAT表
NTSTATUS LoadNtkrnlpa()
{
NTSTATUS status = STATUS_SUCCESS;
HANDLE hFile = NULL;
OBJECT_ATTRIBUTES objAttr;
IO_STATUS_BLOCK ioBlock;
UNICODE_STRING FileName;
FILE_STANDARD_INFORMATION FileInfo;
LARGE_INTEGER Lageint; // 读取位置offset
RtlInitUnicodeString(&FileName, FILEPATH);
InitializeObjectAttributes(&objAttr, &FileName, OBJ_CASE_INSENSITIVE, NULL, NULL);
status = ZwOpenFile(&hFile, FILE_ALL_ACCESS, &objAttr, &ioBlock, 0, FILE_NON_DIRECTORY_FILE);
if (!NT_SUCCESS(status))
{
DbgPrint("ZwOpenFile Failed!, status:%d\n", status);
return STATUS_UNSUCCESSFUL;
}
status = ZwQueryInformationFile(hFile, &ioBlock, &FileInfo, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation);
if (!NT_SUCCESS(status))
{
ZwClose(hFile);
DbgPrint("ZwQueryInformationFile Failed!\n");
return STATUS_UNSUCCESSFUL;
}
FileSize = FileInfo.EndOfFile.LowPart;
pFileBuffer = ExAllocatePool(NonPagedPool, FileSize);
Lageint.QuadPart = 0;
status = ZwReadFile(hFile, NULL, NULL, NULL, &ioBlock, pFileBuffer, FileSize, &Lageint, NULL);
if (!NT_SUCCESS(status))
{
ZwClose(hFile);
DbgPrint("ZwReadFile Failed!\n");
return STATUS_UNSUCCESSFUL;
}
ZwClose(hFile);
// 读取PE信息
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
{
ExFreePool(pFileBuffer);
pFileBuffer = NULL;
DbgPrint("Read PE File Failed\n");
return STATUS_UNSUCCESSFUL;
}
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDosHeader->e_lfanew);
if (pNTHeader->Signature != IMAGE_NT_SIGNATURE)
{
ExFreePool(pFileBuffer);
pFileBuffer = NULL;
DbgPrint("Read PE File Failed\n");
return STATUS_UNSUCCESSFUL;
}
pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);
pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
pReloactionDirectory = (PIMAGE_BASE_RELOCATION)((DWORD)pDosHeader + RVA_TO_FOA(pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress));
pIATDirectory = (PIMAGE_THUNK_DATA)((DWORD)pDosHeader + RVA_TO_FOA(pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress));
return status;
}
(1)修重定向表
NTSTATUS FixRelocTable(DWORD OrignalImageBase)
{
if (pReloactionDirectory == NULL) return STATUS_UNSUCCESSFUL;
// 修复重定位表
DWORD AddItem = OrignalImageBase - pOptionalHeader->ImageBase;
// pOptionalHeader->ImageBase = NewImageBase;
PIMAGE_BASE_RELOCATION pTempRelocationDir = pReloactionDirectory;
UINT Count = 0;
do
{
DWORD ChunkNum = (pTempRelocationDir->SizeOfBlock - 0x8) / 0x2;
for (UINT i = 0; i < ChunkNum; i++)
{
PWORD pItem = (PWORD)(((DWORD)pTempRelocationDir + 0x8) + 0x2 * i);
DWORD Type = (*pItem) >> 12;
if (Type == 3)
{
PDWORD pFixAddress = (PDWORD)((DWORD)pDosHeader + RVA_TO_FOA(pTempRelocationDir->VirtualAddress + (*pItem & 0x0FFF)));
*pFixAddress += AddItem;
}
}
pTempRelocationDir = (PIMAGE_BASE_RELOCATION)((DWORD)pTempRelocationDir + pTempRelocationDir->SizeOfBlock);
Count++;
} while (pTempRelocationDir->VirtualAddress != 0 && pTempRelocationDir->SizeOfBlock != 0);
// DbgPrint("FixBlockCount:%d\n", Count);
return STATUS_SUCCESS;
}
(2)修IAT表
NTSTATUS FixIATTable()
{
PIMAGE_THUNK_DATA pTemIATDir = pIATDirectory;
ULONG CopySize = 0;
while (pTemIATDir->u1.Function != 0)
{
CopySize += 4;
pTemIATDir++;
}
PULONG pCurrentIATDir = OrignImage + pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress;
RtlCopyMemory(pIATDirectory, pCurrentIATDir, CopySize);
return STATUS_SUCCESS;
}
2.内核层申请一块内存贴入buffer
NTSTATUS CopyFileBufferToImageBuffer(_In_ LPVOID pFilebuffer_, _Out_ LPVOID* pImageBuffer_)
{
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFilebuffer_;
PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFilebuffer_ + pDosHeader->e_lfanew);
PIMAGE_FILE_HEADER pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 0x4);
PIMAGE_OPTIONAL_HEADER pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
DWORD AlignImageSize = Align(pOptionalHeader->SizeOfImage, pOptionalHeader->SectionAlignment);
*pImageBuffer_ = ExAllocatePool(NonPagedPool, AlignImageSize);
memset(*pImageBuffer_, 0, AlignImageSize);
memcpy(*pImageBuffer_, pFilebuffer_, pOptionalHeader->SizeOfHeaders);
PIMAGE_SECTION_HEADER TempSectionHeader = pSectionHeader;
for (int i = 0; i < pFileHeader->NumberOfSections; i++)
{
memcpy((LPVOID)((DWORD)*pImageBuffer_ + TempSectionHeader->VirtualAddress), (LPVOID)((DWORD)pDosHeader + TempSectionHeader->PointerToRawData), TempSectionHeader->SizeOfRawData);
TempSectionHeader++;
}
return STATUS_SUCCESS;
}
3.修复ssdt中函数地址为新内核函数地址
4.创建山寨系统服务表
NTSTATUS SetNewSSDT(DWORD NewImageBase)
{
pNewKeServiceDescriptorTable = (PKSERVICE_TABLE_DESCRIPTOR)((DWORD)KeServiceDescriptorTable - OrignImage + NewImageBase);
// 函数表
pNewKeServiceDescriptorTable->ntoskrnl.ServiceTableBase = (PULONG)((DWORD)KeServiceDescriptorTable->ntoskrnl.ServiceTableBase - OrignImage + NewImageBase);
// 函数个数
pNewKeServiceDescriptorTable->ntoskrnl.NumberOfService = KeServiceDescriptorTable->ntoskrnl.NumberOfService;
// 调用次数
// pNewKeServiceDescriptorTable->ntoskrnl.ServiceCounterTableBase = (PULONG)((DWORD)KeServiceDescriptorTable->ntoskrnl.ServiceCounterTableBase - OrignImage + NewImageBase);
// 参数表
pNewKeServiceDescriptorTable->ntoskrnl.ParamTableBase = (PULONG)((DWORD)KeServiceDescriptorTable->ntoskrnl.ParamTableBase - OrignImage + NewImageBase);
PageProtectOff();
// 修复函数地址表 ,其实重定位表修复那里就修好了
for (ULONG i = 0; i < pNewKeServiceDescriptorTable->ntoskrnl.NumberOfService; i++)
{
pNewKeServiceDescriptorTable->ntoskrnl.ServiceTableBase[i] += (-OrignImage + NewImageBase);
}
PageProtectOn();
return STATUS_SUCCESS;
}
5.hook KiFastCallEntry
NTSTATUS HookKiFastCallEntry()
{
ULONG HookAddr = 0;
ULONG uKiFastCallEntry = 0;
// 找到KiFastCallEntry函数首地址, 在特殊模组寄存器的0x176号寄存器中
__asm
{
push ecx;
push eax;
push edx;
mov ecx, 0x176; // 设置编号
rdmsr; ;// 读取到edx:eax
mov uKiFastCallEntry, eax;// 保存到变量
pop edx;
pop eax;
pop ecx;
}
for (ULONG i = 0; i < 0x1FF; ++i)
{
if (RtlCompareMemory((UCHAR*)uKiFastCallEntry + i, OriginalCode, 5) == 5)
{
HookAddr = uKiFastCallEntry + i;
break;
}
}
if (HookAddr == 0)
{
DbgPrint("Not Find 2be1c1e902 bytes");
return STATUS_UNSUCCESSFUL;
}
PDWORD JmpAddr = (PDWORD)HookProc;
PageProtectOff();
DWORD32 X = (HookAddr + 5) - ((DWORD32)&OriginalCode[5] + 5);
OriginalCode[5] = '\xE9';
*(DWORD32*)(OriginalCode + 5 + 1) = X;
pOrigianlCmd = (PORIGINALCOMD)(CHAR*)OriginalCode;
BackAddr = HookAddr + 5;
memset(NewCode, 0, 64);
NewCode[0] = '\xE9';
X = (DWORD32)JmpAddr - (HookAddr + 5);
*(DWORD32*)(NewCode + 1) = (DWORD32)X;
int Numnop = 5 - 5;
for (int i = 0; i < Numnop; i++)
{
NewCode[5 + i] = '\x90';
}
RtlMoveMemory(HookAddr, NewCode, 5);
PageProtectOn();
return STATUS_SUCCESS;
}
三、代码测试截图
四、总结(源码地址)
github地址
https://github.com/DeadpoolWilson12/kernelReload_