最近在学HookSSDT和针对Hook的ResumeSSDT,避免自己理解有所偏差,把它们写出来,希望大家不吝赐教。(虽然已经是过时了的技术,但是最起码了解其中的原理,嘿嘿嘿。)
转载注明出处:http://www.cnblogs.com/littlepear/p/6664637.html
一 HookSSDT:
我们以Hook NtOpenProcess函数为例。首先是寻找SSDT表,32位下已经导出KeServiceDescriptorTable,而64位下没有导出,所以我们先暴力寻找SSDT的地址。
先讨论64位:
1.寻找SSDT表
我们通过读取MSR的0xC0000082处的地址,,里面保存的是64位的syscall,当我们u一下这个地址,发现这个就是x64系统调用的入口KiSystemCall64,我们把它作为搜索起始地址。
然后向下搜寻,以它的lea指令作为特征码,如图
0x00238c47是它的偏移,KeServiceDescriptorTable的地址 = 0xfffff800`03e91cf2+0x00238c47+7 = 0xfffff800`040ca940。
我们把SSDT保存在此结构体中。
typedef struct _SYSTEM_SERVICE_DESCRIPTOR_TABLE_
{
PVOID ServiceTableBase; //SSDT(System Service Dispatch Table)服务表的基地址
PVOID ServiceCounterTableBase; //用于checked builds,包含SSDT中每个服务被调用的次数
PVOID NumberOfServices; //服务函数的个数,NumberOfService * 4就是整个地址表的大小 64位 0x191, 32位 0x11c
PVOID ParamTableBase; //SSPT(System Service Parameter Table)的基地址
}SYSTEM_SERVICE_DESCRIPTOR_TABLE, *PSYSTEM_SERVICE_DESCRIPTOR_TABLE;
2.寻找NtOpenProcess在SSDT表中的系统调用号。
NtOpenProcess和ZwOpenProcess在Ntoskrnl.exe和ntdll.dll中都有导出,那么它们之间有什么区别呢?
先来看ntdll下的两个
发现NtOpenProcess就是ZwOpenProcess的一个别名,我们记他们为ntdll!ZwProcess,它们只把调用号mov到eax中,然后syscall.
看Ntoskrnl下的两个,
又发现内核空间中的ZwOpenProcess只是NtOpenProcess的一个跳板,它只是把系统调用号(rsp)Mov到eax中,然后调用nt!KiSystemServiceLinkage,真正的实现是通过NtOpenProcess,调用nt!PsOpenProcess
所以大体流程是: Kernel32.dll(API)--->ntdll.dll(Nt/Zw)--->用户模式转内核模式--->Ntoskrnl.exe(Nt)--->完成I/O请求(原路返回)
此处参考博客:http://www.cnblogs.com/uAreKongqi/p/6597701.html
然后64位调用号被rsp代替,所以我们只能从ntdll中查找ntdll!ZwOpenProcess,方法就是从ntdll导出表中查找到处函数,然后寻找调用号23h(函数地址+4),我们把它记为__NtOpenProcessIndex
3.保留原NtOpenProcess的偏移和地址。
我们记__OldNtOpenProcessOffset = __ServiceTableBase[__NtOpenProcessIndex]表示64位下NtOpenProcess的偏移,__ServiceTableBase为SSDT的第一个参数,此偏移是相对于 __ServiceTableBase的,
64位下,比如0x02e80205,最后一个数字为(函数参数-4),这里涉及到64位函数的调用约定和压参,不予讨论。我们需要__OldNtOpenProcessOffset >> 4+__ServiceTableBase获得函数的地址。
4.Hook NtOpenProcess函数。
原理就是:将SSDT表中NtOpenProcess的偏移替换成自己的函数的偏移,但是这里就出现问题了,64位下,函数的地址是16位,到__ServiceTableBase的偏移已经远远超过8位,不能放在表里,那怎么办呢? 我们选择InlineHook,就是把一个不经常用的函数,这里选择KeBugCheckEx(这就是64位下这种方法过时的原因,谁知道KeBugCheckEx这个函数不用呢),替换掉NtOpenProcess的偏移,然后我们在KeBugCheckEx函数中实现跳跃到自己的函数中,这就解决问题啦。
以上是64位的,32位需要注意,
第一点:Ntoskrnl.exe中导出了KeServiceDescriptorTable,不需要暴力找。
第二点:__NtOpenProcessIndex这次可以从Ntoskrnl.exe中找了,32位比较好,没用其他东西替代。
第三就是就是__ServiceTableBase[__NtOpenProcessIndex]中储存的是地址,而不是偏移,也不需要找像KeBugCheckEx的跳板函数,直接就可以放我函数的地址,比较方便。
细节看代码:
#include <ntifs.h> #define SEC_IMAGE 0x001000000 extern
PIMAGE_NT_HEADERS
NTAPI
RtlImageNtHeader(PVOID BaseAddress); extern
char* PsGetProcessImageFileName(PEPROCESS EProcess); typedef
NTSTATUS(*pfnNtOpenProcess)(
_Out_ PHANDLE ProcessHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_opt_ PCLIENT_ID ClientId
); typedef struct _SYSTEM_SERVICE_DESCRIPTOR_TABLE_
{
PVOID ServiceTableBase; //SSDT(System Service Dispatch Table)服务表的基地址
PVOID ServiceCounterTableBase; //用于checked builds,包含SSDT中每个服务被调用的次数
PVOID NumberOfServices; //服务函数的个数,NumberOfService * 4就是整个地址表的大小 64位 0x191, 32位 0x11c
PVOID ParamTableBase; //SSPT(System Service Parameter Table)的基地址
}SYSTEM_SERVICE_DESCRIPTOR_TABLE, *PSYSTEM_SERVICE_DESCRIPTOR_TABLE; BOOLEAN GetSSDTAddressInWin7_x64(ULONG64* SSDTAddress);
BOOLEAN GetSSDTAddressInWin7_x86(ULONG32* SSDTAddress);
VOID DriverUnload(PDRIVER_OBJECT DriverObject);
BOOLEAN GetSSDTFunctionIndexFromExportTableOfNtdllByFunctionName(CHAR* szFuntionName, ULONG32* SSDTFunctionIndex);
PVOID
GetExportVariableAddressFromNtosKrnlExportTableByVariableName(WCHAR* wzVariableName);
BOOLEAN Ring0MappingPEFile(WCHAR* szFileFullPath, PVOID* MappingBaseAddress, ULONG_PTR* MappingViewSize);
ULONG32 CalcFunctionOffsetInSSDT(PVOID ServiceTableBase, PVOID FunctionAddress, ULONG32 ParamterCount);
VOID HookSSDTInWin7_x64(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, PVOID MyFunctionAddress,
PVOID OldFuntionAddress, ULONG32 OldFunctionParamterCount, UCHAR* OldFunctionCode, ULONG32 PatchCodeLength);
VOID HookSSDTInWin7_x86(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, ULONG32 MyFunctionAddress);
VOID InlineHook(ULONG64 OldFuntionAddress, ULONG64 MyFunctionAddress, UCHAR* OldFunctionCode, ULONG32 PatchCodeLength);
NTSTATUS MyOpenProcess(
_Out_ PHANDLE ProcessHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_opt_ PCLIENT_ID ClientId
);
VOID WPOFF();
VOID WPON(); VOID UnHookSSDTInWin7_x64(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, ULONG32 OldFunctionOffset, PVOID OldFunctionAddress,
UCHAR* OldFunctionCode, ULONG32 PatchCodeLength);
VOID UnHookSSDTInWin7_x86(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, ULONG32 OldFunctionAddress);
VOID UnlineHook(PVOID OldFunctionAddress, CHAR* OldFunctionCode, ULONG32 PatchCodeLength);
HookSSDT.h
#include "HookSSDT.h"
#include <ntimage.h>
#include <Ntstrsafe.h> ULONG32 __NtOpenProcessIndex = ;
PVOID __ServiceTableBase = NULL;
ULONG32 __OldNtOpenProcessOffset = ;
pfnNtOpenProcess __OldNtOpenProcessAddress = NULL; //这里无所谓,PVOID也可以
BOOLEAN __IsHook = FALSE;
UCHAR __OldCode[] = { }; NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegisterPath)
{
NTSTATUS Status = STATUS_UNSUCCESSFUL;
char szFunctionName[] = "ZwOpenProcess";
ULONG_PTR SSDTAddress = ; //保存整个SSDT基地址 KeServiceDescriptorTable
ULONG32 TempOffset = ;
DriverObject->DriverUnload = DriverUnload; #ifdef _WIN64
if (GetSSDTAddressInWin7_x64(&SSDTAddress) == FALSE)
{
return Status;
}
#else
if (GetSSDTAddressInWin7_x86(&SSDTAddress) == FALSE)
{
return Status;
}
#endif DbgPrint("SSDT:%p\r\n", SSDTAddress); //0x23h
if (GetSSDTFunctionIndexFromExportTableOfNtdllByFunctionName(szFunctionName, &__NtOpenProcessIndex) == FALSE)
{
return Status;
} __ServiceTableBase = ((PSYSTEM_SERVICE_DESCRIPTOR_TABLE)SSDTAddress)->ServiceTableBase;
#ifdef _WIN64
__OldNtOpenProcessOffset = ((PULONG32)__ServiceTableBase)[__NtOpenProcessIndex];
TempOffset = __OldNtOpenProcessOffset >> ; //抹掉最右边的一位
__OldNtOpenProcessAddress = (PVOID)((ULONG64)__ServiceTableBase + TempOffset);
HookSSDTInWin7_x64(__ServiceTableBase, __NtOpenProcessIndex, MyOpenProcess, KeBugCheckEx, , __OldCode, );
#else
__OldNtOpenProcessAddress = (pfnNtOpenProcess)(((PULONG32)__ServiceTableBase)[__NtOpenProcessIndex]);
/*kd > u 0x84016ba1
nt!NtOpenProcess:
84016ba1 8bff mov edi, edi
84016ba3 55 push ebp
84016ba4 8bec mov ebp, esp
84016ba6 51 push ecx
84016ba7 51 push ecx
84016ba8 64a124010000 mov eax, dword ptr fs : [00000124h]
84016bae 8a803a010000 mov al, byte ptr[eax + 13Ah]
84016bb4 8b4d14 mov ecx, dword ptr[ebp + 14h]*/ //0x00145dc8 HookSSDTInWin7_x86(__ServiceTableBase, __NtOpenProcessIndex, (ULONG32)MyOpenProcess);//强制转换后,MyOpenProcess才可以传,真奇怪
#endif
return STATUS_SUCCESS;
} VOID DriverUnload(PDRIVER_OBJECT DriverObject)
{
DbgPrint("ByeBye,Driver!\r\n"); if (__IsHook)
{
#ifdef _WIN64 UnHookSSDTInWin7_x64(__ServiceTableBase, __NtOpenProcessIndex, __OldNtOpenProcessOffset, KeBugCheckEx,
__OldCode, );
#else
UnHookSSDTInWin7_x86(__ServiceTableBase, __NtOpenProcessIndex, __OldNtOpenProcessAddress);
#endif __IsHook = FALSE;
}
} BOOLEAN GetSSDTAddressInWin7_x64(ULONG64* SSDTAddress)
{
//rdmsr c0000082
CHAR* StartSearchAddress = (char*)__readmsr(0xc0000082);
CHAR* EndSearchAddress = StartSearchAddress + PAGE_SIZE; //4KB
CHAR* i = NULL;
UCHAR v1 = , v2 = , v3 = ;
//必须用UCHAR类型,因为Char的范围是 -128~127 0x80-0x7F
INT64 Offset = ;
*SSDTAddress = NULL;
for (i = StartSearchAddress; i < EndSearchAddress; i++)
{
if (MmIsAddressValid(i) && MmIsAddressValid(i + ) && MmIsAddressValid(i + ))
{
v1 = *i;
v2 = *(i + );
v3 = *(i + );
if (v1 == 0x4c && v2 == 0x8d && v3 == 0x15)
{
// 4c8d15238f4700
memcpy(&Offset, i+, );
*SSDTAddress = Offset + (ULONG64)i+;
break;
}
}
}
if (*SSDTAddress == NULL)
{
return FALSE;
}
return TRUE;
} BOOLEAN GetSSDTAddressInWin7_x86(ULONG32* SSDTAddress)
{
//32位下Ntoskrnl.exe有导出 KeServiceDescriptorTable,直接查找即可
*SSDTAddress = NULL;
*SSDTAddress = (ULONG32)GetExportVariableAddressFromNtosKrnlExportTableByVariableName(L"KeServiceDescriptorTable");
if (*SSDTAddress != NULL)
{
return TRUE;
}
return FALSE;
} PVOID
GetExportVariableAddressFromNtosKrnlExportTableByVariableName(WCHAR* wzVariableName)
{
//通过导出变量名字从NtosKrnl中获得导出变量地址
UNICODE_STRING uniVariableName;
PVOID VariableAddress = NULL; if (wzVariableName&&wcslen(wzVariableName) > )
{
RtlUnicodeStringInit(&uniVariableName, wzVariableName);
//从Ntos模块的导出表中获得导出变量的地址
VariableAddress = MmGetSystemRoutineAddress(&uniVariableName);
}
return VariableAddress;
} BOOLEAN GetSSDTFunctionIndexFromExportTableOfNtdllByFunctionName(CHAR* szFuntionName, ULONG32* SSDTFunctionIndex)
{
WCHAR szFileFullPath[] = L"\\SystemRoot\\System32\\ntdll.dll"; //C:\Windows\
ULONG_PTR MappingViewSize = ;
PVOID MappingBaseAddress = ;
BOOLEAN IsOk = FALSE;
PIMAGE_NT_HEADERS Image_Nt_Headers = NULL;
PIMAGE_EXPORT_DIRECTORY ImageExportDirectory = NULL; //导出表
//因为不识别DWORD,所以用UINT32
UINT32* AddressOfFunctions = NULL;
UINT32* AddressOfNames = NULL;
UINT16* AddressOfNameOrdinals = NULL;
int i = ;
char* v1 = NULL;
ULONG32 OrdinalOfFunction = ;
PVOID AddressOfFunction = ;
#ifdef _WIN64
/*
0:004> u zwopenprocess
ntdll!NtOpenProcess:
00000000`774ddc10 4c8bd1 mov r10,rcx
00000000`774ddc13 b823000000 mov eax,23h
00000000`774ddc18 0f05 syscall
00000000`774ddc1a c3 ret
00000000`774ddc1b 0f1f440000 nop dword ptr [rax+rax]
*/
ULONG32 Offset_SSDTFunctionIndex = ;
#else
/*
0:004> u zwopenprocess
ntdll!NtOpenProcess:
00000000`774ddc10 4c8bd1 mov r10,rcx
00000000`774ddc13 b823000000 mov eax,23h
00000000`774ddc18 0f05 syscall
00000000`774ddc1a c3 ret
00000000`774ddc1b 0f1f440000 nop dword ptr [rax+rax]
*/
ULONG32 Offset_SSDTFunctionIndex = ;
#endif *SSDTFunctionIndex = -;
IsOk = Ring0MappingPEFile(szFileFullPath, &MappingBaseAddress, &MappingViewSize);
if (IsOk == FALSE)
{
return FALSE;
}
else
{
__try {
Image_Nt_Headers = RtlImageNtHeader(MappingBaseAddress); //extern进来
if (Image_Nt_Headers&&Image_Nt_Headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress)
{
ImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((char*)MappingBaseAddress
+ Image_Nt_Headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); AddressOfFunctions = (UINT32*)((char*)MappingBaseAddress + ImageExportDirectory->AddressOfFunctions);
//函数的地址(RVA)
AddressOfNames = (UINT32*)((char*)MappingBaseAddress + ImageExportDirectory->AddressOfNames);;
//函数名字的地址(RVA)
AddressOfNameOrdinals = (UINT16*)((char*)MappingBaseAddress + ImageExportDirectory->AddressOfNameOrdinals);
//有名字的序号的首地址(RVA)
for (i = ; i < ImageExportDirectory->NumberOfNames; i++)
{
v1 = (char*)((char*)MappingBaseAddress + AddressOfNames[i]); //可以这样写 ImageExportDirectory->AddressOfNames + i * 4
if (_stricmp(szFuntionName, v1) == )
{
OrdinalOfFunction = AddressOfNameOrdinals[i];
AddressOfFunction = (PVOID)((char*)MappingBaseAddress + AddressOfFunctions[OrdinalOfFunction]);//AddressOfFunctions[AddressOfNameOrdinals[i]]
*SSDTFunctionIndex = *(ULONG32*)((char*)AddressOfFunction + Offset_SSDTFunctionIndex);
break;
}
}
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{} }
ZwUnmapViewOfSection(NtCurrentProcess(), MappingBaseAddress);
if (*SSDTFunctionIndex == -)
{
return FALSE;
}
return TRUE;
}
//函数需要,所以传双字 二维指针
BOOLEAN Ring0MappingPEFile(WCHAR* szFileFullPath, PVOID* MappingBaseAddress, ULONG_PTR* MappingViewSize)
{
NTSTATUS Status;
UNICODE_STRING Temp;
OBJECT_ATTRIBUTES oa;
HANDLE hFile = NULL;
HANDLE hSection = NULL;
IO_STATUS_BLOCK IoStatusBlock; if (!szFileFullPath&&MmIsAddressValid(szFileFullPath))
{
return FALSE;
}
if (!MappingBaseAddress&&MmIsAddressValid(MappingBaseAddress))
{
return FALSE;
}
RtlUnicodeStringInit(&Temp, szFileFullPath);
InitializeObjectAttributes(&oa, //out
&Temp, //in ObjectName
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,//被系统在和ObjectName比较匹配时不区分大小写||此句柄只能用于内核模式下
NULL, //与ObjectName参数匹配的根目录对象,如果ObjectName是对象的全路径则设置此参数为NULL
NULL //驱动程序可以使用NULL用于创建一个具有默认安全描述符的对象
);
//打开文件,获得文件句柄
Status = IoCreateFile(&hFile,
GENERIC_READ | SYNCHRONIZE, //可读|同步
&oa,
&IoStatusBlock, //返回I/O请求的完成情况
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
,
CreateFileTypeNone,
NULL,
IO_NO_PARAMETER_CHECKING
);
if (!NT_SUCCESS(Status))
{
return FALSE;
}
oa.ObjectName = NULL;
Status = ZwCreateSection(&hSection,
SECTION_QUERY | SECTION_MAP_READ,
&oa,
NULL,
PAGE_WRITECOPY,
SEC_IMAGE,//内存按1M对齐 0x1000 000
hFile
);
ZwClose(hFile);
if (!NT_SUCCESS(Status))
{
return FALSE;
}
Status = ZwMapViewOfSection(hSection,
NtCurrentProcess(),
MappingBaseAddress,
,
,
,
MappingViewSize,
ViewUnmap, //不能被映射到子进程中
,
PAGE_WRITECOPY
);
ZwClose(hSection);
if (!NT_SUCCESS(Status))
{
return FALSE;
}
return TRUE;
} ULONG32 CalcFunctionOffsetInSSDT(PVOID ServiceTableBase, PVOID FunctionAddress, ULONG32 ParamterCount)
{
//完全没必要像下面这样折腾,就是一个做个SSDT表中类似的地址,有时间自己写一个
ULONG32 Offset = ;
CHAR Temp = ;
CHAR Bits[] = { };
int i = ;
Offset = (ULONG32)((ULONG64)FunctionAddress - (ULONG64)ServiceTableBase);
Offset = Offset << ;
if (ParamterCount > )
{
ParamterCount = ParamterCount-; //NtReadFile 9个参数 和参数压栈有关
}
else
{
ParamterCount = ;
}
memcpy(&Temp, &Offset, ); // 1010 0010 <<4-----> 0010 0000 后面处理参数
#define SETBIT(x,y) x|=(1<<y) //将X的第Y位置1
#define CLRBIT(x,y) x&=~(1<<y) //将X的第Y位清0
#define GETBIT(x,y) (x & (1 << y)) //取X的第Y位,返回0或非0 for (i = ; i < ; i++)
{
Bits[i] = GETBIT(ParamterCount, i);
if (Bits[i])
{
SETBIT(Temp, i);
}
else
{
CLRBIT(Temp, i);
}
}
memcpy(&Offset, &Temp, );
return Offset;
} //write protect 第17位
VOID WPOFF()
{
_disable();
__writecr0(__readcr0() & (~(0x10000))); } VOID WPON()
{
__writecr0(__readcr0() ^ 0x10000);
_enable();
} VOID HookSSDTInWin7_x64(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, PVOID MyFunctionAddress,
PVOID OldFuntionAddress, ULONG32 OldFunctionParamterCount, UCHAR* OldFunctionCode, ULONG32 PatchCodeLength)
{
ULONG32 MyOffset = ;
WPOFF();
InlineHook(OldFuntionAddress, MyFunctionAddress, OldFunctionCode, PatchCodeLength);
WPON(); MyOffset = CalcFunctionOffsetInSSDT(ServiceTableBase, OldFuntionAddress, OldFunctionParamterCount);
WPOFF();
((PULONG32)ServiceTableBase)[SSDTFunctionIndex] = MyOffset;
WPON(); __IsHook = TRUE;
} VOID HookSSDTInWin7_x86(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, ULONG32 MyFunctionAddress)
{
WPOFF();
((PULONG32)ServiceTableBase)[SSDTFunctionIndex] = (ULONG32)MyFunctionAddress;
WPON(); __IsHook = TRUE;
} VOID InlineHook(ULONG64 OldFuntionAddress, ULONG64 MyFunctionAddress, UCHAR* OldFunctionCode, ULONG32 PatchCodeLength)
{
CHAR PatchCode[] = "\xFF\x25\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"; //神坑啊,脑残啊,写成PatchCode 到memcpy才崩溃
ULONG64 Temp = MyFunctionAddress;
memcpy(OldFunctionCode, (PVOID)OldFuntionAddress, PatchCodeLength); //保存原来的函数指令
memcpy(PatchCode + , &Temp, );
DbgPrint("%s\r\n", PatchCode);
memset((PVOID)OldFuntionAddress, 0x90, PatchCodeLength); //先全部打上NOP(计组)
memcpy((PVOID)OldFuntionAddress, PatchCode, );
} //SSDT HOOK的替换函数如何对访问进行过滤”比“如何实现SSDT HOOK”要复杂多了,详见ediary HookNtOpenProcess后的事情
NTSTATUS MyOpenProcess(
_Out_ PHANDLE ProcessHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_opt_ PCLIENT_ID ClientId
)
{
//EnumProcessByForce.exe
//调用OpenProcess---->去NtDll导出表中寻找ntdll!NtOpenProcess或者ntdll!ZwOpenProcess 导出表有名称的索引---->切入内核-->跳板nt!ZwOpenProcess Ntoskernl.exe(NtOpenProcess mov eax,23h SSDT[23h])
// ---->KeCheckBugEx ---->Jmp MyOpenProcess
PEPROCESS EProcess = PsGetCurrentProcess(); //EnumProcessByForce.exe
if (EProcess != NULL && MmIsAddressValid(EProcess))
{
char *szProcessImageFileName = PsGetProcessImageFileName(EProcess);
if (strstr(szProcessImageFileName, "EnumProcess") != )
{
return STATUS_ACCESS_DENIED; //黑名单中返回
}
}
__OldNtOpenProcessAddress(ProcessHandle, DesiredAccess, ObjectAttributes, ClientId); //白名单
//OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, i)
//return STATUS_SUCCESS; 死循环
//return STATUS_UNSUCCESSFUL; 阻塞 很有趣
} VOID UnHookSSDTInWin7_x64(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, ULONG32 OldFunctionOffset, PVOID OldFunctionAddress,
UCHAR* OldFunctionCode, ULONG32 PatchCodeLength)
{
WPOFF();
UnlineHook(OldFunctionAddress, OldFunctionCode, PatchCodeLength);
WPON(); WPOFF();
((PULONG32)ServiceTableBase)[SSDTFunctionIndex] = (ULONG32)OldFunctionOffset;
WPON();
} VOID UnlineHook(PVOID OldFunctionAddress, CHAR* OldFunctionCode, ULONG32 PatchCodeLength)
{
memcpy((PVOID)OldFunctionAddress, OldFunctionCode, PatchCodeLength);
} VOID UnHookSSDTInWin7_x86(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, ULONG32 OldFunctionAddress)
{
WPOFF();
((PULONG32)ServiceTableBase)[SSDTFunctionIndex] = (ULONG32)OldFunctionAddress;
WPON();
}
HookSSDT.c
ResumeSSDT:
原理:因为我们Hook的是模块中的NtOpenProcess, 所以我们可以寻找Ntoskrnl.exe文件中NtOpenProcess的地址,再替换掉已经被替换掉的。
先谈64位:
1.找SSDT表和调用号和Hook的过程一样。
2.关键是找NtOpenProcess的真正地址。
有两种方法:
1.因为NtOpenProcess已经在Ntoskrnl.exe中导出了,所以我们直接从导出表中找到它的函数地址,只不过这个地址是文件中的,需要转换成在内存中的,那怎么转换呢?
我们首先要了解这个文件中的函数地址是怎么回事,《WindowsPE权威指南》上92页上有讲,IMAGE_OPTIONAL_HEADER32.ImageBase的地址是映像基地址的优先装入地址,exe文件被装入到起始地址为0x400000h的虚拟内存地址处。
再看《WindowsPE权威指南》80页上,链接器在产生可执行文件的时候,都是对应ImageBase(32位下是0x400000, 64位下是0x00000001`40000000)来生成机器码的,好比其中的一个函数NtOpenProcess,直接查看ntoskrnl.exe导出表中它的地址,也就是它在产生可执行文件的时候,所有东西都是对照这个地址生成机器码的,并且这个地址是它假想映射到内存的地址,即按0x1000对齐过的地址。
PS: 用PECheck小工具查看NtOpenProcess,注意偏移值和上述假想地址-ImageBase相等
但是对于EXE来说,每个文件使用的都是独立的虚拟地址空间,所以,优先装入的地址通常不会被其他模块占据,也就是说,如果再来新的模块,前面那个值被占领了,操作系统会做出调整,找到合适的地址,这个地址就是真正的内存中的模块基地址。
那好了,我们可以来计算真正的内存中的地址。我们先计算文件中函数的偏移,即 0x00000001`403473d0-0x00000001`40000000, 再加上真正的模块基地址ModuleBase,不就得到了真正的函数地址了?
然后再和现在内存中SSDT 0x23h的位置比较,看看是否被Hook了。
2.第二种找NtOpenProcess的方法,就是通过将内存中SSDT->ServiceTableBase的偏移(RVA)转换为文件中文件中它的偏移(FOA),然后通过调用号再找到文件中NtOpenProcess的地址,然后转换为内存中的地址方法和上述步骤一样。 那么怎么将RVA转换为FVA呢?
《WindowsPE权威指南》93页上,
(1) 首先判断RVA落在哪个节内。
(2) 求出该节的起始 RVA0 = IMAGE_SRCTION_HEADER->VirtualAddress
(3) 求出偏移量Offset = RVA-RVA0. 这个偏移在文件中和内存中都是一样的(因为对齐是在节的数据后面补0,而不是前面)。
(4) 求出FOA = IMAGE_SECTION_HEADER.PointerToRawData+Offset
好了,64位的两种方法就介绍完了,32位的话,有几个地方需要注意:
1.Ntoskrnl.exe在32位下有几种不同的模式,
参考博客:http://www.tuicool.com/articles/UrqIZv
所以要判断当下系统是哪一个。
2.就是NtOpenProcess在SSDT表中以地址的形式保存,就是和64位的一般区别了。
细节看代码吧:
#include <ntifs.h> #define SEC_IMAGE 0x001000000 extern
PIMAGE_NT_HEADERS
NTAPI
RtlImageNtHeader(PVOID BaseAddress); typedef enum _SYSTEM_INFORMATION_CLASS_
{
SystemBasicInformation = 0x0,
SystemProcessorInformation = 0x1,
SystemPerformanceInformation = 0x2,
SystemTimeOfDayInformation = 0x3,
SystemPathInformation = 0x4,
SystemProcessInformation = 0x5,
SystemCallCountInformation = 0x6,
SystemDeviceInformation = 0x7,
SystemProcessorPerformanceInformation = 0x8,
SystemFlagsInformation = 0x9,
SystemCallTimeInformation = 0xa,
SystemModuleInformation = 0xb,
SystemLocksInformation = 0xc,
SystemStackTraceInformation = 0xd,
SystemPagedPoolInformation = 0xe,
SystemNonPagedPoolInformation = 0xf,
SystemHandleInformation = 0x10,
SystemObjectInformation = 0x11,
SystemPageFileInformation = 0x12,
SystemVdmInstemulInformation = 0x13,
SystemVdmBopInformation = 0x14,
SystemFileCacheInformation = 0x15,
SystemPoolTagInformation = 0x16,
SystemInterruptInformation = 0x17,
SystemDpcBehaviorInformation = 0x18,
SystemFullMemoryInformation = 0x19,
SystemLoadGdiDriverInformation = 0x1a,
SystemUnloadGdiDriverInformation = 0x1b,
SystemTimeAdjustmentInformation = 0x1c,
SystemSummaryMemoryInformation = 0x1d,
SystemMirrorMemoryInformation = 0x1e,
SystemPerformanceTraceInformation = 0x1f,
SystemObsolete0 = 0x20,
SystemExceptionInformation = 0x21,
SystemCrashDumpStateInformation = 0x22,
SystemKernelDebuggerInformation = 0x23,
SystemContextSwitchInformation = 0x24,
SystemRegistryQuotaInformation = 0x25,
SystemExtendServiceTableInformation = 0x26,
SystemPrioritySeperation = 0x27,
SystemVerifierAddDriverInformation = 0x28,
SystemVerifierRemoveDriverInformation = 0x29,
SystemProcessorIdleInformation = 0x2a,
SystemLegacyDriverInformation = 0x2b,
SystemCurrentTimeZoneInformation = 0x2c,
SystemLookasideInformation = 0x2d,
SystemTimeSlipNotification = 0x2e,
SystemSessionCreate = 0x2f,
SystemSessionDetach = 0x30,
SystemSessionInformation = 0x31,
SystemRangeStartInformation = 0x32,
SystemVerifierInformation = 0x33,
SystemVerifierThunkExtend = 0x34,
SystemSessionProcessInformation = 0x35,
SystemLoadGdiDriverInSystemSpace = 0x36,
SystemNumaProcessorMap = 0x37,
SystemPrefetcherInformation = 0x38,
SystemExtendedProcessInformation = 0x39,
SystemRecommendedSharedDataAlignment = 0x3a,
SystemComPlusPackage = 0x3b,
SystemNumaAvailableMemory = 0x3c,
SystemProcessorPowerInformation = 0x3d,
SystemEmulationBasicInformation = 0x3e,
SystemEmulationProcessorInformation = 0x3f,
SystemExtendedHandleInformation = 0x40,
SystemLostDelayedWriteInformation = 0x41,
SystemBigPoolInformation = 0x42,
SystemSessionPoolTagInformation = 0x43,
SystemSessionMappedViewInformation = 0x44,
SystemHotpatchInformation = 0x45,
SystemObjectSecurityMode = 0x46,
SystemWatchdogTimerHandler = 0x47,
SystemWatchdogTimerInformation = 0x48,
SystemLogicalProcessorInformation = 0x49,
SystemWow64SharedInformationObsolete = 0x4a,
SystemRegisterFirmwareTableInformationHandler = 0x4b,
SystemFirmwareTableInformation = 0x4c,
SystemModuleInformationEx = 0x4d,
SystemVerifierTriageInformation = 0x4e,
SystemSuperfetchInformation = 0x4f,
SystemMemoryListInformation = 0x50,
SystemFileCacheInformationEx = 0x51,
SystemThreadPriorityClientIdInformation = 0x52,
SystemProcessorIdleCycleTimeInformation = 0x53,
SystemVerifierCancellationInformation = 0x54,
SystemProcessorPowerInformationEx = 0x55,
SystemRefTraceInformation = 0x56,
SystemSpecialPoolInformation = 0x57,
SystemProcessIdInformation = 0x58,
SystemErrorPortInformation = 0x59,
SystemBootEnvironmentInformation = 0x5a,
SystemHypervisorInformation = 0x5b,
SystemVerifierInformationEx = 0x5c,
SystemTimeZoneInformation = 0x5d,
SystemImageFileExecutionOptionsInformation = 0x5e,
SystemCoverageInformation = 0x5f,
SystemPrefetchPatchInformation = 0x60,
SystemVerifierFaultsInformation = 0x61,
SystemSystemPartitionInformation = 0x62,
SystemSystemDiskInformation = 0x63,
SystemProcessorPerformanceDistribution = 0x64,
SystemNumaProximityNodeInformation = 0x65,
SystemDynamicTimeZoneInformation = 0x66,
SystemCodeIntegrityInformation = 0x67,
SystemProcessorMicrocodeUpdateInformation = 0x68,
SystemProcessorBrandString = 0x69,
SystemVirtualAddressInformation = 0x6a,
SystemLogicalProcessorAndGroupInformation = 0x6b,
SystemProcessorCycleTimeInformation = 0x6c,
SystemStoreInformation = 0x6d,
SystemRegistryAppendString = 0x6e,
SystemAitSamplingValue = 0x6f,
SystemVhdBootInformation = 0x70,
SystemCpuQuotaInformation = 0x71,
SystemNativeBasicInformation = 0x72,
SystemErrorPortTimeouts = 0x73,
SystemLowPriorityIoInformation = 0x74,
SystemBootEntropyInformation = 0x75,
SystemVerifierCountersInformation = 0x76,
SystemPagedPoolInformationEx = 0x77,
SystemSystemPtesInformationEx = 0x78,
SystemNodeDistanceInformation = 0x79,
SystemAcpiAuditInformation = 0x7a,
SystemBasicPerformanceInformation = 0x7b,
SystemQueryPerformanceCounterInformation = 0x7c,
SystemSessionBigPoolInformation = 0x7d,
SystemBootGraphicsInformation = 0x7e,
SystemScrubPhysicalMemoryInformation = 0x7f,
SystemBadPageInformation = 0x80,
SystemProcessorProfileControlArea = 0x81,
SystemCombinePhysicalMemoryInformation = 0x82,
SystemEntropyInterruptTimingInformation = 0x83,
SystemConsoleInformation = 0x84,
SystemPlatformBinaryInformation = 0x85,
SystemThrottleNotificationInformation = 0x86,
SystemHypervisorProcessorCountInformation = 0x87,
SystemDeviceDataInformation = 0x88,
SystemDeviceDataEnumerationInformation = 0x89,
SystemMemoryTopologyInformation = 0x8a,
SystemMemoryChannelInformation = 0x8b,
SystemBootLogoInformation = 0x8c,
SystemProcessorPerformanceInformationEx = 0x8d,
SystemSpare0 = 0x8e,
SystemSecureBootPolicyInformation = 0x8f,
SystemPageFileInformationEx = 0x90,
SystemSecureBootInformation = 0x91,
SystemEntropyInterruptTimingRawInformation = 0x92,
SystemPortableWorkspaceEfiLauncherInformation = 0x93,
SystemFullProcessInformation = 0x94,
SystemKernelDebuggerInformationEx = 0x95,
SystemBootMetadataInformation = 0x96,
SystemSoftRebootInformation = 0x97,
SystemElamCertificateInformation = 0x98,
SystemOfflineDumpConfigInformation = 0x99,
SystemProcessorFeaturesInformation = 0x9a,
SystemRegistryReconciliationInformation = 0x9b,
MaxSystemInfoClass = 0x9c,
} SYSTEM_INFORMATION_CLASS; typedef struct _SYSTEM_MODULE_INFORMATION
{
ULONG Reserved[];
#ifdef _WIN64
ULONG Reserved2[];
#endif PVOID Base;
ULONG Size;
ULONG Flags;
USHORT Index;
USHORT Unknown;
USHORT LoadCount;
USHORT ModuleNameOffset;
CHAR ImageName[];
}SYSTEM_MODULE_INFORMATION,*PSYSTEM_MODULE_INFORMATION; typedef struct
{
ULONG ulNumberOfModules;
SYSTEM_MODULE_INFORMATION smi; //我只取Ntoskrnl一个
}MODULES,*PMODULES; typedef struct _SYSTEM_SERVICE_DESCRIPTOR_TABLE_
{
PVOID ServiceTableBase; //SSDT(System Service Dispatch Table)服务表的基地址
PVOID ServiceCounterTableBase; //用于checked builds,包含SSDT中每个服务被调用的次数
PVOID NumberOfServices; //服务函数的个数,NumberOfService * 4就是整个地址表的大小 64位 0x191, 32位 0x11c
PVOID ParamTableBase; //SSPT(System Service Parameter Table)的基地址
}SYSTEM_SERVICE_DESCRIPTOR_TABLE, *PSYSTEM_SERVICE_DESCRIPTOR_TABLE; extern
NTSTATUS
ZwQuerySystemInformation(
IN ULONG SystemInformationClass,
IN PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength); void chartowchar(char* src, WCHAR* dst); VOID UnloadDriver(PDRIVER_OBJECT DriverObject); BOOLEAN GetModuleInfoByModuleName(PVOID* ModuleBase, ULONG64* ModuleSize); BOOLEAN GetSSDTAddressInWin7_x64(ULONG64* SSDTAddress); BOOLEAN GetSSDTAddressInWin7_x86(ULONG32* SSDTAddress); PVOID GetExportVariableAddressFromNtoskrnlExportTableByVariableName(WCHAR* wzVariableName); BOOLEAN GetSSDTFunctionIndexFromExportTableOfNtdllByFunctionName(CHAR* szFuntionName, ULONG* SSDTFunctionIndex); VOID WPOFF(); VOID WPON(); BOOLEAN Ring0MappingPEFile(WCHAR* szFileFullPath, PVOID* MappingBaseAddress, ULONG_PTR* MappingViewSize); BOOLEAN ResumeSSDTInWin7(ULONG_PTR SSDTAddress, ULONG_PTR ModuleBase, ULONG32 SSDTFunctionIndex, ULONG32 ParameterCount); BOOLEAN ReadingFileInRing0Space(WCHAR* wzFileFullPath, PVOID* szBuffer); VOID CharToWchar(PCHAR src, PWCHAR dst);
ResumeSSDT.h
#include "ResumeSSDT.h"
#include <ntstrsafe.h>
#include <ntimage.h> PVOID __NtosModuleBaseAddress = ;
PVOID __NtosModuleSize = ;
ULONG __NtOpenProcessIndex = ;
char __szNtosName[] = { };
WCHAR __wzNtosName[] = { };
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverEntry, PUNICODE_STRING RegisterPath)
{ ULONG_PTR SSDTAddress = ;
char szFunctionName[] = "NtOpenProcess";
DriverEntry->DriverUnload = UnloadDriver;
if (GetModuleInfoByModuleName(
&__NtosModuleBaseAddress, &__NtosModuleSize) == FALSE)
{
return STATUS_UNSUCCESSFUL;
}
DbgPrint("_Ntos:%p", __NtosModuleBaseAddress); #ifdef _WIN64
if (GetSSDTAddressInWin7_x64(&SSDTAddress) == FALSE)
{
DbgPrint("U\r\n");
return STATUS_UNSUCCESSFUL;
}
#else
if (GetSSDTAddressInWin7_x86(&SSDTAddress) == FALSE)
{
return STATUS_UNSUCCESSFUL;
}
#endif
if (GetSSDTFunctionIndexFromExportTableOfNtdllByFunctionName(szFunctionName, &__NtOpenProcessIndex) == FALSE)
{
return STATUS_UNSUCCESSFUL;
} if (ResumeSSDTInWin7(SSDTAddress, __NtosModuleBaseAddress, __NtOpenProcessIndex, ) == TRUE)
{
DbgPrint("Success\r\n");
return STATUS_SUCCESS;
} return STATUS_UNSUCCESSFUL;
} VOID UnloadDriver(PDRIVER_OBJECT DriverObject)
{
DbgPrint("UnloadDriver Success!\r\n");
} //下面这个函数是根据模块名字得到模块信息
BOOLEAN GetModuleInfoByModuleName(PVOID* ModuleBase, ULONG64* ModuleSize)
{
NTSTATUS Status = STATUS_SUCCESS;
ULONG ulReturnLength = ;
PVOID szBufferData = ; Status = ZwQuerySystemInformation(SystemModuleInformation,NULL, , &ulReturnLength);
if (Status != STATUS_INFO_LENGTH_MISMATCH) //此返回值的意思是 返回的长度不等于你要求的长度,因为我们传0,所以正好判断一下是否读取成功
{
return FALSE;
}
szBufferData = ExAllocatePool(PagedPool, ulReturnLength); //一般数据可以用PagedPool,ShellCode用NoPagedPool
if (szBufferData == NULL)
{
return FALSE;
}
Status = ZwQuerySystemInformation(SystemModuleInformation, szBufferData, ulReturnLength, &ulReturnLength);
if (!NT_SUCCESS(Status))
{
ExFreePool(szBufferData);
return FALSE;
}
for (int i = ; i < ((PMODULES)szBufferData)->ulNumberOfModules; i++)
{
if (strstr(((PMODULES)szBufferData)->smi.ImageName,"ntoskrnl.exe") != NULL)
{
strcpy(__szNtosName, "ntoskrnl.exe");
*ModuleBase = ((PMODULES)szBufferData)->smi.Base;
*ModuleSize = ((PMODULES)szBufferData)->smi.Size;
break;
}
else if (strstr(((PMODULES)szBufferData)->smi.ImageName, "ntkrnlpa.exe") != NULL)
{
strcpy(__szNtosName, "ntkrnlpa.exe");
*ModuleBase = ((PMODULES)szBufferData)->smi.Base;
*ModuleSize = ((PMODULES)szBufferData)->smi.Size;
break;
}
else if (strstr(((PMODULES)szBufferData)->smi.ImageName, "ntkrnlmp.exe") != NULL)
{
strcpy(__szNtosName, "ntkrnlmp.exe");
*ModuleBase = ((PMODULES)szBufferData)->smi.Base;
*ModuleSize = ((PMODULES)szBufferData)->smi.Size;
break;
}
else if (strstr(((PMODULES)szBufferData)->smi.ImageName, "ntkrpamp.exe") != NULL)
{
strcpy(__szNtosName, "ntkrpamp.exe");
*ModuleBase = ((PMODULES)szBufferData)->smi.Base;
*ModuleSize = ((PMODULES)szBufferData)->smi.Size;
break;
}
}
chartowchar(__szNtosName, __wzNtosName);
if (szBufferData != NULL)
{
ExFreePool(szBufferData);
szBufferData = NULL;
}
if (*ModuleBase != )
{
return TRUE;
}
return FALSE;
} //BOOLEAN GetNtosModule(PVOID* ModuleBase, ULONG64* ModuleSize)
//{
// NTSTATUS Status = STATUS_SUCCESS;
// ULONG ulReturnLength = 0;
// PVOID szBufferData = 0;
//
// Status = ZwQuerySystemInformation(SystemModuleInformation,NULL, 0, &ulReturnLength);
// if (Status != STATUS_INFO_LENGTH_MISMATCH) //此返回值的意思是 返回的长度不等于你要求的长度,因为我们传0,所以正好判断一下是否读取成功
// {
// return FALSE;
// }
// szBufferData = ExAllocatePool(PagedPool, ulReturnLength); //一般数据可以用PagedPool,ShellCode用NoPagedPool
// if (szBufferData == NULL)
// {
// return FALSE;
// }
// Status = ZwQuerySystemInformation(SystemModuleInformation, szBufferData, ulReturnLength, &ulReturnLength);
// if (!NT_SUCCESS(Status))
// {
// ExFreePool(szBufferData);
// return FALSE;
// }
// for (int i = 0; i < ((PMODULES)szBufferData)->ulNumberOfModules; i++)
// {
// strcpy(__szNtosName, ((PMODULES)szBufferData)->smi.ImageName); //依据的原理就是ZwQuerySystemInformation读的第一个模块就是Ntos系列的,这样不用比对,直接取第一个,大大方便了32位的编程
// CharToWchar(__szNtosName, __wzNtosName);
// *ModuleBase = ((PMODULES)szBufferData)->smi.Base;
// *ModuleSize = ((PMODULES)szBufferData)->smi.Size;
// break;
// }
// if (szBufferData != NULL)
// {
// ExFreePool(szBufferData);
// szBufferData = NULL;
// }
// if (*ModuleBase != 0)
// {
// return TRUE;
// }
// return FALSE;
//}
//char*转 wchar*
//输入窄字符串首地址,输出宽字符串,buffer 需要已经分配好空间 void chartowchar(char* src, WCHAR* dst)
{
UNICODE_STRING ustring;
ANSI_STRING astring;
RtlInitAnsiString(&astring, src);
RtlAnsiStringToUnicodeString(&ustring, &astring, TRUE);
wcscpy(dst, ustring.Buffer);
RtlFreeUnicodeString(&ustring);
} BOOLEAN GetSSDTAddressInWin7_x64(ULONG64* SSDTAddress)
{
CHAR* StartSearchAddress = (char*)__readmsr(0xc0000082);
CHAR* EndSearchAddress = StartSearchAddress + PAGE_SIZE;
CHAR* i = NULL;
UCHAR v1 = , v2 = , v3 = ;
INT64 Offset = ;
*SSDTAddress = NULL;
for (i = StartSearchAddress; i < EndSearchAddress; i++)
{
if (MmIsAddressValid(i) && MmIsAddressValid(i + ) && MmIsAddressValid(i + ))
{
v1 = *i;
v2 = *(i + );
v3 = *(i + );
if (v1 == 0x4c && v2 == 0x8d && v3 == 0x15)
{
memcpy(&Offset, i + , );
*SSDTAddress = Offset + (ULONG64)i + ;
return TRUE;
}
}
}
return FALSE;
} BOOLEAN GetSSDTAddressInWin7_x86(ULONG32* SSDTAddress)
{
//直接查找KeServiceDescriptorTable
*SSDTAddress = (ULONG32)GetExportVariableAddressFromNtoskrnlExportTableByVariableName(L"KeServiceDescriptorTable");
if (*SSDTAddress != )
{
return TRUE;
}
return FALSE;
} PVOID GetExportVariableAddressFromNtoskrnlExportTableByVariableName(WCHAR* wzVariableName)
{
UNICODE_STRING uniVariableName;
PVOID VariableAddress = NULL;
if (wzVariableName&&wcslen(wzVariableName) > )
{
RtlUnicodeStringInit(&uniVariableName, wzVariableName);
VariableAddress = MmGetSystemRoutineAddress(&uniVariableName);
}
return VariableAddress;
} BOOLEAN GetSSDTFunctionIndexFromExportTableOfNtdllByFunctionName(CHAR* szFuntionName, ULONG* SSDTFunctionIndex)
{
WCHAR szFileFullPath[] = L"\\SystemRoot\\System32\\ntdll.dll";
ULONG32 Offset_SSDTFunctionIndex = ;
PVOID MappingBaseAddress = ;
BOOLEAN IsOk = FALSE;
ULONG_PTR MappingViewSize = ;
PIMAGE_NT_HEADERS Image_Nt_Headers = NULL;
PIMAGE_EXPORT_DIRECTORY ImageExportDirectory = NULL;
//因为不识别DWORD,所以用UINT32
UINT32* AddressOfFunctions = NULL;
UINT32* AddressOfNames = NULL;
UINT16* AddressOfNameOrdinals = NULL;
int i = ;
char* v1 = NULL;
ULONG32 OrdinalOfFunction = ;
PVOID AddressOfFunction = ;
#ifdef _WIN64
Offset_SSDTFunctionIndex = ;
#else
Offset_SSDTFunctionIndex = ;
#endif
*SSDTFunctionIndex = -;
IsOk = Ring0MappingPEFile(szFileFullPath, &MappingBaseAddress, &MappingViewSize);
if (IsOk == FALSE)
{
return FALSE;
}
else
{
__try
{
Image_Nt_Headers = RtlImageNtHeader(MappingBaseAddress);
if (Image_Nt_Headers&&Image_Nt_Headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress)
{
ImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((char*)MappingBaseAddress
+ Image_Nt_Headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); AddressOfFunctions = (UINT32*)((char*)MappingBaseAddress + ImageExportDirectory->AddressOfFunctions);
//函数的地址(RVA)
AddressOfNames = (UINT32*)((char*)MappingBaseAddress + ImageExportDirectory->AddressOfNames);;
//函数名字的地址(RVA)
AddressOfNameOrdinals = (UINT16*)((char*)MappingBaseAddress + ImageExportDirectory->AddressOfNameOrdinals);
//有名字的序号的首地址(RVA)
for (i = ; i < ImageExportDirectory->NumberOfNames; i++)
{
v1 = (char*)((char*)MappingBaseAddress + AddressOfNames[i]); //可以这样写 ImageExportDirectory->AddressOfNames + i * 4
if (_stricmp(szFuntionName, v1) == )
{
OrdinalOfFunction = AddressOfNameOrdinals[i];
AddressOfFunction = (PVOID)((char*)MappingBaseAddress + AddressOfFunctions[OrdinalOfFunction]);//AddressOfFunctions[AddressOfNameOrdinals[i]]
*SSDTFunctionIndex = *(ULONG32*)((char*)AddressOfFunction + Offset_SSDTFunctionIndex);
break;
}
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{}
}
ZwUnmapViewOfSection(NtCurrentProcess(), MappingBaseAddress);
if (*SSDTFunctionIndex == -)
{
return FALSE;
}
return TRUE;
} BOOLEAN Ring0MappingPEFile(WCHAR* szFileFullPath, PVOID* MappingBaseAddress, ULONG_PTR* MappingViewSize)
{
UNICODE_STRING v1;
OBJECT_ATTRIBUTES oa;
NTSTATUS Status;
HANDLE hFile = NULL;
HANDLE hSection = NULL;
IO_STATUS_BLOCK IoStatusBlock;
if (!szFileFullPath&&MmIsAddressValid(szFileFullPath))
{
return FALSE;
}
if (!MappingBaseAddress&&MmIsAddressValid(MappingBaseAddress))
{
return FALSE;
}
RtlUnicodeStringInit(&v1, szFileFullPath);
InitializeObjectAttributes(&oa,
&v1,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL
);
Status = IoCreateFile(&hFile,
GENERIC_READ | SYNCHRONIZE,
&oa,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
,
CreateFileTypeNone,
NULL,
IO_NO_PARAMETER_CHECKING);
if (!NT_SUCCESS(Status))
{
return FALSE;
}
oa.ObjectName = NULL;
Status = ZwCreateSection(&hSection,
SECTION_QUERY | SECTION_MAP_READ,
&oa,
NULL,
PAGE_WRITECOPY,
SEC_IMAGE,
hFile);
ZwClose(hFile);
if (!NT_SUCCESS(Status))
{
return FALSE;
}
Status = ZwMapViewOfSection(hSection,
NtCurrentProcess(),
MappingBaseAddress,
,
,
,
MappingViewSize,
ViewUnmap, //不能被映射到子进程中
,
PAGE_WRITECOPY
);
ZwClose(hSection);
if (!NT_SUCCESS(Status))
{
return FALSE;
}
return TRUE;
} BOOLEAN ResumeSSDTInWin7(ULONG_PTR SSDTAddress, ULONG_PTR ModuleBase, ULONG32 SSDTFunctionIndex, ULONG32 ParameterCount)
{
PUCHAR RVAOfSSDTBase = ;
PVOID szBuffer = NULL;
PVOID PresupposeOfImageBase = ;
PVOID AddressOfSSDTBaseInFile = ;
PVOID Temp = ;
CHAR TempByte = ;
CHAR Bits[] = { };
ULONG32 HookedOffset = ;
PIMAGE_DOS_HEADER Image_Dos_Header = NULL;
PIMAGE_NT_HEADERS Image_Nt_Headers = NULL;
PIMAGE_OPTIONAL_HEADER OptionalHeader = NULL;
PIMAGE_SECTION_HEADER SectionHeader = NULL;
WCHAR wzFileFullPath[0x100] = L"\\SystemRoot\\System32\\"; // C:\\
int i = ;
wcscat(wzFileFullPath, __wzNtosName);
RVAOfSSDTBase = (PUCHAR)(((PSYSTEM_SERVICE_DESCRIPTOR_TABLE)SSDTAddress)->ServiceTableBase) - (PUCHAR)ModuleBase;
if (ReadingFileInRing0Space(wzFileFullPath, &szBuffer) == FALSE)
{
return FALSE;
}
Image_Dos_Header = (PIMAGE_DOS_HEADER)szBuffer;
Image_Nt_Headers = (PIMAGE_NT_HEADERS)(Image_Dos_Header->e_lfanew + (PUCHAR)szBuffer);
OptionalHeader = &(Image_Nt_Headers->OptionalHeader);
PresupposeOfImageBase = OptionalHeader->ImageBase; //64位为0x00000001`40000000,假想值,希望EXE文件加载到内存后就是这个值,并且文件中所有的机器码都是按照这个地址对齐的 SectionHeader = (PIMAGE_SECTION_HEADER)((char*)Image_Nt_Headers + sizeof(IMAGE_NT_HEADERS));
for (i = ; i < Image_Nt_Headers->FileHeader.NumberOfSections; i++)
{
if (RVAOfSSDTBase >= SectionHeader[i].VirtualAddress && RVAOfSSDTBase < (SectionHeader[i].VirtualAddress + SectionHeader[i].SizeOfRawData))
{ //内存映像中的RVA
AddressOfSSDTBaseInFile = (PVOID)((PUCHAR)szBuffer + (RVAOfSSDTBase - (PUCHAR)(SectionHeader[i].VirtualAddress)) + (SectionHeader[i].PointerToRawData));
break;
} //0xfffff7fe`c3e5a040
}
Temp = (PUCHAR)(((PULONG_PTR)AddressOfSSDTBaseInFile)[SSDTFunctionIndex]) - (PUCHAR)PresupposeOfImageBase + (PUCHAR)ModuleBase; #ifdef _WIN64
//重定位函数地址 内存中的函数地址 = 预想的函数基地址 - 预想的模块基地址 + 真实的模块基地址 预想的基地址是由操作系统自己完成,链接器在产生可执行文件的时候,是对应ImageBase来生成机器码的
Temp = (PUCHAR)Temp - (PUCHAR)(((PSYSTEM_SERVICE_DESCRIPTOR_TABLE)SSDTAddress)->ServiceTableBase);
Temp = (ULONG32)Temp << ;
//处理参数个数 if (ParameterCount > )
{
ParameterCount = ParameterCount - ;
}
else
{
ParameterCount = ;
}
memcpy(&TempByte, &Temp, );
#define SETBIT(x, y) x |= (1 << y) //将X的第Y位置1
#define CLRBIT(x,y) x&=~(1<<y) //将X的第Y位清0
#define GETBIT(x,y) (x & (1 << y)) //取X的第Y位,返回0或非0
for (i = ; i < ; i++)
{
Bits[i] = GETBIT(ParameterCount, i);
if (Bits[i])
{
SETBIT(TempByte, i);
}
else
{
CLRBIT(TempByte, i);
}
}
memcpy(&Temp, &TempByte, );
#endif // _WIN64
//获得当前已经被Hook了的地址
HookedOffset = ((PULONG32)((PSYSTEM_SERVICE_DESCRIPTOR_TABLE)SSDTAddress)->ServiceTableBase)[SSDTFunctionIndex];
if (Temp != HookedOffset)
{
WPOFF();
((PLONG32)((PSYSTEM_SERVICE_DESCRIPTOR_TABLE)SSDTAddress)->ServiceTableBase)[SSDTFunctionIndex] = (ULONG32)Temp;
WPON();
}
if (szBuffer != NULL)
{
ExFreePool(szBuffer);
szBuffer = NULL;
}
return TRUE;
} BOOLEAN ReadingFileInRing0Space(WCHAR* wzFileFullPath, PVOID* szBuffer)
{
NTSTATUS Status;
UNICODE_STRING Temp;
OBJECT_ATTRIBUTES oa;
HANDLE hFile;
IO_STATUS_BLOCK IoStatusBlock;
LARGE_INTEGER liReturnLength = { };
FILE_STANDARD_INFORMATION fsi = { };
if (wzFileFullPath == NULL&&*szBuffer != NULL)
{
return FALSE;
}
RtlUnicodeStringInit(&Temp, wzFileFullPath);
InitializeObjectAttributes(&oa, &Temp, OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = ZwCreateFile(&hFile,
SYNCHRONIZE, //异步
&oa,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
);
if (!NT_SUCCESS(Status))
{
return FALSE;
}
Status = ZwQueryInformationFile(hFile,
&IoStatusBlock,
&fsi,
sizeof(FILE_STANDARD_INFORMATION),
FileStandardInformation);
if (!NT_SUCCESS(Status))
{
ZwClose(hFile);
return FALSE;
}
*szBuffer = ExAllocatePool(PagedPool, fsi.EndOfFile.LowPart);
if (*szBuffer == NULL)
{
ZwClose(hFile);
return FALSE;
}
Status = ZwReadFile(hFile,
NULL,
NULL,
NULL,
&IoStatusBlock,
*szBuffer,
fsi.EndOfFile.LowPart,
&liReturnLength,
NULL); if (!NT_SUCCESS(Status))
{
ExFreePool(*szBuffer);
ZwClose(hFile);
return FALSE;
}
ZwClose(hFile);
return TRUE;
} VOID WPOFF()
{
_disable();
__writecr0(__readcr0() & (~(0x10000))); }
VOID WPON()
{
__writecr0(__readcr0() ^ 0x10000);
_enable();
}
ResumeSSDT.c
这几个终于做完了,做驱动的代码,我感觉有个坑,因为内核的地址都比较大,都达到0xFFFF8000_00000000以上了,所以一般如果表示成十进制有符号数,都是负数了,你如果直接和某个数加,如果这个数是ULONG类型的,则那个地址必须转换了,就出错了,看下面的例子:
PointerToRawData是ULONG类型,如果前面几个变量用PCHAR的话,根据C语言的默认的强制类型转换规则,char,short --> int --> unsigned --> long --> double <-- float。 内核层的地址都成负数了,一加肯定错了,坑了好几次,引以为戒吧。
最后如果我哪里有理解错的地方,欢迎大家指正,我将虚心求教。