[C] 纯文本查看 复制代码
原理:
1.为物理地址扩展的 内核模块ntkrnlpa.exe申请一块新的SizeOfImage大小的内存
2.将ntkrnlpa.exe拉伸读取至新申请的内存
3.修复新申请的ntkrnlpa.exe重定位表
4.修复新申请的ntkrnlpa.exe系统服务表
5.在KiFastCallEntry关键部位加钩子
6.处理你感兴趣的程序 让它调用新的内核模块
测试通过
//测试代码
#include <ntddk.h>
//系统服务描述符表
typedef struct ServiceDescriptorEntry {
unsigned int *ServiceTableBase; // 系统服务表基址
unsigned int *ServiceCounterTableBase; // 系统服务表被调用的次数
unsigned int NumberOfServices; // 系统服务表函数个数
unsigned char *ParamTableBase; // 系统服务表函数参数大小 (字节)
}ServiceDescriptorTableEntry, *PServiceDescriptorTableEntry;
__declspec(dllimport) ServiceDescriptorTableEntry KeServiceDescriptorTable;
typedef NTSTATUS(NTAPI *PNewZwOpenProcess)(
_Out_ PHANDLE ProcessHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_opt_ PCLIENT_ID ClientId
);
ULONG32 g_uOldNtOpenProcess = 0;
ULONG32 g_uJmpPoint = 0;
// 关闭cr0读写位
void Cr0WpOff()
{
__asm
{
cli
mov eax, cr0
and eax, not 10000h
mov cr0, eax
}
}
// 开启cr0读写位
void Cr0WpOn()
{
__asm
{
mov eax, cr0
or eax, 10000h
mov cr0, eax
sti
}
}
VOID PrintTest()
{
if (strstr((PCHAR)PsGetCurrentProcess() + 0x174, "notepad") != 0)
{
KdPrint(("记事本被Hook了\n"));
}
}
__declspec(naked)
VOID HookFunc()
{
__asm
{
pushad
pushfd
call PrintTest
popfd
popad
push 0x0C4
jmp g_uJmpPoint
}
}
VOID HookNtOpenProcess()
{
g_uOldNtOpenProcess = KeServiceDescriptorTable.ServiceTableBase[122];
g_uJmpPoint = g_uOldNtOpenProcess + 5;
UCHAR uJmp[5] = { 0 };
uJmp[0] = 0xE9;
*(PULONG32)&uJmp[1] = (ULONG32)HookFunc - g_uOldNtOpenProcess - 5;
Cr0WpOff();
RtlCopyMemory((PVOID)g_uOldNtOpenProcess, uJmp, 5);
Cr0WpOn();
}
//驱动卸载
VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
UCHAR uJmp[5] = { 0x68, 0xc4, 0x00, 0x00, 0x00 };
Cr0WpOff();
RtlCopyMemory((PVOID)g_uOldNtOpenProcess, uJmp, 5);
Cr0WpOn();
}
//驱动加载
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pStrRegPath)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
pDriverObject->DriverUnload = DriverUnload;
HookNtOpenProcess();
return ntStatus;
}
//内核重载代码
#pragma once
#include <ntddk.h>
#include "PE.h"
//系统服务描述符表
typedef struct ServiceDescriptorEntry {
unsigned int *ServiceTableBase; // 系统服务表基址
unsigned int *ServiceCounterTableBase; // 系统服务表被调用的次数
unsigned int NumberOfServices; // 系统服务表函数个数
unsigned char *ParamTableBase; // 系统服务表函数参数大小 (字节)
}ServiceDescriptorTableEntry, *PServiceDescriptorTableEntry;
__declspec(dllimport) ServiceDescriptorTableEntry KeServiceDescriptorTable;
ServiceDescriptorTableEntry *g_pNewKeServiceDescriptorTable;
ServiceDescriptorTableEntry *g_qNewKeServiceDescriptorTable;
typedef NTSTATUS(NTAPI *PNewZwOpenProcess)(
_Out_ PHANDLE ProcessHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_opt_ PCLIENT_ID ClientId
);
typedef struct _PE
{
IMAGE_DOS_HEADER DosHeader;
IMAGE_NT_HEADERS32 NtHeaders;
IMAGE_SECTION_HEADER SectionHeader;
}PE, *pPE;
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pStrRegPath);
VOID DriverUnload(PDRIVER_OBJECT pDriverObject);
ULONG32 GetKernelImageBase();
PVOID GetNewKernelBuffer(PUNICODE_STRING pStrKernelPathName);
VOID RepirRelocTable(ULONG32 uNewModule, ULONG32 uOldModule);
VOID HookKiFastCallEntry();
ULONG32 SearchHookPoint(PULONG32 pHookAddress);
VOID CallZwOpenProcess();
VOID BeginHook(ULONG32 g_uHookAddress);
VOID RepirSSDT(ULONG32 pNewKernelBuffer, ULONG32 uKernelImageBase);
#pragma once
#include "KernelOverload.h"
// 关闭cr0读写位
void Cr0WpOff()
{
__asm
{
cli
mov eax, cr0
and eax, not 10000h
mov cr0, eax
}
}
// 开启cr0读写位
void Cr0WpOn()
{
__asm
{
mov eax, cr0
or eax, 10000h
mov cr0, eax
sti
}
}
//找到要Hook的点
ULONG32 SearchHookPoint(PULONG32 pRetAddress)
{
if (pRetAddress == NULL)
{
return -1;
}
PUCHAR pAddress = (PUCHAR)pRetAddress;
for (ULONG32 uCount = 0; uCount < 500; uCount++, pAddress--)
{
if ((*(pAddress) == 0x2b &&
*(pAddress + 1) == 0xe1 &&
*(pAddress + 2) == 0xc1 &&
*(pAddress + 3) == 0xe9 &&
*(pAddress + 4) == 0x02))
{
return (ULONG32)pAddress;
}
}
return -2;
}
//立刻调用ZwOpenProcess让钩子生效
VOID CallZwOpenProcess()
{
NTSTATUS ntStatus = 0;
HANDLE hPorcess = NULL;
UNICODE_STRING strProcessName = { 0 };
OBJECT_ATTRIBUTES objAttr = { 0 };
RtlInitUnicodeString(&strProcessName, L"\\??\\C:\\Windows\\System32\\ntkrnlpa.exe");
InitializeObjectAttributes(&objAttr, &strProcessName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
CLIENT_ID clientId = { 0 };
ntStatus = ZwOpenProcess(&hPorcess, GENERIC_READ, &objAttr, &clientId);
if (!NT_SUCCESS(ntStatus))
{
KdPrint(("SearchKiFastCallEntry() ZwCreateFile unsuccessed!\n"));
return;
}
ZwClose(hPorcess);
}
// 获取内核模块基址
ULONG32 GetKernelImageBase()
{
ULONG32 uKernelImageBase = 0;
_asm
{
push eax
mov eax, fs:[0x34]
add eax, 0x18
mov eax, [eax]
mov eax, [eax]
mov eax, [eax + 0x18]
mov uKernelImageBase, eax
pop eax
}
return uKernelImageBase == 0 ? 0 : uKernelImageBase;
}
// 获取新的内核模块虚拟缓存
PVOID GetNewKernelBuffer(PUNICODE_STRING pStrKernelPathName)
{
PE pe = { 0 };
HANDLE hFile = NULL;
OBJECT_ATTRIBUTES objectAttributes = { 0 };
IO_STATUS_BLOCK ioStatusBlock = { 0 };
InitializeObjectAttributes(&objectAttributes, pStrKernelPathName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
NTSTATUS ntStatus = ZwCreateFile(&hFile, GENERIC_READ, &objectAttributes, &ioStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ, FILE_OPEN_IF, FILE_NON_DIRECTORY_FILE, NULL, 0);
if (!NT_SUCCESS(ntStatus))
{
KdPrint(("ZwCreateFile错误:%x\n", ntStatus));
return NULL;
}
LARGE_INTEGER fileOffset = { 0 };
fileOffset.QuadPart = 0;
//读取DOS头
ntStatus = ZwReadFile(hFile, NULL, NULL, NULL, &ioStatusBlock, &pe.DosHeader, sizeof(IMAGE_DOS_HEADER), &fileOffset, NULL);
if (!NT_SUCCESS(ntStatus))
{
KdPrint(("ZwReadFile错误:%x\n", ntStatus));
return NULL;
}
fileOffset.QuadPart += pe.DosHeader.e_lfanew;
//读取NT头
ntStatus = ZwReadFile(hFile, NULL, NULL, NULL, &ioStatusBlock, &pe.NtHeaders, sizeof(IMAGE_NT_HEADERS32), &fileOffset, NULL);
if (!NT_SUCCESS(ntStatus))
{
KdPrint(("ZwReadFile错误:%x\n", ntStatus));
return NULL;
}
PVOID pNewBuffer = ExAllocatePool(NonPagedPool, pe.NtHeaders.OptionalHeader.SizeOfImage);
if (pNewBuffer == NULL)
{
KdPrint(("pNewBuffer错误\n"));
return NULL;
}
PVOID pTempBuffer = pNewBuffer;
RtlCopyMemory(pTempBuffer, &pe.DosHeader, sizeof(IMAGE_DOS_HEADER));
pTempBuffer = (PVOID)((ULONG32)pTempBuffer + pe.DosHeader.e_lfanew);
RtlCopyMemory(pTempBuffer, &pe.NtHeaders, sizeof(IMAGE_NT_HEADERS32));
fileOffset.QuadPart += sizeof(IMAGE_NT_HEADERS32);
pTempBuffer = (PVOID)((ULONG32)pTempBuffer + sizeof(IMAGE_NT_HEADERS32));
//读取节表
ntStatus = ZwReadFile(hFile, NULL, NULL, NULL, &ioStatusBlock, pTempBuffer, (sizeof(IMAGE_SECTION_HEADER) * pe.NtHeaders.FileHeader.NumberOfSections), &fileOffset, NULL);
if (!NT_SUCCESS(ntStatus))
{
KdPrint(("ZwReadFile错误:%x\n", ntStatus));
return NULL;
}
PIMAGE_SECTION_HEADER pTempSectionHeader = pTempBuffer;
//读取节内容
for (ULONG32 uCount = 0; uCount < pe.NtHeaders.FileHeader.NumberOfSections; uCount++)
{
pTempBuffer = (PVOID)((ULONG32)pNewBuffer + pTempSectionHeader->VirtualAddress);
fileOffset.QuadPart = pTempSectionHeader->PointerToRawData;
ntStatus = ZwReadFile(hFile, NULL, NULL, NULL, &ioStatusBlock, pTempBuffer, pTempSectionHeader->SizeOfRawData, &fileOffset, NULL);
if (!NT_SUCCESS(ntStatus))
{
KdPrint(("ZwReadFile错误:%x\n", ntStatus));
return NULL;
}
pTempSectionHeader++;
}
return pNewBuffer;
}
#include "KernelOverload.h"
#include "BaseFunctions.h"
PVOID g_pNewKernelBuffer = NULL;
ULONG32 g_uOldNtOpenProcessFuncAddress = 0;
ULONG32 g_uHookAddress = 0;
ULONG32 g_uJmpAdress = 0;
ULONG32 g_uOffset = 0;
//驱动加载
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pStrRegPath)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
pDriverObject->DriverUnload = DriverUnload;
//获取内核模块基址
ULONG32 uKernelImageBase = GetKernelImageBase();
KdPrint(("uKernelImageBase:%08x\n", uKernelImageBase));
// 获取新的内核模块虚拟缓存
UNICODE_STRING strKernelPathName = RTL_CONSTANT_STRING(L"\\??\\C:\\WINDOWS\\system32\\ntkrnlpa.exe");
PVOID pNewKernelBuffer = GetNewKernelBuffer(&strKernelPathName);
if (!MmIsAddressValid(pNewKernelBuffer))
{
KdPrint(("pNewKernelBuffer无效!\n"));
return STATUS_UNSUCCESSFUL;
}
KdPrint(("pNewKernelBuffer:%08x\n", pNewKernelBuffer));
g_pNewKernelBuffer = pNewKernelBuffer;
//基址重定位
RepirRelocTable((ULONG32)pNewKernelBuffer, uKernelImageBase);
g_uOffset = (ULONG32)pNewKernelBuffer - uKernelImageBase;
//系统服务表重定位
RepirSSDT((ULONG32)pNewKernelBuffer, uKernelImageBase);
KdPrint(("g_uOffset:%08x\n", g_uOffset));
//对KiFastCallEntry加钩子
HookKiFastCallEntry();
return ntStatus;
}
//驱动卸载
VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
//卸载新的模块
if (g_pNewKernelBuffer)
{
ExFreePool(g_pNewKernelBuffer);
g_pNewKernelBuffer = NULL;
}
UCHAR uJmp[5] = { 0x2b, 0xe1, 0xc1, 0xe9, 0x02 };
Cr0WpOff();
RtlCopyMemory((PVOID)g_uHookAddress, uJmp, 5);
Cr0WpOn();
}
//修复重定位表
VOID RepirRelocTable(ULONG32 uNewModule, ULONG32 uOldModule)
{
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS32 pNtHeaders = NULL;
PIMAGE_BASE_RELOCATION pRelocation = NULL;
PIMAGE_DATA_DIRECTORY pData = NULL;
pDosHeader = (PIMAGE_DOS_HEADER)uNewModule;
pNtHeaders = (PIMAGE_NT_HEADERS32)((ULONG32)pDosHeader + pDosHeader->e_lfanew);
pData = pNtHeaders->OptionalHeader.DataDirectory;
//定位重定位表
pRelocation = (PIMAGE_BASE_RELOCATION)((ULONG32)uNewModule + pData[5].VirtualAddress);
//由于新的内核里面的全局变量地址都是用的老的 所以要加上它们之间的偏移量 就等于我们新的内核全局变量地址
ULONG32 uOffset = uOldModule - pNtHeaders->OptionalHeader.ImageBase;
while (pRelocation->VirtualAddress != 0 && pRelocation->SizeOfBlock != 0)
{
ULONG32 uNumOfRelocs = (pRelocation->SizeOfBlock - 8) / 2;
PUSHORT pUShort = (PUSHORT)((ULONG32)pRelocation + 8);
for (ULONG32 uCount = 0; uCount < uNumOfRelocs; uCount++, pUShort++)
{
if (((*pUShort) >> 12) == 3)
{
PULONG32 pUlong32 = (PULONG32)((*pUShort & 0x0FFF) + pRelocation->VirtualAddress + uNewModule);
*pUlong32 += uOffset;
}
}
pRelocation = (PIMAGE_BASE_RELOCATION)((ULONG32)pRelocation + pRelocation->SizeOfBlock);
}
}
//修复新的系统服务表
VOID RepirSSDT(ULONG32 pNewKernelBuffer, ULONG32 uKernelImageBase)
{
g_pNewKeServiceDescriptorTable = (PServiceDescriptorTableEntry)((ULONG32)&KeServiceDescriptorTable + g_uOffset);
g_pNewKeServiceDescriptorTable->NumberOfServices = KeServiceDescriptorTable.NumberOfServices;
ULONG32 uOffset = ((ULONG32)KeServiceDescriptorTable.ServiceTableBase - uKernelImageBase);
g_pNewKeServiceDescriptorTable->ServiceTableBase = (PULONG32)(pNewKernelBuffer + uOffset);
for (ULONG32 uCount = 0; uCount < g_pNewKeServiceDescriptorTable->NumberOfServices; uCount++)
{
g_pNewKeServiceDescriptorTable->ServiceTableBase[uCount] += g_uOffset;
}
uOffset = ((ULONG32)KeServiceDescriptorTable.ServiceCounterTableBase - uKernelImageBase);
g_pNewKeServiceDescriptorTable->ServiceCounterTableBase = (PULONG32)(pNewKernelBuffer + uOffset);
uOffset = ((ULONG32)KeServiceDescriptorTable.ParamTableBase - uKernelImageBase);
g_pNewKeServiceDescriptorTable->ParamTableBase = (PCHAR)(pNewKernelBuffer + uOffset);
RtlCopyMemory(g_pNewKeServiceDescriptorTable->ParamTableBase, KeServiceDescriptorTable.ParamTableBase, g_pNewKeServiceDescriptorTable->NumberOfServices);
g_qNewKeServiceDescriptorTable = g_pNewKeServiceDescriptorTable;
}
//过滤函数
ULONG32 FilterFunc(ULONG32 uKeServiceTableBase, ULONG32 uIndex, ULONG32 uOldKiFastCallEntry)
{
if (uKeServiceTableBase == (ULONG32)KeServiceDescriptorTable.ServiceTableBase)
{
if (strstr((PCHAR)PsGetCurrentProcess() + 0x174, "notepad") != 0)
{
return g_qNewKeServiceDescriptorTable->ServiceTableBase[uIndex];
}
}
return uOldKiFastCallEntry;
}
//钩子函数
__declspec(naked)
VOID HookFunc()
{
__asm
{
pushad
pushfd
// mov ebx,dword ptr [edi+eax*4]
push ebx //函数地址
push eax //函数下标
push edi //系统服务表基址
call FilterFunc //内平栈
//50 push eax
//51 push ecx
//52 push edx
//53 push ebx esp + 0x14
//54 push esp
//55 push ebp
//56 push esi
//57 push edi
//push eflag
mov dword ptr ss:[esp + 0x14], eax
popfd
popad
sub esp, ecx
shr ecx, 2
jmp g_uJmpAdress
}
}
//开始加钩子
VOID BeginHook(ULONG32 g_uHookAddress)
{
UCHAR uJmp[5] = { 0 };
uJmp[0] = 0xE9;
ULONG32 uJmpAddress = (ULONG32)HookFunc - g_uHookAddress - 5;
*(PULONG32)&uJmp[1] = uJmpAddress;
Cr0WpOff();
RtlCopyMemory((PVOID)g_uHookAddress, uJmp, 5);
Cr0WpOn();
}
//新的ZwOpenProcess
NTSTATUS NewZwOpenProcess(
_Out_ PHANDLE ProcessHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_opt_ PCLIENT_ID ClientId
)
{
ULONG32 uRetAddress = 0;
// 获取返回地址
__asm
{
pushad;
mov eax, dword ptr ss : [ebp + 0x4];
mov uRetAddress, eax;
popad;
}
//找到Hook点
g_uHookAddress = SearchHookPoint((PULONG32)uRetAddress);
//mov edi,esp
//cmp esi,dword ptr [nt!MmUserProbeAddress (80563134)] g_uJmpAdress = g_uHookAddress + 5;
//开始Hook
BeginHook(g_uHookAddress);
//恢复原来的NtOpenProcess //不恢复将会造成死循环 无止尽执行新的NtOpenProcess
Cr0WpOff();
KeServiceDescriptorTable.ServiceTableBase[122] = g_uOldNtOpenProcessFuncAddress;
Cr0WpOn();
return ((PNewZwOpenProcess)g_uOldNtOpenProcessFuncAddress)(
ProcessHandle, DesiredAccess, ObjectAttributes, ClientId);
}
//Hook入口
VOID HookKiFastCallEntry()
{
Cr0WpOff();
// 保存原来的NewZwOpenProcess
g_uOldNtOpenProcessFuncAddress = KeServiceDescriptorTable.ServiceTableBase[122];
// 设置新的NewZwOpenProcess
KeServiceDescriptorTable.ServiceTableBase[122] = (ULONG32)NewZwOpenProcess;
Cr0WpOn();
// 立即调用ZwOpenProcess跳转到Hook的新的ZwOpenProcess
CallZwOpenProcess();
}