-
-
[求助]内核重载之KiFastCalEntry Hook
-
发表于: 2020-9-16 22:43 3001
-
#include<ntddk.h>
#include"PE.h"
#include"LDR.h"
UCHAR Buf = NULL;
UCHAR Mem1 = NULL;
DWORD OldImageBase;
DWORD SizeOfHeaders;
DWORD SetionNumber;
DWORD SizeofImage ;
NTSTATUS NTAPI GetMoudleAddress(PUNICODE_STRING);
NTSTATUS NTAPI GetProcessAddress(DWORD , char*);
PDRIVER_OBJECT CurrentObject = NULL;
DWORD HookAddress = 0x8053e621;
DWORD RetAddress;
DWORD NewSeriverBase = 0;
char HooKData[5] = { 0 };
extern PKSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable;
//extern __declspec(dllimport) PKSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable;
PKSERVICE_TABLE_DESCRIPTOR g_NewKernelSeriveDescriptorTaber = NULL;
void Cr0Close();
void Cr0Off();
void MemFree() {
ExFreePool(Buf);
ExFreePool(Mem1);
DbgPrint("内存释放成功!\n");
}
void UnLoadHook() {
Cr0Off();
RtlCopyMemory((void*)HookAddress, HooKData, 5);
Cr0Close();
DbgPrint("钩子卸载成功!\n");
}
NTSTATUS DriverUnload(PDRIVER_OBJECT Pobject) {
DbgPrint("驱动卸载成功!\n");
MemFree();
UnLoadHook();
return STATUS_SUCCESS;
}
NTSTATUS GetFileSize(PUNICODE_STRING KernelPathName) {
DWORD Temp = 0;
PE_HEADER pE = { 0 };
HANDLE hFile=NULL;
NTSTATUS status = 0;
OBJECT_ATTRIBUTES Object;
IO_STATUS_BLOCK Io_Status;
LARGE_INTEGER fileOffset = { 0 };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | InitializeObjectAttributes(& Object , KernelPathName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); status = ZwCreateFile(&hFile, GENERIC_READ, & Object , &Io_Status, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_NON_DIRECTORY_FILE, NULL, 0 ); if (!NT_SUCCESS(status)) { DbgPrint( "ZwCreateFile 函数打开文件失败!\n" ); return 0 ; } Buf = (UCHAR * )ExAllocatePool(PagedPool, 0x1000 ); / / 开辟分页内存 0x1000 会被交换到文件中 if (NULL = = Buf) { DbgPrint( "开辟一个页的分页内存失败\n" ); return - 1 ; } status = ZwReadFile(hFile, NULL, NULL, NULL, &Io_Status, Buf, 0x1000 ,&fileOffset, NULL); if (!NT_SUCCESS(status)) { DbgPrint( "ZwReadFile读取文件内容DosHeader失败 status=%d\n" , status); return - 2 ; } pE.DosHeader = (PIMAGE_DOS_HEADER)Buf; pE.NtHeaders.FileHeader = (PIMAGE_FILE_HEADER)((DWORD)pE.DosHeader + (DWORD)pE.DosHeader - >e_lfanew + 4 ); pE.NtHeaders.OptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pE.NtHeaders.FileHeader + sizeof(IMAGE_FILE_HEADER)); pE.SectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pE.NtHeaders.OptionalHeader + pE.NtHeaders.FileHeader - >SizeOfOptionalHeader); SizeofImage = pE.NtHeaders.OptionalHeader - >SizeOfImage; / / 拉伸后的大小 OldImageBase = pE.NtHeaders.OptionalHeader - >ImageBase; / / ntkrnlpa.exe的imagebase SizeOfHeaders = pE.NtHeaders.OptionalHeader - >SizeOfHeaders; / / 获得PE头大小 SetionNumber = pE.NtHeaders.FileHeader - >NumberOfSections; / / ntkrnlpa.exe文件节的数量 0x19 个 DbgPrint( "%p SizeofImage=%p ImageBase=%p\n SizeOfHeaders=%p SetionNumber=%p\n" , * ((DWORD * )Buf), SizeofImage, OldImageBase, SizeOfHeaders, SetionNumber); Mem1 = (UCHAR * )(UCHAR * )ExAllocatePool(PagedPool, SizeofImage); if (NULL = = Mem1) { DbgPrint( "ExAllocatePool函数开辟内核文件内存 sizeofimage大小内存失败!\n" ); return - 3 ; } |
#if 1
DbgPrint("Buf=%p Mem1=%p SizeOfHeaders=%p\n", Buf, Mem1,SizeOfHeaders);
memset(Mem1,0, SizeofImage);
memcpy(Mem1, Buf, SizeOfHeaders); //CPY 复制PE头
for (Temp = 0; Temp < SetionNumber; Temp++) {
fileOffset.QuadPart = pE.SectionHeader->PointerToRawData; //这个参数决定了ReadFile读取文件内容从哪里开始 该节的FOA
//DbgPrint("Temp=%p %p %p\n", Temp + 1, pE.SectionHeader->VirtualAddress,pE.SectionHeader->PointerToRawData);
//DbgPrint("%p %p\n", (VOID)((DWORD)Mem1 + pE.SectionHeader->VirtualAddress), pE.SectionHeader->Misc.VirtualSize);
status = ZwReadFile(hFile, NULL, NULL, NULL, &Io_Status, (VOID)((DWORD)Mem1+ pE.SectionHeader->VirtualAddress), pE.SectionHeader->Misc.VirtualSize, &fileOffset, NULL);
if (!NT_SUCCESS(status)) {
DbgPrint("拉伸FileBuf到ImagaeBuf失败 status=%d\n", status);
return -2;
}
pE.SectionHeader++;
}
#endif
1 2 3 | DbgPrint( "拉伸成功!\n" ); ZwClose(hFile); return 1 ; |
}
NTSTATUS RestoreReLcationTaber() { //修改内核文件重定位
DWORD i;
WORD Data;
DWORD Item;
PE_HEADER pE = { 0 };
PIMAGE_BASE_RELOCATION Reloction;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | pE.DosHeader = (PIMAGE_DOS_HEADER)Mem1; pE.NtHeaders.FileHeader = (PIMAGE_FILE_HEADER)((DWORD)pE.DosHeader + (DWORD)pE.DosHeader - >e_lfanew + 4 ); / / e_lfarlc写错找到 2 个小时bug pE.NtHeaders.OptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pE.NtHeaders.FileHeader + sizeof(IMAGE_FILE_HEADER)); pE.SectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pE.NtHeaders.OptionalHeader + pE.NtHeaders.FileHeader - >SizeOfOptionalHeader); DbgPrint( "%p " ,pE.NtHeaders.OptionalHeader - >Magic); DbgPrint( "OPtion=%p\n" , pE.NtHeaders.FileHeader - >SizeOfOptionalHeader); DbgPrint( "%p %p \n%p %p\n" , pE.DosHeader, pE.NtHeaders.FileHeader, pE.NtHeaders.OptionalHeader, pE.SectionHeader); if (pE.NtHeaders.OptionalHeader - >DataDirectory[ 5 ].VirtualAddress) { DbgPrint( "存在重定位表 %p Size=%p!\n" , pE.NtHeaders.OptionalHeader - >DataDirectory[ 5 ].VirtualAddress, pE.NtHeaders.OptionalHeader - >DataDirectory[ 5 ].Size); Reloction = (PIMAGE_BASE_RELOCATION)((DWORD)Mem1 + (DWORD)pE.NtHeaders.OptionalHeader - >DataDirectory[ 5 ].VirtualAddress); / / 指向重定位表 } else { DbgPrint( "不存在重定位表 加载内核重载失败\n" ); return 0 ; } pE.NtHeaders.OptionalHeader - >ImageBase = (DWORD)Mem1; / / 修改IMAGEBASE |
#if 1
//DbgPrint("Reloction->VirtualAddr=%p SizeofBloc=%p\n", Reloction->VirtualAddress, Reloction->SizeOfBlock);
while (Reloction->VirtualAddress||Reloction->SizeOfBlock) {
Data = (WORD)((DWORD)Reloction + 8);
//DbgPrint("Reloction->VirtualAddr=%p SizeofBloc=%p\n", Reloction->VirtualAddress, Reloction->SizeOfBlock);
for (i = 0; i < (Reloction->SizeOfBlock - 8) / 2; i++) {
if ((Data[i] & 0xF000) == 0x3000) {
Item = (DWORD)((DWORD)Mem1 + Reloction->VirtualAddress + (Data[i] & 0x0FFF)); //修复重定位表
//DbgPrint("%p Size=%p\n ", Reloction->VirtualAddress, Reloction->SizeOfBlock);
Item = Item + (DWORD)Mem1 - (DWORD)OldImageBase; //修改重定位
1 2 3 4 | } } Reloction = (PIMAGE_BASE_RELOCATION)((DWORD)Reloction + Reloction - >SizeOfBlock); } |
#endif
DbgPrint("修复重定位成功\n");
return 1;
}
NTSTATUS NTAPI GetProcessAddress(DWORD Base, char FuntionName) {
DWORD i = 0;
DWORD FuntionNumber = 0;
DWORD FuntionAddress;
DWORD FuntionName1;
WORD IndexTaber;
char PeName ;
char FuntionName2 = NULL;
PE_HEADER pE = { 0 };
char Mz[3] = { 0 };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | PIMAGE_EXPORT_DIRECTORY ExPort_Taber = NULL; pE.DosHeader = (PIMAGE_DOS_HEADER)Base; pE.NtHeaders.FileHeader = (PIMAGE_FILE_HEADER)((DWORD)pE.DosHeader + (DWORD)pE.DosHeader - >e_lfanew + 4 ); / / e_lfarlc写错找到 2 个小时bug pE.NtHeaders.OptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pE.NtHeaders.FileHeader + sizeof(IMAGE_FILE_HEADER)); if (pE.NtHeaders.OptionalHeader - >DataDirectory[ 0 ].VirtualAddress) { / / DbgPrint( "导出表 RVA=%p Size=%p\n" , pE.NtHeaders.OptionalHeader - >DataDirectory[ 0 ].VirtualAddress, pE.NtHeaders.OptionalHeader - >DataDirectory[ 0 ].Size); ExPort_Taber = (PIMAGE_EXPORT_DIRECTORY)((DWORD)Base + pE.NtHeaders.OptionalHeader - >DataDirectory[ 0 ].VirtualAddress); } else { DbgPrint( "没有找到导出表!\n" ); return 0 ; } PeName = (char * )(Base + ExPort_Taber - >Name); / / DbgPrint( "PENAME=%s\n" , PeName); / / DbgPrint( "导出表OK %p %p %p!\n" , Base,PeName, ExPort_Taber - >Name); / / DbgPrint( "到处函数的起始序号%d 导出函数的个数=%d 按照函数名导出的函数个数=%d\n" , ExPort_Taber - >Base, ExPort_Taber - >NumberOfFunctions, ExPort_Taber - >NumberOfNames); FuntionNumber = ExPort_Taber - >NumberOfNames; / / 按照函数名导处函数的个数 FuntionAddress = (DWORD * )(Base + ExPort_Taber - >AddressOfFunctions); / / 指向函数地址表 FuntionName1 = (DWORD * )(Base + ExPort_Taber - >AddressOfNames); / / 指向函数名称表 IndexTaber = (WORD * )(Base + ExPort_Taber - >AddressOfNameOrdinals); / / 指向函数序号表 for (i = 0 ; i < FuntionNumber; i + + ) { / / 函数名表项对应的序号表只是函数地址表的索引 FuntionName2 = (char * )(Base + * FuntionName1); if ( 0 = = strcmp(FuntionName2, FuntionName)) { return FuntionAddress[IndexTaber[i]] + Base; } / / DbgPrint( "%d %s\n" , i + 1 , FuntionName2); FuntionName1 + + ; } return 0 ; |
}
NTSTATUS NTAPI GetMoudleAddress(PUNICODE_STRING DLLName) {
PLDR_DATA_TABLE_ENTRY Moude= (PLDR_DATA_TABLE_ENTRY )CurrentObject->DriverSection;
PLIST_ENTRY Flag = &(Moude->InLoadOrderLinks);
1 2 3 4 5 6 7 8 9 10 11 12 | while (Moude - >InLoadOrderLinks.Flink) { if ( 0 = = RtlCompareUnicodeString(DLLName,&Moude - >BaseDllName, TRUE)) { / / DbgPrint( "DLLNAME %wZ DLLBase=%p\n" , &Moude - >BaseDllName, Moude - >DllBase); return (DWORD)Moude - >DllBase; } / / DbgPrint( "DLLNAME %wZ\n" , &Moude - >BaseDllName); Moude = (PLDR_DATA_TABLE_ENTRY)Moude - >InLoadOrderLinks.Flink; if (&(Moude - >InLoadOrderLinks) = = Flag) { break ; } } return 0 ; |
}
NTSTATUS RestoreIATTaber() {
DWORD i = 0;
DWORD ImageBase = 0;
NTSTATUS status = 0;
char DllName ;
char FuintionName1;
char FuintionName2;
DWORD INT = NULL;
DWORD* IAT = NULL;
PE_HEADER pE = { 0 };
ANSI_STRING Transition;
ANSI_STRING Transition1;
UNICODE_STRING Unicode_String;
UNICODE_STRING Unicode_DLLName;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | PIMAGE_BASE_RELOCATION Reloction; PIMAGE_IMPORT_DESCRIPTOR ImPort_Taber = NULL; pE.DosHeader = (PIMAGE_DOS_HEADER)Mem1; pE.NtHeaders.FileHeader = (PIMAGE_FILE_HEADER)((DWORD)pE.DosHeader + (DWORD)pE.DosHeader - >e_lfanew + 4 ); / / e_lfarlc写错找到 2 个小时bug pE.NtHeaders.OptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pE.NtHeaders.FileHeader + sizeof(IMAGE_FILE_HEADER)); / / pE.SectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pE.NtHeaders.OptionalHeader + pE.NtHeaders.FileHeader - >SizeOfOptionalHeader); if (pE.NtHeaders.OptionalHeader - >DataDirectory[ 1 ].VirtualAddress) { / / DbgPrint( "存在导入表! RVA=%p Size=%p\n" , pE.NtHeaders.OptionalHeader - >DataDirectory[ 1 ].VirtualAddress, pE.NtHeaders.OptionalHeader - >DataDirectory[ 1 ].Size); ImPort_Taber = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)Mem1 + pE.NtHeaders.OptionalHeader - >DataDirectory[ 1 ].VirtualAddress); } else { DbgPrint( "获得导入表失败!\n" ); return 0 ; } / * 经过验证得到了经验到PE文件没有加载到内存中的时候, INT 和IAT项指向的都是函数名的RVA结构 OK * / while (ImPort_Taber - >OriginalFirstThunk&&ImPort_Taber - >FirstThunk) { DWORD n = 0 ; DllName = (char * )((DWORD)Mem1 + ImPort_Taber - >Name); INT = (DWORD * )((DWORD)Mem1 + ImPort_Taber - >OriginalFirstThunk); / / ( INT 函数名称表) IAT = (DWORD * )((DWORD)Mem1 + ImPort_Taber - >FirstThunk); / / (IAT函数地址表) RtlInitAnsiString(&Transition1, DllName); / / 将DLL名从ASCLL字符串转换位ANSI字符串 status = RtlAnsiStringToUnicodeString(&Unicode_DLLName, &Transition1, sizeof(DllName) * 2 ); / / 将DLL从ANSI转换为 UNICODE 字符串 if (status) { DbgPrint( "RtlAnsiStringToUnicodeString开辟空间失败!\n" ); } ImageBase = GetMoudleAddress(&Unicode_DLLName); if (ImageBase = = 0 ) { DbgPrint( "获取模块Base失败 修复IAT表失败!\n" ); return - 1 ; } DbgPrint( "%s Base\n" , DllName, ImageBase); while (( * IAT)) { if ((( * INT )& 0x80000000 ) ! = 0x80000000 ) { / / 当 INT 项存储胡DWORD数据的最高位不为 0 时候执行这个 FuintionName1 = (char * )((DWORD)Mem1 + * INT + 2 ); FuintionName2 = (char * )((DWORD)Mem1 + * IAT + 2 ); / / RtlInitAnsiString(&Transition, FuintionName1); / / 把ASCLL字符转换位ANSI_STRING / / status = RtlAnsiStringToUnicodeString(&Unicode_String, &Transition, sizeof(FuintionName1) * 2 ); / / 把ANSI_STRING字符串转换为UNICODE_STRING字符串 / / DbgPrint( "%wZ %d %Z\n" , &Unicode_String, status,&Transition); / / DbgPrint( "i=%d DLLName=%s,FuntionName=%s,FuntionName2=%s *INT=%p *IAT=%p" ,i + 1 , DllName, FuintionName1, FuintionName2, * INT , * IAT); / / RtlFreeUnicodeString(&Unicode_String); * IAT = GetProcessAddress(ImageBase, FuintionName1); if ( 0 = = * IAT) { DbgPrint( "FuintionName1=%s 获取导入函数地址函数!\n" , FuintionName1); return - 2 ; } DbgPrint( "%d DllName=%s Address=%p FuntionName=%s\n" ,n + 1 , DllName, * IAT ,FuintionName1); / / DbgPrint( "%d DllName=%s %s \n" ,n + 1 , DllName,FuintionName1); } else { / / FuintionName1 = / / FuintionName2 = DbgPrint( "*INT=%p *IAT=%p\n" , * INT , * IAT); } IAT + + ; INT + + ; n + + ; } RtlFreeUnicodeString(&Unicode_DLLName); ImPort_Taber + + ; } DbgPrint( "导入表 ok!\n" ); return 1 ; |
}
NTSTATUS CharacteristicScan(DWORD ImageBase) {
DWORD SizeofImage;
DWORD i = 0;
DWORD j = 0;
DWORD Number = 0;
PE_HEADER pE = { 0 };
char Data = NULL;
char Dest = NULL;
pE.DosHeader = (PIMAGE_DOS_HEADER)ImageBase;
pE.NtHeaders.FileHeader = (PIMAGE_FILE_HEADER)((DWORD)pE.DosHeader + (DWORD)pE.DosHeader->e_lfanew + 4); //e_lfarlc写错找到2个小时bug
pE.NtHeaders.OptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pE.NtHeaders.FileHeader + sizeof(IMAGE_FILE_HEADER));
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | Data = (char * )KeServiceDescriptorTable; SizeofImage = pE.NtHeaders.OptionalHeader - >SizeOfImage; / / ShaDow所在模块大小 Dest = (char * )ImageBase; DbgPrint( "SizeofImage=%p\n" , SizeofImage); for (i = ImageBase; i < ImageBase + SizeofImage; i + + ) { / / 应该是扫描到 if (Dest[i] = = Data[j]) { Number + + ; j + + ; } else { if (j > = 15 ) { DbgPrint( "%p\n" , Dest + i - j); } j = 0 ; Number = 0 ; } } return 0 ; |
}
NTSTATUS GetKernelMoudleAddr() {
DWORD ImageBase = 0;
__asm {
push eax
mov eax, fs:[0x34]
add eax, 0x18
mov eax, [eax]
mov eax, [eax]
mov eax, [eax + 0x18] //指向内核模块基地址
mov ImageBase, eax
pop eax
}
return (ImageBase == 0) ? 0 : ImageBase;
}
NTSTATUS RepairSSDT(DWORD OlbkernelAddress) {
DWORD u_offset;
DWORD i;
DbgPrint("%p %p %p", KeServiceDescriptorTable, Mem1, OlbkernelAddress);
g_NewKernelSeriveDescriptorTaber = (PKSERVICE_TABLE_DESCRIPTOR)((DWORD)(KeServiceDescriptorTable) + ((DWORD)Mem1 - OlbkernelAddress)); //老系统服务表地址-老内核Base+新内核Base=RVA+内核base
1 2 3 4 5 6 7 8 | u_offset = ((DWORD)KeServiceDescriptorTable - >ntoskrnel.ServiceTableBase - OlbkernelAddress); / / 得到旧内核SSDT函数表到ImageBase的offset g_NewKernelSeriveDescriptorTaber - >ntoskrnel.ServiceTableBase = (PVOID)(u_offset + (DWORD)Mem1); g_NewKernelSeriveDescriptorTaber - >ntoskrnel.NumberOfServices = KeServiceDescriptorTable - >ntoskrnel.NumberOfServices; g_NewKernelSeriveDescriptorTaber - >ntoskrnel.ParamTableBase = (PVOID)((DWORD)Mem1 + ((DWORD)KeServiceDescriptorTable - >ntoskrnel.ParamTableBase - OlbkernelAddress)); DbgPrint( "新内核的系统服务表地址%p %p %p %p %p\n" , g_NewKernelSeriveDescriptorTaber, g_NewKernelSeriveDescriptorTaber - >ntoskrnel.ServiceTableBase, g_NewKernelSeriveDescriptorTaber - >ntoskrnel.ServiceCouterTable, g_NewKernelSeriveDescriptorTaber - >ntoskrnel.NumberOfServices, g_NewKernelSeriveDescriptorTaber - >ntoskrnel.ParamTableBase); NewSeriverBase = (DWORD)g_NewKernelSeriveDescriptorTaber - >ntoskrnel.ServiceTableBase; |
#if 0 /修复重定位的时候这个都修复了/
for (i = 0; i < g_NewKernelSeriveDescriptorTaber->ntoskrnel.NumberOfServices; i++) {
g_NewKernelSeriveDescriptorTaber->ntoskrnel.NumberOfServices[i] += u_offset; //修复SSDT
}
#endif
1 2 3 | / / DbgPrint( "%p %p %p" , g_NewKernelSeriveDescriptorTaber - >ntoskrnel.ServiceTableBase, g_NewKernelSeriveDescriptorTaber - >ntoskrnel.ServiceCouterTable, / / g_NewKernelSeriveDescriptorTaber - >ntoskrnel.NumberOfServices, g_NewKernelSeriveDescriptorTaber - >ntoskrnel.ParamTableBase); return 0 ; |
}
DWORD DisPaly(DWORD Base,DWORD FuntionAddress,DWORD Index) {
DWORD Data = NULL;
DWORD New = NULL;
char ProcessName = NULL;
char CurrentProcessName = 0;
PEPROCESS Current;
if (Base == (DWORD)KeServiceDescriptorTable->ntoskrnel.ServiceTableBase) {
Current = PsGetCurrentProcess();
CurrentProcessName = (char*)((DWORD)Current + 0x174);
if (Index == 0x25) {
1 2 3 4 5 6 7 8 9 10 11 12 13 | DbgPrint( "NtCreateFile! =%p %s %s\n" , FuntionAddress, CurrentProcessName,ProcessName); } else if (Index = = 0x74 ) { char * Size = (char * )(((DWORD)KeServiceDescriptorTable - >ntoskrnel.ParamTableBase) + Index); DbgPrint( "NtOpenFile! =%p %s %s\n" , FuntionAddress, CurrentProcessName, ProcessName); } DbgPrint( "111111111 eax=%p %p %p" , Index, FuntionAddress, Base); return * ((DWORD * )((DWORD)g_NewKernelSeriveDescriptorTaber - >ntoskrnel.ServiceTableBase + Index * 4 )); } else { DbgPrint( "eax=%p %p %p" , Index, FuntionAddress, Base); return FuntionAddress; } |
}/
push EAX, ECX,EDX,EBX, ESP(初始值0x7c00),EBP,ESI,EDI
popad EDI ESI EBP ESP EBX EDX ECX EAX
/
declspec(naked) void MyKiFastCallEntry() { //我自己的KiFastCallEntry
asm {
pushad
pushfd
__asm {
int 3
}
push eax //eaxSSDT索引
push ebx //ebx指向即将别调用函数的地址
push edi //执行到了这里edi指向函数表地址
//push edx
call DisPaly
test eax,eax
je L
mov [esp+0x14],eax
L:
popfd
popad
1 2 3 4 | sub esp, ecx shr ecx, 2 jmp RetAddress } |
}
void Cr0Close() {
__asm {
mov eax,cr0
and eax, 0xFFFEFFFF
mov cr0,eax
sti //STI允许中断发生
}
}
/WP位是Supervisor的写保护位(CPL < 3是Supervisor) Supervisor监管者模式就是内核模式
当WP = 1时,Supervisor不能写R / W没有置位的页。 WP=1 内核下不能写 R/W=0的物理页
WP = 0时,Supervisor可以写任何页。 WP=0是 可以写任何页/
void Cr0Off() {
__asm {
cli //静止中断发送
mov eax, cr0
or eax, 0x10000
mov cr0, eax
}
}
NTSTATUS HookkiFastCallEntry() {
unsigned char Jmp_Code[5] = {0};
Jmp_Code[0] = 0xE9;
/JMP后面跟的32位数=目标地址-当前指令地址-5/
((DWORD)&Jmp_Code[1]) = (DWORD)MyKiFastCallEntry - HookAddress - 5;
RetAddress = HookAddress + 5;
Cr0Off();
RtlCopyMemory(HooKData, (void)HookAddress, 5);
RtlCopyMemory((void)HookAddress,(void*)Jmp_Code, 5);
Cr0Close();
1 2 3 | DbgPrint( "Hook Yes!\n" ); return 0 ; |
}
NTSTATUS DirverEntry(PDRIVER_OBJECT Pobject, PUNICODE_STRING RegPath) {
DWORD OlbkernelAddress;
NTSTATUS status;
UNICODE_STRING KernelPathName;
char Name[10] = "taolaoda";
CurrentObject = Pobject;
RtlInitUnicodeString(&KernelPathName, L"\??\C:\WINDOWS\system32\ntkrnlpa.exe"); //ntkrnlpa.exe
DbgPrint("驱动加载成功!\n");
if (1==GetFileSize(&KernelPathName)) {
if (1 != RestoreReLcationTaber()) {
DbgPrint("修复重定位表失败");
goto exit;
}
}
switch (RestoreIATTaber()) {
case -2:
DbgPrint("修复IAT获得函数地址失败\n");
break;
case -1:
DbgPrint("修复IAT获得模块Base失败!\n");
break;
case 0:
DbgPrint("获得导入表RVA失败!\n");
break;
case 1:
DbgPrint("修复IAT表成功!\n");
break;
}
exit:
//GetProcessAddress(0x804D8000, Name);
1 2 3 4 5 6 7 8 9 10 11 | DbgPrint( " KeServiceDescriptorTable=%p %p %p %p %p\n" , KeServiceDescriptorTable, KeServiceDescriptorTable - >ntoskrnel.ServiceTableBase, KeServiceDescriptorTable - >ntoskrnel.ServiceCouterTable, KeServiceDescriptorTable - >ntoskrnel.NumberOfServices, KeServiceDescriptorTable - >ntoskrnel.ParamTableBase); / / CharacteristicScan( 0x804D8000 ); / / DbgPrint( "KeServiceDescriptorTableShadow=%p\n" , KeServiceDescriptorTableShadow); OlbkernelAddress = GetKernelMoudleAddr(); / / 旧内核模块的地址 DbgPrint( "内核模块地址为=%p\n" , OlbkernelAddress); RepairSSDT(OlbkernelAddress); HookkiFastCallEntry(); Pobject - >DriverUnload = DriverUnload; return STATUS_SUCCESS; |
}
通过重载一份内核后,通过Hook KiFastCallEntry 中的那两行代码,可以实现Ring3调用SSDT中的函数都走我们hook的MyKiFastCallEntry函数,我们又在MyKiFastCallEntry函数中打印出来,结构却发现大部分的结构eax都是溢出的大于11C小于0x1000 都溢出了甚至很多时候打印出的SSDT函数表的Base值都是错误的,得到的函数地址也是错误的,但是我们不在MyKiFastCallEntry 中改变Ebx的值运行却不会出现问题,因为按照打印的结构来看应该必出现问题的,实在找不到原因,求有经验的大佬指点,按照KiFastCallEntry函数逆向的结构 执行SSDT中的函数 eax如果溢出了不会执行我们hook的地方
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课