Rootkit之SSDT hook(通过CR0)
SSDT即System Service Dispath Table,它是一个表,这个表中有内核调用的函数地址。
KeServiceDescriptorTable:是由内核(Ntoskrnl.exe)导出的一个表,这个表是访问SSDT的关键,具体结构是
typedef struct ServiceDescriptorTable {
PVOID ServiceTableBase;
PVOID ServiceCounterTable(0);
unsigned int NumberOfServices;
PVOID ParamTableBase;
}
其中,
ServiceTableBase System Service Dispatch Table 的基地址。
NumberOfServices 由 ServiceTableBase 描述的服务的数目。
ServiceCounterTable 此域用于操作系统的 checked builds,包含着 SSDT 中每个服务被调用次数的计数器。这个计数器由 INT 2Eh 处理程序 (KiSystemService)更新。
ParamTableBase 包含每个系统服务参数字节数表的基地址。
CR0当中有一个写保护位,是保护内存不可写属性的,为了能够写入内核,只能把它的保护给咔嚓掉了,不过……如果做完了手脚但不还原写保护属性的话,极有可能会BOSD.
代码实例如下:
#include <NTDDK.h>
#pragma pack(1)
typedef struct ServiceDescriptorEntry {
unsigned int *ServiceTableBase;
unsigned int *ServiceCounterTableBase; //Used only in checked build
unsigned int NumberOfServices;
unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry, *PServiceDescriptorTableEntry;
#pragma pack()
_declspec(dllimport) ServiceDescriptorTableEntry
KeServiceDescriptorTable;
NTSYSAPI NTSTATUS ZwOpenProcess(OUT PHANDLE ProcessHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PCLIENT_ID ClientId);
typedef NTSTATUS (*ZWOPENPROCESS)(OUT PHANDLE ProcessHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PCLIENT_ID ClientId);
#define SYSTEMSERVICE(_function)
KeServiceDescriptorTable.ServiceTableBase[*(PULONG)((PUCHAR)_function + 1)]
ZWOPENPROCESS OldZwOpenProcess;
NTSTATUS MyZwOpenProcess(PHANDLE ProcessHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
PCLIENT_ID ClientId)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
KdPrint(("MyZwOpenProcess\r\n"));
//调用原来的NtOpenProcess;
ntStatus = OldZwOpenProcess(ProcessHandle, DesiredAccess, ObjectAttributes, ClientId);
return ntStatus;
}
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
__asm{//去掉内存保护
cli
mov eax,cr0
and eax,not 10000h
mov cr0,eax
}
(ZWOPENPROCESS)SYSTEMSERVICE(ZwOpenProcess) = OldZwOpenProcess;//恢复HOOK SSDT
__asm{//恢复内存保护
mov eax,cr0
or eax,10000h
mov cr0,eax
sti
}
KdPrint(("驱动卸载完毕!\r\n"));
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING pRegistryPath)
{
NTSTATUS status = STATUS_SUCCESS;
KdPrint(("The driver begin loading.\r\n"));
DriverObject->DriverUnload = DriverUnload;
OldZwOpenProcess = (ZWOPENPROCESS)SYSTEMSERVICE(ZwOpenProcess);
__asm{//去掉内存保护
cli
mov eax,cr0
and eax,not 10000h
mov cr0,eax
}
(ZWOPENPROCESS)SYSTEMSERVICE(ZwOpenProcess) = MyZwOpenProcess;
//HOOK SSDT
__asm{//恢复内存保护
mov eax,cr0
or eax,10000h
mov cr0,eax
sti
}
KdPrint(("The driver ends loading\r\n"));
return status;
}
KeServiceDescriptorTable:是由内核(Ntoskrnl.exe)导出的一个表,这个表是访问SSDT的关键,具体结构是
typedef struct ServiceDescriptorTable {
PVOID ServiceTableBase;
PVOID ServiceCounterTable(0);
unsigned int NumberOfServices;
PVOID ParamTableBase;
}
其中,
ServiceTableBase System Service Dispatch Table 的基地址。
NumberOfServices 由 ServiceTableBase 描述的服务的数目。
ServiceCounterTable 此域用于操作系统的 checked builds,包含着 SSDT 中每个服务被调用次数的计数器。这个计数器由 INT 2Eh 处理程序 (KiSystemService)更新。
ParamTableBase 包含每个系统服务参数字节数表的基地址。
CR0当中有一个写保护位,是保护内存不可写属性的,为了能够写入内核,只能把它的保护给咔嚓掉了,不过……如果做完了手脚但不还原写保护属性的话,极有可能会BOSD.
代码实例如下:
#include <NTDDK.h>
#pragma pack(1)
typedef struct ServiceDescriptorEntry {
unsigned int *ServiceTableBase;
unsigned int *ServiceCounterTableBase; //Used only in checked build
unsigned int NumberOfServices;
unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry, *PServiceDescriptorTableEntry;
#pragma pack()
_declspec(dllimport) ServiceDescriptorTableEntry
KeServiceDescriptorTable;
NTSYSAPI NTSTATUS ZwOpenProcess(OUT PHANDLE ProcessHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PCLIENT_ID ClientId);
typedef NTSTATUS (*ZWOPENPROCESS)(OUT PHANDLE ProcessHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PCLIENT_ID ClientId);
#define SYSTEMSERVICE(_function)
KeServiceDescriptorTable.ServiceTableBase[*(PULONG)((PUCHAR)_function + 1)]
ZWOPENPROCESS OldZwOpenProcess;
NTSTATUS MyZwOpenProcess(PHANDLE ProcessHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
PCLIENT_ID ClientId)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
KdPrint(("MyZwOpenProcess\r\n"));
//调用原来的NtOpenProcess;
ntStatus = OldZwOpenProcess(ProcessHandle, DesiredAccess, ObjectAttributes, ClientId);
return ntStatus;
}
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
__asm{//去掉内存保护
cli
mov eax,cr0
and eax,not 10000h
mov cr0,eax
}
(ZWOPENPROCESS)SYSTEMSERVICE(ZwOpenProcess) = OldZwOpenProcess;//恢复HOOK SSDT
__asm{//恢复内存保护
mov eax,cr0
or eax,10000h
mov cr0,eax
sti
}
KdPrint(("驱动卸载完毕!\r\n"));
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING pRegistryPath)
{
NTSTATUS status = STATUS_SUCCESS;
KdPrint(("The driver begin loading.\r\n"));
DriverObject->DriverUnload = DriverUnload;
OldZwOpenProcess = (ZWOPENPROCESS)SYSTEMSERVICE(ZwOpenProcess);
__asm{//去掉内存保护
cli
mov eax,cr0
and eax,not 10000h
mov cr0,eax
}
(ZWOPENPROCESS)SYSTEMSERVICE(ZwOpenProcess) = MyZwOpenProcess;
//HOOK SSDT
__asm{//恢复内存保护
mov eax,cr0
or eax,10000h
mov cr0,eax
sti
}
KdPrint(("The driver ends loading\r\n"));
return status;
}