#include "HookSSDT.h"
#include <ntimage.h>
#define SEC_IMAGE 0x001000000
ULONG32 __NtOpenProcessIndex = 0;
PVOID __ServiceTableBase = NULL;
ULONG32 __OldNtOpenProcessOffset = 0;
PVOID __OldNtOpenProcess = NULL;
UCHAR __OldCode[15] = {0};
BOOLEAN __IsHook = FALSE;
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegisterPath)
{
NTSTATUS Status = STATUS_SUCCESS;
ULONG32 v1 = 0;
char FunctionName[] = "NtOpenProcess";
ULONG64 SSDTAddress = 0;
DriverObject->DriverUnload = DriverUnload;
if (GetSSDTAddress(&SSDTAddress) == FALSE)
{
return Status;
}
DbgPrint("Win7x64 SSDT:%p\r\n", SSDTAddress);
//寻找23H
if (GetSSDTFunctionIndexFromNtdllExportTableByFunctionName(FunctionName,
&__NtOpenProcessIndex) == FALSE)
{
return STATUS_UNSUCCESSFUL;
}
__ServiceTableBase = ((PSERVER_SERVICE_DESCRIPTOR_TABLE)SSDTAddress)->Unknow0;
__OldNtOpenProcessOffset = ((PULONG32)__ServiceTableBase)[__NtOpenProcessIndex];
v1 = __OldNtOpenProcessOffset >> 4;
__OldNtOpenProcess = (PVOID)((ULONG64)__ServiceTableBase + v1);
HookSSDT(__ServiceTableBase,__NtOpenProcessIndex,FakeOpenProcess,KeBugCheckEx,5,__OldCode,15);
return Status;
}
BOOLEAN GetSSDTAddress(ULONG64* SSDTAddress)
{
//kd> rdmsr c0000082
PUCHAR StartSearchAddress = (PUCHAR)__readmsr(0xC0000082);
PUCHAR EndSearchAddress = StartSearchAddress + PAGE_SIZE;
PUCHAR i = NULL;
UCHAR v1 = 0, v2 = 0, v3 = 0;
INT64 Offset = 0; //002320c7
ULONG64 VariableAddress = 0;
*SSDTAddress = NULL;
for (i = StartSearchAddress; i < EndSearchAddress; i++)
{
if (MmIsAddressValid(i) && MmIsAddressValid(i + 1) && MmIsAddressValid(i + 2))
{
v1 = *i;
v2 = *(i + 1);
v3 = *(i + 2);
if (v1 == 0x4c && v2 == 0x8d && v3 == 0x15)
{
memcpy(&Offset, i + 3, 4);
*SSDTAddress = Offset + (ULONG64)i + 7;
break;
}
}
}
//Win32 导出表 搜索 KeServiceDescriptorTable
if (*SSDTAddress == NULL)
{
return FALSE;
}
return TRUE;
}
BOOLEAN GetSSDTFunctionIndexFromNtdllExportTableByFunctionName(CHAR* FunctionName,ULONG32* SSDTFunctionIndex)
{
/*
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]
*/
ULONG i;
BOOLEAN IsOk = FALSE;
WCHAR FileFullPath[] = L"\\SystemRoot\\System32\\ntdll.dll"; //C:\Windows\
SIZE_T MappingViewSize = 0;
PVOID MappingBaseAddress = NULL;
PIMAGE_EXPORT_DIRECTORY ImageExportDirectory = NULL;
PIMAGE_NT_HEADERS NtHeader = NULL;
UINT32* AddressOfFunctions = NULL;
UINT32* AddressOfNames = NULL;
UINT16* AddressOfNameOrdinals = NULL;
CHAR* v1 = NULL;
ULONG32 FunctionOrdinal = 0;
PVOID FunctionAddress = 0;
ULONG32 Offset_SSDTFunctionIndex = 4;
//将Ntdll.dll 当前的空间中
*SSDTFunctionIndex = -1;
IsOk = MappingPEFileInRing0Space(FileFullPath,&MappingBaseAddress, &MappingViewSize);
if (IsOk==FALSE)
{
return FALSE;
}
else
{
__try{
NtHeader = RtlImageNtHeader(MappingBaseAddress); //extern
if (NtHeader && NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress)
{
ImageExportDirectory =(IMAGE_EXPORT_DIRECTORY*)((UINT8*)MappingBaseAddress +
NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
//AddressOfFunctions 指向函数地址数组
AddressOfFunctions = (UINT32*)((UINT8*)MappingBaseAddress + ImageExportDirectory->AddressOfFunctions);
AddressOfNames = (UINT32*)((UINT8*)MappingBaseAddress + ImageExportDirectory->AddressOfNames);
AddressOfNameOrdinals = (UINT16*)((UINT8*)MappingBaseAddress + ImageExportDirectory->AddressOfNameOrdinals);
for(i = 0; i < ImageExportDirectory->NumberOfNames; i++)
{
v1 = (char*)((ULONG64)MappingBaseAddress + AddressOfNames[i]); //获得函数名称
if (_stricmp(FunctionName, v1) == 0)
{
FunctionOrdinal = AddressOfNameOrdinals[i];
FunctionAddress = (PVOID)((UINT8*)MappingBaseAddress + AddressOfFunctions[FunctionOrdinal]);
*SSDTFunctionIndex = *(ULONG32*)((UINT8*)FunctionAddress+Offset_SSDTFunctionIndex);
break;
}
}
}
}__except(EXCEPTION_EXECUTE_HANDLER)
{
;
}
}
ZwUnmapViewOfSection(NtCurrentProcess(), MappingBaseAddress); //解除映射
if (*SSDTFunctionIndex==-1)
{
return FALSE;
}
return TRUE;
}
BOOLEAN
MappingPEFileInRing0Space(WCHAR* FileFullPath,PVOID* MappingBaseAddress, PSIZE_T MappingViewSize)
{
NTSTATUS Status;
UNICODE_STRING v1;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
HANDLE FileHandle = NULL;
HANDLE SectionHandle = NULL;
if (!FileFullPath &&MmIsAddressValid(FileFullPath))
{
return FALSE;
}
if (!MappingBaseAddress&&MmIsAddressValid(MappingBaseAddress))
{
return FALSE;
}
RtlInitUnicodeString(&v1, FileFullPath);
//初始化一个OBJECT_ATTRIBUTES结构体ObjectAttributes,它指定对象句柄的属性,供打开句柄的例程使用。
//驱动程序运行进程上下文中,若要运行在系统进程,需要设置OBJ_KERNEL_HANDLE标志到Attributes参数。
//OBJ_KERNEL_HANDLE标志限制,使用此打开的句柄的进程仅能运行在内核模式。否则句柄可以在驱动运行的进程上下文中访问。
InitializeObjectAttributes(&ObjectAttributes,
&v1,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL
);
//传递ObjectAttributes结构的指针到实际打开句柄的例程
//获得文件句柄
Status = IoCreateFile(&FileHandle,
GENERIC_READ | SYNCHRONIZE,
&ObjectAttributes, //文件绝对路径
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0,
CreateFileTypeNone,
NULL,
IO_NO_PARAMETER_CHECKING
);
if (!NT_SUCCESS(Status))
{
return FALSE;
}
ObjectAttributes.ObjectName = NULL;
//创建一个Section Object ,即共享内存
Status = ZwCreateSection(&SectionHandle,
SECTION_QUERY | SECTION_MAP_READ,
&ObjectAttributes,
NULL,
PAGE_WRITECOPY,
SEC_IMAGE, //内存对齐 0x1000
FileHandle
);
/*NTSTATUS ZwCreateSection(
OUT PHANDLE SectionHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN PLARGE_INTEGER MaximumSize OPTIONAL,
IN ULONG SectionPageProtection,
IN ULONG AllocationAttributes,
IN HANDLE FileHandle OPTIONAL
);*/
ZwClose(FileHandle);
if (!NT_SUCCESS(Status))
{
return FALSE;
}
//生成一个可以访问的MappingBaseAddress
Status = ZwMapViewOfSection(SectionHandle,
NtCurrentProcess(), //映射到当前进程的内存空间中
MappingBaseAddress,
0,
0,
0,
MappingViewSize,
ViewUnmap,
0,
PAGE_WRITECOPY
);
ZwClose(SectionHandle);
if (!NT_SUCCESS(Status))
{
return FALSE;
}
return TRUE;
}
VOID HookSSDT(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex,PVOID FakeFunctionAddress,
PVOID OldFunctionAddress,ULONG32 OldFunctionParameterCount,UCHAR* OldFunctionCode,ULONG32 PatchCodeLength)
{
//寻找一个内核不常用的函数(KeBugCheckEx) 进行InlineHook使其跳转到Fake_NtOpenProcess函数
ULONG32 v1 = 0;
WPOFF();
// KeBugCheckEx
// mov rax,10 Jmp Fake 15
// mov rbx,rax
InlineHook(OldFunctionAddress, FakeFunctionAddress, OldFunctionCode, PatchCodeLength);
WPON();
//寻找一个内核不常用的函数(KeBugCheckEx) 计算SSDT中的偏移 进行置换
v1 = CalcFunctionOffsetInSSDT(ServiceTableBase,OldFunctionAddress, OldFunctionParameterCount);
WPOFF();
((PULONG32)ServiceTableBase)[SSDTFunctionIndex] = (ULONG32)v1;
WPON();
__IsHook = TRUE;
}
VOID
UnHookSSDT(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex,ULONG32 OldFunctionOffset,PVOID OldFunctionAddress,
UCHAR* OldFunctionCode,ULONG32 PatchCodeLength)
{
WPOFF();
UnInlineHook(OldFunctionAddress, OldFunctionCode, PatchCodeLength);
WPON();
WPOFF();
((PULONG32)ServiceTableBase)[SSDTFunctionIndex] = (ULONG32)OldFunctionOffset;
WPON();
}
VOID InlineHook(ULONG64 OldFunctionAddress, ULONG64 FakeFunctionAddress, UCHAR* OldFunctionCode, ULONG32 PatchCodeLength)
{
ULONG64 v1 = 0;
UCHAR PatchCode[] = "\xFF\x25\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"; //InlineHook Jmp 函数地址
v1 = FakeFunctionAddress;
memcpy(OldFunctionCode, (PVOID)OldFunctionAddress, PatchCodeLength); //保存原先函数的指令
memcpy(PatchCode + 6, &v1, 8);
memset((PVOID)OldFunctionAddress, 0x90, PatchCodeLength); //打补丁 NOP = 0x90
memcpy((PVOID)OldFunctionAddress, PatchCode, 14);
}
VOID UnInlineHook(PVOID OldFunctionAddress, UCHAR* OldFunctionCode, ULONG32 PatchCodeLength)
{
memcpy((PVOID)OldFunctionAddress, OldFunctionCode, PatchCodeLength);
}
ULONG32 CalcFunctionOffsetInSSDT(PVOID ServiceTableBase, PVOID FunctionAddress,ULONG32 ParameterCount)
{
//v1 : INT8 Temp = 0
CHAR v1 = 0;
CHAR Bits[4] = {0};
ULONG32 v2 = 0,i;
v2 = (ULONG32)((ULONG64)FunctionAddress-(ULONG64)ServiceTableBase);
v2 = v2<<4; //0110 0001 a1 ----> 0001 0000
if(ParameterCount>4)
{
ParameterCount = ParameterCount-4; //NtReadFile 9个参数
}
else
{
ParameterCount = 0;
}
memcpy(&v1,&v2,1);
//处理低四位,填写参数个数 如果一个函数的参数为5 那么dwTemp的低4位就是 0001 如果参数是6 就是0002 因为 6要减4
#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=0;i<4;i++) //一个16进制 4个二进制 0000
{
Bits[i]=GETBIT(ParameterCount,i);
if(Bits[i])
{
SETBIT(v1,i);
}
else
{
CLRBIT(v1,i);
}
}
/*
ulParamCount i Bits[i] b i b
0101 0 1 0000 0 0001 set
0101 1 0 0001 1 0001 clr
0101 2 1 0001 2 0101 set
0101 3 0 0101 3 0101 clr
*/
//把数据复制回去
memcpy(&v2,&v1,1);
return v2;
}
NTSTATUS FakeOpenProcess(
_Out_ PHANDLE ProcessHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_opt_ PCLIENT_ID ClientID)
{
//EnumProcessByForce.exe
//OpenProcess---->Ntdll(ZwOpenProcess eax,23H syscall)----->NtosKrnl.exe(ZwOpenProcss eax,23H SSDT[23H])----->KeCheckBugEx---->Jmp FakeOpenProcess
PEPROCESS EProcess = PsGetCurrentProcess(); //EnumProcessByForce进程上下背景文
if (EProcess != NULL&&MmIsAddressValid(EProcess))
{
//通过EProcess 获得进程名称
char *ProcessImageName = PsGetProcessImageFileName(EProcess); //0x2e0
if (strstr(ProcessImageName, "EnumProcess") != 0)
{
return STATUS_ACCESS_DENIED; //黑名单
}
}
((pfnNtOpenProcess)__OldNtOpenProcess)(ProcessHandle, DesiredAccess, ObjectAttributes, ClientID); //白名单
}
VOID WPOFF()
{
_disable();
__writecr0(__readcr0() & (~(0x10000)));
}
VOID WPON()
{
__writecr0(__readcr0() ^ 0x10000);
_enable();
}
VOID DriverUnload(PDRIVER_OBJECT DriverObject)
{
DbgPrint("ByeByeDriver\r\n");
if (__IsHook)
{
UnHookSSDT(__ServiceTableBase, __NtOpenProcessIndex, __OldNtOpenProcessOffset, KeBugCheckEx,
__OldCode, 15);
__IsHook = FALSE;
}
}
#pragma once
#include <ntddk.h>
typedef struct _SERVER_SERVICE_DESCRIPTOR_TABLE_
{
PVOID Unknow0;
PVOID Unknow1;
PVOID Unknow2;
PVOID Unknow3;
}SERVER_SERVICE_DESCRIPTOR_TABLE, *PSERVER_SERVICE_DESCRIPTOR_TABLE;
typedef
NTSTATUS(*pfnNtOpenProcess)(
_Out_ PHANDLE ProcessHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_opt_ PCLIENT_ID ClientID);
extern
PIMAGE_NT_HEADERS
NTAPI
RtlImageNtHeader(PVOID BaseAddress);
extern
char* PsGetProcessImageFileName(PEPROCESS EProcess);
BOOLEAN GetSSDTFunctionIndexFromNtdllExportTableByFunctionName(
CHAR* FunctionName,
ULONG32* SSDTFunctionIndex);
BOOLEAN
MappingPEFileInRing0Space(WCHAR* FileFullPath, PVOID* MappingBaseAddress, PSIZE_T MappingViewSize);
BOOLEAN GetSSDTAddress(ULONG64* SSDTAddress);
VOID HookSSDT(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, PVOID FakeFunctionAddress);
ULONG32 CalcFunctionOffsetInSSDT(PVOID ServiceTableBase, PVOID FunctionAddress, ULONG32 ParameterCount);
VOID HookSSDT(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, PVOID FakeFunctionAddress,
PVOID OldFunctionAddress, ULONG32 OldFunctionParameterCount, UCHAR* OldFunctionCode, ULONG32 PatchCodeLength);
VOID
UnHookSSDT(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, ULONG32 OldFunctionOffset, PVOID OldFunctionAddress,
UCHAR* OldFunctionCode, ULONG32 PatchCodeLength);
VOID InlineHook(ULONG64 OldFunctionAddress, ULONG64 FakeFunctionAddress, UCHAR* OldFunctionCode, ULONG32 PatchCodeLength);
VOID UnInlineHook(PVOID OldFunctionAddress, UCHAR* OldFunctionCode, ULONG32 PatchCodeLength);
NTSTATUS FakeOpenProcess(
_Out_ PHANDLE ProcessHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_opt_ PCLIENT_ID ClientID);
VOID WPOFF();
VOID WPON();
VOID DriverUnload(PDRIVER_OBJECT DriverObject);