内核重载
思路:
应用层函数要进入内核层一定要通过一个函数来实现,该函数为KiFastCallEntry,所以只需要定位到该函数就可以就可以。
-
得到NtOsKrnl.exe模块的基地址:通过调用ZwQuerySystemInformation函数搜索SystemModuleInformation变量得到模块信息
-
遍历所有的模块比较与目标模块名称是否匹配,如果匹配证明成功
-
将NtOsKrnl模块加载到自己的内存中:调用ZwCreateFile函数打开文件获得文件句柄
-
调用ZwQueryInformationFile获得文件信息中的文件长度
-
根据文件长度调用函数ExAllocate函数动态申请内存,得到内存基地址
-
调用函数ZwReadFile函数将该模块读取到自己的内存中的BufferData位置处
-
在自己的进程中根据原来的NtOsKrnl.exe的地址KernelModule进行修复
-
通过BufferData得到模块的IMAGE_DOS_HEADER和IMAGE_NT_HEADERS。
-
根据PE文件大小动态申请内存得到基地址v5和大小v7
-
将BufferData中的文件头拷贝到v5中,拷贝大小为ImageNtHeaders->OptionalHeader.SizeOfHeaders
-
根据BufferData得到选项头ImageSectionHeaders
-
for循环将所有的节拷贝到v5中
-
对v5进行导入表修复和重定位表修复
-
返回经过修复后的我们内存中的NtOsKrnl模块基地址v5
-
根据得到的自己内存中的NtOsKrnl来修复SSDT系统服务表
-
该SSDT服务表位于重定向表中,所以首先得到重定位表的基地址,遍历整个重定位表。得到重定位表项。
-
判断重定位表项是否为KeServiceDescriptorTable,KeServiceDescriptorTable是x86导出变量,可以直接通过Extern得到
typedef struct _SERVICE_DESCRIPTOR_TABLE { PULONG Unknow0; PULONG Unknow1; ULONG Unknow2; PUCHAR Unknow3; }SERVICE_DESCRIPTOR_TABLE, * PSERVICE_DESCRIPTOR_TABLE; extern PSERVICE_DESCRIPTOR_TABLE KeServiceDescriptorTable;
-
-
然后得到SSDT表的位置后通过偏移计算我们新的SSDT表中的偏移位置
-
根据判断要Hook的函数,将SSDT表中的地址修改为我们自己的Fake函数地址
-
对KiFastCallEntry函数进行Hook,首先定位KiFastCallEntry函数地址,方法是通过读取msr寄存器0x176位置处。
-
得到KiFastCallEntry入口函数后,遍历整个函数,通过硬编码指令搜索
__HookPosition = FindKey("\x2B\xE1\xC1\xE9\x02\x8B\xFC", 7, (PCHAR)KiFastCallEntry, 1000); /* kd> rdmsr 0x176 msr[176] = 00000000`83e450c0 kd> u 00000000`83e450c0 l 50 83e45199 8b570c mov edx,dword ptr [edi+0Ch] 83e4519c 8b3f mov edi,dword ptr [edi] 83e4519e 8a0c10 mov cl,byte ptr [eax+edx] 83e451a1 8b1487 mov edx,dword ptr [edi+eax*4] //KeServiceDescriptorTable->Unknow[eax*4]函数地址 83e451a4 2be1 sub esp,ecx 83e451a6 c1e902 shr ecx,2 8488f879 8bfc mov edi,esp
-
对83e451a4 2be1 sub esp,ecx的位置进行Hook,因为上一步中的edi中是SSDT表基地址,eax中是函数索引
-
执行Hook,改变__HookPosition的第一个字节为e9,后面跟Fake函数与当前位置的偏移差Offset,因为e9为跳转指令,当我们调研该函数的之后,E9指令执行过程是跳转到基地址83e451a4+5个字节+偏移地址。直接跳转到我们的Fake函数处。
-
当结束Hook的时候需要将原来的值拷贝回__HookPosition处。
导入表修复
- 通过PE基地址得到导入表描述的位置.
- for循环遍历导入表中所有的导入模块。
- 通过导入模块名称得到导入模块的基地址ModuleBase(ZwQuerySystemInformation函数搜索参数SystemModuleInformation)
- 得到导入表的OriginalFirstThunk和FirstThunk两个成员
- while循环遍历所有的OriginalFirstThunk,然后通过基地址+OriginalFirstThunk的偏移得到的函数名或函数索引
- 内核模式下好像没有索引导入
- 得到导入函数的名称
- 通过得到的模块基地址ModuleBase根据导入函数名称得到该函数在其导入表中的地址
- 根据函数名和模块基地址得到导出函数地址:遍历导出表三个成员为AddressOfName,AddressOfFunctions,AddressOfNameOrdinals,根据三个成员通过for循环得到在导出表中得到函数地址
- 将得到的函数地址重新写入到FirstThunk中。
VOID FixImportTable(IN PVOID MappingModuleBase)
{
PIMAGE_IMPORT_DESCRIPTOR ImpageImportDescriptor;
ULONG ImpageImportDescriptorLength;
PIMAGE_THUNK_DATA OriginalFirstThunk, FirstThunk;
ImpageImportDescriptor = RtlImageDirectoryEntryToData(MappingModuleBase, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ImpageImportDescriptorLength);
while (ImpageImportDescriptor->OriginalFirstThunk
&& ImpageImportDescriptor->Name)
{
PVOID ModuleBase = NULL;
SIZE_T ModuleSize = 0;
//ntos.exe [hal.dll][1][2][3][4]
//hal.dll [Hook][Hook]
//ntfs.sys
GetKernelModuleInfo((PUCHAR)MappingModuleBase + ImpageImportDescriptor->Name,
&ModuleBase, &ModuleSize);
if (ModuleBase == NULL)
{
break;
}
OriginalFirstThunk = (PIMAGE_THUNK_DATA)((ULONG)MappingModuleBase + ImpageImportDescriptor->OriginalFirstThunk);
FirstThunk = (PIMAGE_THUNK_DATA)((ULONG)MappingModuleBase + ImpageImportDescriptor->FirstThunk);
while (OriginalFirstThunk->u1.Ordinal)
{
PIMAGE_IMPORT_BY_NAME ImageImportByName =
(PIMAGE_IMPORT_BY_NAME)((PUCHAR)MappingModuleBase + OriginalFirstThunk->u1.AddressOfData);
//序号导入
if (IMAGE_SNAP_BY_ORDINAL32(OriginalFirstThunk->u1.Ordinal))
{
//内核中貌似没有序号导出的
//DbgPrint("导入序号:%d", ImageImportByName->Hint);
}
else
{
ANSI_STRING FunctionName;
RtlInitAnsiString(&FunctionName, ImageImportByName->Name);
FirstThunk->u1.Function = (ULONG)MiFindExportedRoutineByName(ModuleBase, &FunctionName);
//DbgPrint("名字:%s, Adress:%08X", ImageImportByName->Name, FirstThunk->u1.Function);
}
OriginalFirstThunk++;
FirstThunk++;
}
ImpageImportDescriptor++;
}
return;
}
PVOID
MiFindExportedRoutineByName(
IN PVOID ModuleBase,
IN PANSI_STRING FunctionName
)
{
USHORT v1;
PULONG AddressOfNames;
PUSHORT AddressOfNameOrdinals;
PULONG v2;
LONG High;
LONG Low;
LONG Middle;
LONG Result;
ULONG ExportLength;
PVOID FunctionAddress;
PIMAGE_EXPORT_DIRECTORY ImageExportDirectory;
ImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(
ModuleBase,
TRUE,
IMAGE_DIRECTORY_ENTRY_EXPORT,
&ExportLength);
if (ImageExportDirectory == NULL) {
return NULL;
}
AddressOfNames = (PULONG)((PCHAR)ModuleBase + (ULONG)ImageExportDirectory->AddressOfNames);
AddressOfNameOrdinals = (PUSHORT)((PCHAR)ModuleBase + (ULONG)ImageExportDirectory->AddressOfNameOrdinals);
Low = 0;
Middle = 0;
High = ImageExportDirectory->NumberOfNames - 1;
while (High >= Low) {
Middle = (Low + High) >> 1;
Result = strcmp(FunctionName->Buffer,
(PCHAR)ModuleBase + AddressOfNames[Middle]);
if (Result < 0) {
High = Middle - 1;
}
else if (Result > 0) {
Low = Middle + 1;
}
else {
break;
}
}
if (High < Low) {
return NULL;
}
v1 = AddressOfNameOrdinals[Middle];
//函数转发器
if ((ULONG)v1 >= ImageExportDirectory->NumberOfFunctions)
{
return NULL;
}
v2 = (PULONG)((PCHAR)ModuleBase + (ULONG)ImageExportDirectory->AddressOfFunctions);
FunctionAddress = (PVOID)((PCHAR)ModuleBase + v2[v1]);
return FunctionAddress;
}
重定位表修复:
-
得到重定位表的位置
-
首先计算重定位表中一共有多少个需要重定位的表项。每一张重定位表的前四个字节是VIrtualAddress,后四个字节是SizeofBlock(块大小),后面跟着的都是两个字节的重定位表项。所以每一张表中需要重定位的表项就是:(SizeofBlock-8)/2
-
for循环所有的重定位表项,2个字节共16位,但是每一页大小最大是0x1000只需要12位表示,所以16位中低12位保存的是真正的重定位地址。前四位表示4字节地址共32位中的高16位需要修复还是低16位需要修复,一般情况下是32位都需要修复。
-
用基地址+重定位表项中的低12位得到的就是真实加载的地址。
-
用真实加载的地址-预加载地址ImageNtHeaders->OptionalHeader.ImageBase得到的就是加载过程中的偏移
-
用我们自己的映像地址+偏移地址得到的就是修复后的地址
VOID FixBaseRelocTable(IN PVOID MappingModuleBase, IN PVOID KernelModuleBase)
{
PIMAGE_BASE_RELOCATION ImageBaseRelocation;
ULONG ImageBaseRelocationLength;
PIMAGE_DOS_HEADER ImageDosHeader = (PIMAGE_DOS_HEADER)MappingModuleBase;
PIMAGE_NT_HEADERS ImageNtHeaders = (PIMAGE_NT_HEADERS)(ImageDosHeader->e_lfanew + (ULONG)MappingModuleBase);
ImageBaseRelocation = RtlImageDirectoryEntryToData(MappingModuleBase,
TRUE, IMAGE_DIRECTORY_ENTRY_BASERELOC, &ImageBaseRelocationLength);
if (NULL == ImageBaseRelocation)
{
return;
}
do
{
ULONG ItemCount;
ULONG i;
USHORT TypeOffset;
ULONG RelocationAddress;
ItemCount = (ImageBaseRelocation->SizeOfBlock - 8) / 2;
for (i = 0; i < ItemCount; i++)
{
TypeOffset = ((PUSHORT)((ULONG)ImageBaseRelocation + 8))[i];
if (TypeOffset >> 12 == IMAGE_REL_BASED_HIGHLOW)
{
RelocationAddress = ImageBaseRelocation->VirtualAddress + (TypeOffset & 0x0FFF) + (ULONG)MappingModuleBase;
if (KernelModuleBase == NULL)
{
*(PULONG)RelocationAddress =
*(PULONG)RelocationAddress + (ULONG)MappingModuleBase - ImageNtHeaders->OptionalHeader.ImageBase;
}
else
{
*(PULONG)RelocationAddress =
*(PULONG)RelocationAddress + (ULONG)KernelModuleBase - ImageNtHeaders->OptionalHeader.ImageBase;
}
}
}
ImageBaseRelocation = (PIMAGE_BASE_RELOCATION)((ULONG)ImageBaseRelocation + ImageBaseRelocation->SizeOfBlock);
} while (ImageBaseRelocation->VirtualAddress); //第一个VirtualAddress可能是0
}
代码:
DriverEntry.h
#pragma once
#include <fltKernel.h>
#include <ntimage.h>
#define WPOFF() \
_asm{cli}\
_asm{mov eax, cr0}\
_asm{and eax, ~0x10000}\
_asm{mov cr0, eax}
#define WPON() \
_asm{mov eax, cr0}\
_asm{or eax, 0x10000}\
_asm{mov cr0, eax}\
_asm{sti}
typedef struct _SYSTEM_SERVICE_DESCRIPTOR_TABLE
{
PULONG_PTR ServiceTableBase; //指针数组
PULONG_PTR ServiceCounterTableBase;
ULONG_PTR NumberOfServices; //多少个函数
PULONG_PTR ParamterTableBase;
} SYSTEM_SERVICE_DESCRIPTOR_TABLE, * PSYSTEM_SERVICE_DESCRIPTOR_TABLE;
extern PSYSTEM_SERVICE_DESCRIPTOR_TABLE KeServiceDescriptorTable;
#define AlignSize(Size, Align) (Size+Align-1)/Align*Align
typedef enum _SYSTEM_INFORMATION_CLASS {
SystemBasicInformation,
SystemProcessorInformation,
SystemPerformanceInformation,
SystemTimeOfDayInformation,
SystemPathInformation,
SystemProcessInformation,
SystemCallCountInformation,
SystemDeviceInformation,
SystemProcessorPerformanceInformation,
SystemFlagsInformation,
SystemCallTimeInformation,
SystemModuleInformation,
SystemLocksInformation,
SystemStackTraceInformation,
SystemPagedPoolInformation,
SystemNonPagedPoolInformation,
SystemHandleInformation,
SystemObjectInformation,
SystemPageFileInformation,
SystemVdmInstemulInformation,
SystemVdmBopInformation,
SystemFileCacheInformation,
SystemPoolTagInformation,
SystemInterruptInformation,
SystemDpcBehaviorInformation,
SystemFullMemoryInformation,
SystemLoadGdiDriverInformation,
SystemUnloadGdiDriverInformation,
SystemTimeAdjustmentInformation,
SystemSummaryMemoryInformation,
SystemNextEventIdInformation,
SystemEventIdsInformation,
SystemCrashDumpInformation,
SystemExceptionInformation,
SystemCrashDumpStateInformation,
SystemKernelDebuggerInformation,
SystemContextSwitchInformation,
SystemRegistryQuotaInformation,
SystemExtendServiceTableInformation,
SystemPrioritySeperation,
SystemPlugPlayBusInformation,
SystemDockInformation,
#if !defined PO_CB_SYSTEM_POWER_POLICY
SystemPowerInformation,
#else
_SystemPowerInformation,
#endif
SystemProcessorSpeedInformation,
SystemCurrentTimeZoneInformation,
SystemLookasideInformation
} SYSTEM_INFORMATION_CLASS;
typedef struct _RTL_PROCESS_MODULE_INFORMATION
{
ULONG Section;
PVOID MappedBase;
PVOID ImageBase;
ULONG ImageSize;
ULONG Flags;
USHORT LoadOrderIndex;
USHORT InitOrderIndex;
USHORT LoadCount;
USHORT OffsetToFileName;
CHAR FullPathName[256];
} RTL_PROCESS_MODULE_INFORMATION, * PRTL_PROCESS_MODULE_INFORMATION;
typedef struct _RTL_PROCESS_MODULES
{
ULONG NumberOfModules;
RTL_PROCESS_MODULE_INFORMATION Modules[1];
} RTL_PROCESS_MODULES, * PRTL_PROCESS_MODULES;
NTSTATUS
NTAPI
ZwQuerySystemInformation(
IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
OUT PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength);
PVOID
NTAPI
RtlImageDirectoryEntryToData(
IN PVOID ModuleBase,
IN BOOLEAN MappedAsImage,
IN USHORT DirectoryEntry,
OUT PULONG DirectoryEntryLength);
extern UCHAR* PsGetProcessImageFileName(PEPROCESS EProcess);
void DriverUnload();
NTSTATUS GetKernelModuleInfo(PCHAR KernelModuleName,
PVOID* KernelModuleBase, SIZE_T* KernelModuleSize);
PVOID LoadLibrary(PCWSTR FileFullPathData, PVOID KernelModuleBase);
PVOID LoadLibraryEx(unsigned char* BufferData, PVOID KernelModuleBase);
VOID FixImportTable(IN PVOID MappingModuleBase);
PVOID
MiFindExportedRoutineByName(
IN PVOID ModuleBase,
IN PANSI_STRING FunctionName
);
VOID FixBaseRelocTable(IN PVOID MappingModuleBase, IN PVOID KernelModuleBase);
PVOID FixKeServiceDescriptorTable(IN PVOID MappingModuleBase, IN PVOID KernelModuleBase);
typedef NTSTATUS(NTAPI* LPFN_TERMINATEPROCESS)(IN HANDLE ProcessHandle, IN NTSTATUS ExitStatus);
NTSTATUS NTAPI FakeNtTerminateProcess(HANDLE ProcessHandle, NTSTATUS ExitStatus);
VOID SetSysEnterHook();
VOID ResetSysEnterHook();
VOID UnHook(PUCHAR HookData, ULONG HookDataLength, PVOID HookPositioin);
ULONG Fake911(ULONG ServiceTableBase, ULONG FunctionIndex, ULONG FunctionAddress);
NTSTATUS
NTAPI
FakeNtTerminateProcess(HANDLE ProcessHandle, NTSTATUS ExitStatus);
ULONG FindKey(PUCHAR KeyValue, ULONG KeyValueLength, PUCHAR BufferData, ULONG BufferLength);
VOID SetHook(ULONG HookPositioin, ULONG HookData);
DriverEntry.c
#include "DriverEntry.h"
PVOID __KernelModuleBase = NULL;
SIZE_T __KernelModuleSize = 0;
PVOID __MappingModuleBase = NULL;
SYSTEM_SERVICE_DESCRIPTOR_TABLE __MappingKeServiceDescriptorTable; //自己的Ssdt
LPFN_TERMINATEPROCESS __OldNtTerminateProcess = NULL; //
int __HookPosition = 0;
VOID __declspec(naked) FakeKiFastCallEntry()
{
_asm
{
pushad //PUSHAD指令压入32位寄存器,其入栈顺序是:EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI
pushfd
push edx //原函数地址
push eax //索引
push edi //SSDT->Base
call Fake911
//再返回前修改堆栈里的数据
/*
pushfd esp
edi
esi
ebp
esp
ebx
edx ---->函数地址
ecx
eax
*/
mov[esp + 0x18], eax
popfd
popad
sub esp, ecx
shr ecx, 2
jmp __HookPosition
}
}
//bp HookKiFastCall!DriverEntry
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegisterPath)
{
NTSTATUS Status = STATUS_SUCCESS;
PDEVICE_OBJECT DeviceObject = NULL;
DbgPrint("DriverEntry()\r\n");
DriverObject->DriverUnload = DriverUnload;
GetKernelModuleInfo("ntoskrnl.exe", &__KernelModuleBase, &__KernelModuleSize);
if (NULL != __KernelModuleBase)
{
__MappingModuleBase = LoadLibrary(L"\\??\\C:\\windows\\system32\\ntoskrnl.exe", __KernelModuleBase);
}
else
{
GetKernelModuleInfo("ntkrnlpa.exe", &__KernelModuleBase, &__KernelModuleSize);
__MappingModuleBase = LoadLibrary(L"\\??\\C:\\windows\\system32\\ntkrnlpa.exe", __KernelModuleBase);
}
FixKeServiceDescriptorTable(__MappingModuleBase, __KernelModuleBase);
SetSysEnterHook(); //KiFastCall
return Status;
}
NTSTATUS GetKernelModuleInfo(PCHAR KernelModuleName,
PVOID* KernelModuleBase, SIZE_T* KernelModuleSize)
{
PVOID BufferData = NULL;
ULONG ReturnLength = 0;
ULONG i;
PRTL_PROCESS_MODULES v1 = NULL;
if (STATUS_INFO_LENGTH_MISMATCH == ZwQuerySystemInformation(SystemModuleInformation, 0, 0, &ReturnLength))
{
BufferData = ExAllocatePool(PagedPool, ReturnLength);
if (BufferData)
{
if (!NT_SUCCESS(ZwQuerySystemInformation(SystemModuleInformation, BufferData, ReturnLength, 0)))
{
ExFreePool(BufferData);
BufferData = NULL;
return STATUS_UNSUCCESSFUL;
}
}
else
{
return STATUS_UNSUCCESSFUL;
}
}
else
{
return STATUS_UNSUCCESSFUL;
}
v1 = (PRTL_PROCESS_MODULES)BufferData;
for (i = 0; i < v1->NumberOfModules; i++)
{
_strlwr(KernelModuleName); //大小写转换
_strlwr(v1->Modules[i].FullPathName);
if (strstr(v1->Modules[i].FullPathName, KernelModuleName))
{
*KernelModuleBase = v1->Modules[i].ImageBase;
*KernelModuleSize = v1->Modules[i].ImageSize;
ExFreePool(BufferData);
return STATUS_SUCCESS;
}
}
ExFreePool(BufferData);
return STATUS_UNSUCCESSFUL;
}
PVOID LoadLibrary(PCWSTR FileFullPathData, PVOID KernelModuleBase)
{
NTSTATUS Status = STATUS_UNSUCCESSFUL;
IO_STATUS_BLOCK IoStatusBlock;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING v1;
HANDLE FileHandle = NULL;
FILE_STANDARD_INFORMATION FileStandardInfo;
PVOID BufferData, MappingModuleBase;
LARGE_INTEGER ReturnLength = { 0 };
RtlInitUnicodeString(&v1, FileFullPathData);
InitializeObjectAttributes(&ObjectAttributes, &v1, OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = ZwCreateFile(&FileHandle, FILE_READ_DATA, &ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, \
FILE_SHARE_READ, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
if (!NT_SUCCESS(Status))
{
DbgPrint("打开文件失败%ws", FileFullPathData);
ZwClose(FileHandle);
return NULL;
}
//通过文件句柄获得文件长度
Status = ZwQueryInformationFile(FileHandle, &IoStatusBlock, &FileStandardInfo, sizeof(FILE_STANDARD_INFORMATION), \
FileStandardInformation);
if (!NT_SUCCESS(Status))
{
DbgPrint("查询文件信息失败%ws", FileFullPathData);
ZwClose(FileHandle);
return NULL;
}
BufferData = ExAllocatePool(PagedPool, FileStandardInfo.EndOfFile.LowPart);
if (NULL == BufferData)
{
DbgPrint("分配文件内存失败%ws", FileFullPathData);
ZwClose(FileHandle);
return NULL;
}
Status = ZwReadFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, BufferData, FileStandardInfo.EndOfFile.LowPart,
&ReturnLength, NULL);
if (!NT_SUCCESS(Status))
{
DbgPrint("读取文件到内存失败%ws", FileFullPathData);
ExFreePool(BufferData);
ZwClose(FileHandle);
return NULL;
}
ZwClose(FileHandle);
MappingModuleBase = LoadLibraryEx(BufferData, KernelModuleBase);
if (NULL == MappingModuleBase)
{
ExFreePool(BufferData);
return NULL;
}
ExFreePool(BufferData);
return MappingModuleBase;
}
PVOID LoadLibraryEx(unsigned char* BufferData, PVOID KernelModuleBase)
{
PIMAGE_DOS_HEADER ImageDosHeader;
PIMAGE_NT_HEADERS ImageNtHeaders;
ULONG v7;
unsigned char* v5;
PIMAGE_SECTION_HEADER ImageSectionHeader;
int i;
ImageDosHeader = (PIMAGE_DOS_HEADER)BufferData;
if (ImageDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
{
return NULL;
}
ImageNtHeaders = (PIMAGE_NT_HEADERS)(BufferData + ImageDosHeader->e_lfanew);
if (ImageNtHeaders->Signature != IMAGE_NT_SIGNATURE)
{
return NULL;
}
v7 = AlignSize(ImageNtHeaders->OptionalHeader.SizeOfImage, ImageNtHeaders->OptionalHeader.SectionAlignment);
v5 = ExAllocatePool(NonPagedPool, v7);
if (NULL == v5)
{
return NULL;
}
RtlZeroMemory(v5, v7);
RtlCopyMemory(v5, BufferData, ImageNtHeaders->OptionalHeader.SizeOfHeaders); //拷贝所有头部
ImageSectionHeader = (PIMAGE_SECTION_HEADER)((ULONG)ImageNtHeaders + sizeof(ImageNtHeaders->Signature) + \
sizeof(ImageNtHeaders->FileHeader) + ImageNtHeaders->FileHeader.SizeOfOptionalHeader);
for (i = 0; i < ImageNtHeaders->FileHeader.NumberOfSections; i++)
{
RtlCopyMemory(v5 + ImageSectionHeader[i].VirtualAddress, \
BufferData + ImageSectionHeader[i].PointerToRawData, ImageSectionHeader[i].Misc.VirtualSize); //
}
FixImportTable(v5);
FixBaseRelocTable(v5, KernelModuleBase);
return v5;
}
VOID FixImportTable(IN PVOID MappingModuleBase)
{
PIMAGE_IMPORT_DESCRIPTOR ImpageImportDescriptor;
ULONG ImpageImportDescriptorLength;
PIMAGE_THUNK_DATA OriginalFirstThunk, FirstThunk;
ImpageImportDescriptor = RtlImageDirectoryEntryToData(MappingModuleBase, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ImpageImportDescriptorLength);
while (ImpageImportDescriptor->OriginalFirstThunk
&& ImpageImportDescriptor->Name)
{
PVOID ModuleBase = NULL;
SIZE_T ModuleSize = 0;
//
//
//ntos.exe [hal.dll][1][2][3][4]
//hal.dll [Hook][Hook]
//ntfs.sys
GetKernelModuleInfo((PUCHAR)MappingModuleBase + ImpageImportDescriptor->Name,
&ModuleBase, &ModuleSize);
if (ModuleBase == NULL)
{
break;
}
OriginalFirstThunk = (PIMAGE_THUNK_DATA)((ULONG)MappingModuleBase + ImpageImportDescriptor->OriginalFirstThunk);
FirstThunk = (PIMAGE_THUNK_DATA)((ULONG)MappingModuleBase + ImpageImportDescriptor->FirstThunk);
while (OriginalFirstThunk->u1.Ordinal)
{
PIMAGE_IMPORT_BY_NAME ImageImportByName =
(PIMAGE_IMPORT_BY_NAME)((PUCHAR)MappingModuleBase + OriginalFirstThunk->u1.AddressOfData);
//序号导入
if (IMAGE_SNAP_BY_ORDINAL32(OriginalFirstThunk->u1.Ordinal))
{
//内核中貌似没有序号导出的
//DbgPrint("导入序号:%d", ImageImportByName->Hint);
}
else
{
ANSI_STRING FunctionName;
RtlInitAnsiString(&FunctionName, ImageImportByName->Name);
FirstThunk->u1.Function = (ULONG)MiFindExportedRoutineByName(ModuleBase, &FunctionName);
//DbgPrint("名字:%s, Adress:%08X", ImageImportByName->Name, FirstThunk->u1.Function);
}
OriginalFirstThunk++;
FirstThunk++;
}
ImpageImportDescriptor++;
}
return;
}
PVOID
MiFindExportedRoutineByName(
IN PVOID ModuleBase,
IN PANSI_STRING FunctionName
)
{
USHORT v1;
PULONG AddressOfNames;
PUSHORT AddressOfNameOrdinals;
PULONG v2;
LONG High;
LONG Low;
LONG Middle;
LONG Result;
ULONG ExportLength;
PVOID FunctionAddress;
PIMAGE_EXPORT_DIRECTORY ImageExportDirectory;
ImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(
ModuleBase,
TRUE,
IMAGE_DIRECTORY_ENTRY_EXPORT,
&ExportLength);
if (ImageExportDirectory == NULL) {
return NULL;
}
AddressOfNames = (PULONG)((PCHAR)ModuleBase + (ULONG)ImageExportDirectory->AddressOfNames);
AddressOfNameOrdinals = (PUSHORT)((PCHAR)ModuleBase + (ULONG)ImageExportDirectory->AddressOfNameOrdinals);
Low = 0;
Middle = 0;
High = ImageExportDirectory->NumberOfNames - 1;
while (High >= Low) {
Middle = (Low + High) >> 1;
Result = strcmp(FunctionName->Buffer,
(PCHAR)ModuleBase + AddressOfNames[Middle]);
if (Result < 0) {
High = Middle - 1;
}
else if (Result > 0) {
Low = Middle + 1;
}
else {
break;
}
}
if (High < Low) {
return NULL;
}
v1 = AddressOfNameOrdinals[Middle];
//函数转发器
if ((ULONG)v1 >= ImageExportDirectory->NumberOfFunctions)
{
return NULL;
}
v2 = (PULONG)((PCHAR)ModuleBase + (ULONG)ImageExportDirectory->AddressOfFunctions);
FunctionAddress = (PVOID)((PCHAR)ModuleBase + v2[v1]);
return FunctionAddress;
}
VOID FixBaseRelocTable(IN PVOID MappingModuleBase, IN PVOID KernelModuleBase)
{
PIMAGE_BASE_RELOCATION ImageBaseRelocation;
ULONG ImageBaseRelocationLength;
PIMAGE_DOS_HEADER ImageDosHeader = (PIMAGE_DOS_HEADER)MappingModuleBase;
PIMAGE_NT_HEADERS ImageNtHeaders = (PIMAGE_NT_HEADERS)(ImageDosHeader->e_lfanew + (ULONG)MappingModuleBase);
ImageBaseRelocation = RtlImageDirectoryEntryToData(MappingModuleBase,
TRUE, IMAGE_DIRECTORY_ENTRY_BASERELOC, &ImageBaseRelocationLength);
if (NULL == ImageBaseRelocation)
{
return;
}
do
{
ULONG ItemCount;
ULONG i;
USHORT TypeOffset;
ULONG RelocationAddress;
ItemCount = (ImageBaseRelocation->SizeOfBlock - 8) / 2;
for (i = 0; i < ItemCount; i++)
{
TypeOffset = ((PUSHORT)((ULONG)ImageBaseRelocation + 8))[i];
if (TypeOffset >> 12 == IMAGE_REL_BASED_HIGHLOW)
{
RelocationAddress = ImageBaseRelocation->VirtualAddress + (TypeOffset & 0x0FFF) + (ULONG)MappingModuleBase;
if (KernelModuleBase == NULL)
{
*(PULONG)RelocationAddress =
*(PULONG)RelocationAddress + (ULONG)MappingModuleBase - ImageNtHeaders->OptionalHeader.ImageBase;
}
else
{
*(PULONG)RelocationAddress =
*(PULONG)RelocationAddress + (ULONG)KernelModuleBase - ImageNtHeaders->OptionalHeader.ImageBase;
}
}
}
ImageBaseRelocation = (PIMAGE_BASE_RELOCATION)((ULONG)ImageBaseRelocation + ImageBaseRelocation->SizeOfBlock);
} while (ImageBaseRelocation->VirtualAddress); //第一个VirtualAddress可能是0
}
PVOID FixKeServiceDescriptorTable(IN PVOID MappingModuleBase, IN PVOID KernelModuleBase)
{
PIMAGE_BASE_RELOCATION ImageBaseRelocation;
ULONG ImageBaseRelocationLength;
PIMAGE_DOS_HEADER ImageDosHeader = (PIMAGE_DOS_HEADER)MappingModuleBase;
PIMAGE_NT_HEADERS ImageNtHeaders = (PIMAGE_NT_HEADERS)(ImageDosHeader->e_lfanew + (ULONG)MappingModuleBase);
ImageBaseRelocation = RtlImageDirectoryEntryToData(MappingModuleBase, TRUE, IMAGE_DIRECTORY_ENTRY_BASERELOC, &ImageBaseRelocationLength);
if (NULL == ImageBaseRelocation)
{
return NULL;
}
do
{
ULONG ItemCount;
ULONG i;
USHORT TypeOffset;
ULONG RelocationAddress;
ItemCount = (ImageBaseRelocation->SizeOfBlock - 8) / 2;
for (i = 0; i < ItemCount; i++)
{
TypeOffset = ((PUSHORT)((ULONG)ImageBaseRelocation + 8))[i];
if (TypeOffset >> 12 == IMAGE_REL_BASED_HIGHLOW)
{
RelocationAddress = ImageBaseRelocation->VirtualAddress + (TypeOffset & 0x0FFF) + (ULONG)MappingModuleBase;
if (*(PULONG)RelocationAddress == (ULONG)(KeServiceDescriptorTable))
{
// 可以使用IDA 导出变量KeServiceDescriptorTable 交叉引用
// mov ds:_KeServiceDescriptorTable, offset _KiServiceTable
if (*(PUSHORT)(RelocationAddress - 2) == 0x05C7)
{
ULONG j;
PULONG v10; //MappingModuleBase 中的 KeServiceDescriptorTable
v10 =
(PULONG)(*(PULONG)(RelocationAddress + 4) - (ULONG)KernelModuleBase + (ULONG)MappingModuleBase);
//执行到该处
/*
v10 = 0x8addd43c
0: kd> dd 0x8addd43c
8addd43c 84a8bfbf 848d3855 84a1bd47 84837897
8addd44c 84a8d895 84910112 84afe0d7 84afe120
8addd45c 84a10563 84b179d4 84b18c2d 84a06d3b
8addd46c 84a97ed3 84af0da3 84a43cc7 84a138ab
8addd47c 849a99e3 84ae2c88 849fa28c 84a3ccbc
8addd48c 84a89191 849ea300 84a8859e 84a07db2
8addd49c 84a9995a 84a0a435 84a9973a 84a91e92
8addd4ac 84a1c2cf 84adda25 84a8f25f 84a99b8c
0: kd> u 84a8bfbf
nt!NtAcceptConnectPort:
84a8bfbf 8bff mov edi,edi
84a8bfc1 55 push ebp
所以好像不需要下面的修正了
*/
for (j = 0; j < KeServiceDescriptorTable->NumberOfServices; j++)
{
v10[j] = (ULONG)(KeServiceDescriptorTable->ServiceTableBase[j]) - \
(ULONG)KernelModuleBase + (ULONG)MappingModuleBase; //这里如果内核已经被Hook 就有问题了
if (j == 370)
{
__OldNtTerminateProcess = v10[j];
v10[j] = (ULONG32)FakeNtTerminateProcess;
}
}
__MappingKeServiceDescriptorTable.ServiceTableBase = v10;
__MappingKeServiceDescriptorTable.ServiceCounterTableBase = KeServiceDescriptorTable->ServiceCounterTableBase;
__MappingKeServiceDescriptorTable.NumberOfServices = KeServiceDescriptorTable->NumberOfServices;
__MappingKeServiceDescriptorTable.ParamterTableBase = KeServiceDescriptorTable->ParamterTableBase;
return NULL;
}
}
}
}
ImageBaseRelocation = (PIMAGE_BASE_RELOCATION)((ULONG)ImageBaseRelocation + ImageBaseRelocation->SizeOfBlock);
} while (ImageBaseRelocation->VirtualAddress);
return NULL;
}
VOID SetSysEnterHook()
{
LONG KiFastCallEntry;
_asm
{
mov ecx, 0x176
rdmsr
mov KiFastCallEntry, eax
}
__HookPosition = FindKey("\x2B\xE1\xC1\xE9\x02\x8B\xFC", 7, (PCHAR)KiFastCallEntry, 1000);
/*
kd> rdmsr 0x176
msr[176] = 00000000`83e450c0
kd> u 00000000`83e450c0 l 50
83e45199 8b570c mov edx,dword ptr [edi+0Ch]
83e4519c 8b3f mov edi,dword ptr [edi]
83e4519e 8a0c10 mov cl,byte ptr [eax+edx]
83e451a1 8b1487 mov edx,dword ptr [edi+eax*4] //KeServiceDescriptorTable->Unknow[eax*4]函数地址
83e451a4 2be1 sub esp,ecx
83e451a6 c1e902 shr ecx,2
8488f879 8bfc mov edi,esp
*/
if (-1 == __HookPosition)
return;
SetHook(__HookPosition, (ULONG)(FakeKiFastCallEntry));
__HookPosition += 5;
}
VOID ResetSysEnterHook()
{
UnHook((PUCHAR)"\x2B\xE1\xC1\xE9\x02\x8B\xFC", 7, (PVOID)(__HookPosition - 5));
if (__MappingModuleBase != NULL)
{
ExFreePool(__MappingModuleBase);
__MappingModuleBase = NULL;
}
}
VOID UnHook(PUCHAR HookData, ULONG HookDataLength, PVOID HookPositioin)
{
WPOFF();
memcpy(HookPositioin, HookData, HookDataLength);
WPON();
}
VOID SetHook(ULONG HookPositioin, ULONG HookData)
{
WPOFF();
*(PUCHAR)HookPositioin = 0xE9;
*(PULONG)(HookPositioin + 1) = HookData - HookPositioin - 5;
WPON();
}
ULONG Fake911(ULONG ServiceTableBase, ULONG FunctionIndex, ULONG FunctionAddress)
{
if (ServiceTableBase == (ULONG)KeServiceDescriptorTable->ServiceTableBase)
{
return __MappingKeServiceDescriptorTable.ServiceTableBase[FunctionIndex];
}
return FunctionAddress;
}
NTSTATUS
NTAPI
FakeNtTerminateProcess(HANDLE ProcessHandle, NTSTATUS ExitStatus)
{
PEPROCESS EProcess;
NTSTATUS Status = ObReferenceObjectByHandle(ProcessHandle, 0, *PsProcessType, KernelMode, &EProcess, NULL);
if (NT_SUCCESS(Status))
{
ObDereferenceObject(EProcess);
if (!_stricmp(PsGetProcessImageFileName(EProcess), "calc.exe"))
return STATUS_ACCESS_DENIED;
}
return __OldNtTerminateProcess(ProcessHandle, ExitStatus);
}
ULONG FindKey(PUCHAR KeyValue, ULONG KeyValueLength, PUCHAR BufferData, ULONG BufferLength)
{
UCHAR v1[0x100];
ULONG i = 0;
PUCHAR Travel = BufferData;
if (BufferLength <= 0)
return -1;
memset(v1, KeyValueLength + 1, 0x100);
for (i = 0; i < KeyValueLength; i++)
{
v1[KeyValue[i]] = (UCHAR)(KeyValueLength - i);
}
while (Travel + KeyValueLength <= BufferData + BufferLength)
{
UCHAR* m = KeyValue, * n = Travel;
ULONG i = 0;
for (i = 0; i < KeyValueLength; i++)
{
if (m[i] != n[i])
break;
}
if (i == KeyValueLength)
return (ULONG)Travel;
if (Travel + KeyValueLength == BufferData + BufferLength)
return -1;
Travel += v1[Travel[KeyValueLength]];
}
return -1;
}
VOID DriverUnload(PDRIVER_OBJECT DriverObject)
{
DbgPrint("DriverUnload()\r\n");
ResetSysEnterHook();
}