也谈SSDT Hook(二)
一、實戰篇
本不想摘代碼,既然實戰,就不多講廢話了,還是貼上吧,誰都有違背原則的時候:)。
代碼一:經典案例,替換NtQuerySystemInformation,列取所有查詢到的進程名,我使用修改CR0寄存器的方法。
#include <ntddk.h>
?
typedef struct _SYSTEM_THREADS
{
??? LARGE_INTEGER KernelTime;
??? LARGE_INTEGER UserTime;
??? LARGE_INTEGER CreateTime;
??? ULONG WaitTime;
??? PVOID StartAddress;
??? CLIENT_ID ClientIs;
??? KPRIORITY Priority;
??? KPRIORITY BasePriority;
??? ULONG ContextSwitchCount;
??? ULONG ThreadState;
??? KWAIT_REASON WaitReason;
}SYSTEM_THREADS, *PSYSTEM_THREADS;
?
typedef struct _SYSTEM_PROCESSES
{
??? ULONG NextEntryDelta;
??? ULONG ThreadCount;
??? ULONG Reserved[6];
??? LARGE_INTEGER CreateTime;
??? LARGE_INTEGER UserTime;
??? LARGE_INTEGER KernelTime;
??? UNICODE_STRING ProcessName;
??? KPRIORITY BasePriority;
??? ULONG ProcessId;
??? ULONG InheritedFromProcessId;
??? ULONG HandleCount;
??? ULONG Reserved2[2];
??? VM_COUNTERS VmCounters;
??? IO_COUNTERS IoCounters;
??? struct _SYSTEM_THREADS Threads[1];
}SYSTEM_PROCESSES, *PSYSTEM_PROCESSES;
?
NTSYSAPI NTSTATUS NTAPI ZwQuerySystemInformation(
??????? IN ULONG SystemInformationClass,
??????? IN PVOID SystemInformation,
??????? IN ULONG SystemInformationLength,
??????? OUT PULONG ReturnLength);
?
NTSTATUS NewNtQuerySystemInformation(
??????? IN ULONG SystemInformationClass,
??????? IN PVOID SystemInformation,
??????? IN ULONG SystemInformationLength,
??????? OUT PULONG ReturnLength);
?
// SDT Structure
typedef struct _ServiceDescriptorTableEntry
{
??? unsigned int *ServiceTableBase;
??? unsigned int *ServiceCounterTableBase;
??? unsigned int NumberOfServices;
??? unsigned char *ParamTableBase;
}ServiceDescriptorTableEntry, *PServiceDescriptorTableEntry;
?
// import KeServiceDescriptorTable
extern PServiceDescriptorTableEntry KeServiceDescriptorTable;
PServiceDescriptorTableEntry pSDT;
?
// real NtQuerySystemInformation
typedef NTSTATUS (*NTQUERYSYSTEMINFORMATION)(
???????????????????????????? IN ULONG SystemInformationClass,
???????????????????????????? IN PVOID SystemInformation,
???????????????????????????? IN ULONG SystemInformationLength,
???????????????????????????? OUT PULONG ReturnLength);
NTQUERYSYSTEMINFORMATION OldNtQuerySystemInformation;
?
UNICODE_STRING usLinkDeviceNameString;
?
VOID UnloadDriver(IN PDRIVER_OBJECT pDriverObject)
{
??? ULONG _cr0;
??? PDEVICE_OBJECT pDeviceObject;
?
??? // recovery SSDT
??? _asm
??? {
??????? // WP off
??????? cli
??????? mov eax, cr0
??????? mov _cr0, eax
??????? and eax, 0fffeffffh
??????? mov cr0,eax
??????? // recovery SSDT
??????? mov ecx, DWORD PTR [ZwQuerySystemInformation]
??????? mov edx, [ecx+1]
??????? mov eax, DWORD PTR [pSDT];
??????? mov esi, [eax]
??????? mov ebx, DWORD PTR [OldNtQuerySystemInformation]
??????? mov [esi+edx*4],ebx
??????? // WP on
??????? mov eax, _cr0
??????? mov cr0, eax
??????? sti
??? }
?
??? pDeviceObject= pDriverObject->DeviceObject;
??? IoDeleteSymbolicLink(&usLinkDeviceNameString);
??? ASSERT(!pDeviceObject->AttachedDevice);
??? if ( pDeviceObject != NULL )
??? {
??????? IoDeleteDevice(pDeviceObject);
??? }
?
}
?
NTSTATUS DriverEntry (IN PDRIVER_OBJECT pDriverObject,IN PUNICODE_STRING usRegistryPath)
{
??? ULONG _cr0;
??? NTSTATUS ntStatus;
??? PDEVICE_OBJECT pDeviceObject;
??? UNICODE_STRING usDeviceNameString;
?
??? RtlInitUnicodeString(&usDeviceNameString, L"//Device//SSDTHOOK" );
??? RtlInitUnicodeString(&usLinkDeviceNameString, L"//DosDevices//SSDTHOOK" );
?
??? ntStatus = IoCreateDevice(
??????????????? pDriverObject,
??????????????? 0,
??????????????? &usDeviceNameString,
??????????????? FILE_DEVICE_DISK_FILE_SYSTEM,
??????????????? FILE_DEVICE_SECURE_OPEN,
??????????????? FALSE,
??????????????? &pDeviceObject);
?
??? if (!NT_SUCCESS(ntStatus))
??? {
??????? return ntStatus;
??? }
?
??? ntStatus = IoCreateSymbolicLink(&usLinkDeviceNameString,&usDeviceNameString);
?
??? if (!NT_SUCCESS(ntStatus))
??? {
??????? IoDeleteDevice(pDeviceObject);
??????? return ntStatus;
??? }
??? pDriverObject->DriverUnload=UnloadDriver;
???
??? pSDT = KeServiceDescriptorTable;
??? // modify SSDT
??? _asm
??? {
??????? // WP off
??????? cli
??????? mov eax, cr0
??????? mov _cr0, eax
??????? and eax, 0fffeffffh
??????? mov cr0, eax
??????? // replace NtQuerySystemInformation with NewNtQuerySystemInformation
??????? mov ecx, DWORD PTR [ZwQuerySystemInformation]
??????? mov edx, [ecx+1]
??????? mov eax, DWORD PTR [pSDT]
??????? mov esi, [eax]
??????? mov edx, [esi+edx*4]
??????? mov DWORD PTR [OldNtQuerySystemInformation], edx
??????? mov ecx, [ecx+1]
??????? mov eax, [eax]
??????? mov dword ptr [eax+ecx*4], offset NewNtQuerySystemInformation
??????? // WP on
??????? mov eax, _cr0
??????? mov cr0, eax
??????? sti
??? }
?
??? return ntStatus;
}
?
NTSTATUS NewNtQuerySystemInformation(
??????? IN ULONG SystemInformationClass,
??????? IN PVOID SystemInformation,
??????? IN ULONG SystemInformationLength,
??????? OUT PULONG ReturnLength)
{
??? ANSI_STRING asProcessName;
??? NTSTATUS ntQuerySystemInformation = (OldNtQuerySystemInformation)
??????????????????????????????????????? (SystemInformationClass,
???????????????????????????????????????? SystemInformation,
???????????????????????????????????????? SystemInformationLength,
???????????????????????????????????????? ReturnLength);
??? if(NT_SUCCESS(ntQuerySystemInformation))
??? {
??????? if(5 == SystemInformationClass)
??????? {
??????????? PSYSTEM_PROCESSES curr = (PSYSTEM_PROCESSES)SystemInformation;
??????????? PSYSTEM_PROCESSES prev = NULL;
??????????? if(curr->NextEntryDelta)((char *)curr += curr->NextEntryDelta);
?
??????????? while(curr)
??????????? {
??????????????? RtlUnicodeStringToAnsiString(&asProcessName, &(curr->ProcessName), TRUE);
??????????????? DbgPrint(asProcessName.Buffer);
??????????????? RtlFreeAnsiString(&asProcessName);
??????????????? if(curr != NULL)
??????????????? {
??????????????????? prev = curr;
??????????????????? if(curr->NextEntryDelta)((char *)curr += curr->NextEntryDelta);
??????????????????? else curr = NULL;
??????????????? }
??????????? }
?????? ?}
??? }
??? return ntQuerySystemInformation;
}
?
案例二:修改SDT中NtCreateSection的地址,列出所有創建SECTION的文件名稱,我使用了MDL。其實,搞進程很麻煩凡的,windows的大麻煩之一。
#include <ntddk.h>
?
NTSYSAPI
NTSTATUS
NTAPI 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);
?
NTSTATUS NewNtCreateSection(
??? OUT PHANDLE SectionHandle,
??? IN ULONG DesiredAccess,
??? IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
??? IN PLARGE_INTEGER MaximumSize OPTIONAL,
??? IN ULONG PageAttributess,
??? IN ULONG SectionAttributes,
??? IN HANDLE FileHandle OPTIONAL);
?
// SDT Structure
#pragma pack(1)
typedef struct _ServiceDescriptorTableEntry
{
??? unsigned int *ServiceTableBase;
??? unsigned int *ServiceCounterTableBase;
??? unsigned int NumberOfServices;
??? unsigned char *ParamTableBase;
}ServiceDescriptorTableEntry, *PServiceDescriptorTableEntry;
#pragma pack()
?
__declspec(dllimport)? ServiceDescriptorTableEntry KeServiceDescriptorTable;
#define SYSTEMSERVICE(_function) KeServiceDescriptorTable.ServiceTableBase[*(PULONG)((PUCHAR)_function+1)]
?
// real NtCreateSection
typedef NTSTATUS (*NTCREATESECTION)(
??? OUT PHANDLE SectionHandle,
??? IN ULONG DesiredAccess,
??? IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
??? IN PLARGE_INTEGER MaximumSize OPTIONAL,
??? IN ULONG PageAttributess,
??? IN ULONG SectionAttributes,
??? IN HANDLE FileHandle OPTIONAL);
NTCREATESECTION OldNtCreateSection;
?
UNICODE_STRING usLinkDeviceNameString;
?
// MDL define
PMDL? g_pmdlSystemCall;
PVOID *pMappedSystemCallTable;
#define SYSCALL_INDEX(_Function) *(PULONG)((PUCHAR)_Function+1)
#define HOOK_SYSCALL(_Function, _Hook, _Orig)/
?????? _Orig = (PVOID) InterlockedExchange( (PLONG) &pMappedSystemCallTable[SYSCALL_INDEX(_Function)], (LONG) _Hook)
?
#define UNHOOK_SYSCALL(_Function, _Hook, _Orig)/
?????? InterlockedExchange( (PLONG) &pMappedSystemCallTable[SYSCALL_INDEX(_Function)], (LONG) _Hook)
?
VOID UnloadDriver(IN PDRIVER_OBJECT pDriverObject)
{
??? PDEVICE_OBJECT pDeviceObject;
?
??? // recovery SSDT
??? UNHOOK_SYSCALL(ZwCreateSection, OldNtCreateSection, NewNtCreateSection);
?
??? // Unlock and Free MDL
??? if(g_pmdlSystemCall)
??? {
??????? MmUnmapLockedPages(pMappedSystemCallTable, g_pmdlSystemCall);
??????? IoFreeMdl(g_pmdlSystemCall);
??? }
???
??? pDeviceObject= pDriverObject->DeviceObject;
??? IoDeleteSymbolicLink(&usLinkDeviceNameString);
??? ASSERT(!pDeviceObject->AttachedDevice);
??? if ( pDeviceObject != NULL )
??? {
??????? IoDeleteDevice(pDeviceObject);
??? }
?
}
?
NTSTATUS DriverEntry (IN PDRIVER_OBJECT pDriverObject,IN PUNICODE_STRING usRegistryPath)
{
??? NTSTATUS ntStatus;
??? PDEVICE_OBJECT pDeviceObject;
??? UNICODE_STRING usDeviceNameString;
?
??? RtlInitUnicodeString(&usDeviceNameString, L"//Device//SSDTHOOK" );
??? RtlInitUnicodeString(&usLinkDeviceNameString, L"//DosDevices//SSDTHOOK" );
?
??? ntStatus = IoCreateDevice(
??????????????? pDriverObject,
??????????????? 0,
??????????????? &usDeviceNameString,
??????????????? FILE_DEVICE_DISK_FILE_SYSTEM,
??????????????? FILE_DEVICE_SECURE_OPEN,
??????????????? FALSE,
??????????????? &pDeviceObject);
?
??? if (!NT_SUCCESS(ntStatus))
??? {
??????? return ntStatus;
??? }
?
??? ntStatus = IoCreateSymbolicLink(&usLinkDeviceNameString,&usDeviceNameString);
?
??? if (!NT_SUCCESS(ntStatus))
??? {
??????? IoDeleteDevice(pDeviceObject);
??????? return ntStatus;
??? }
??? pDriverObject->DriverUnload=UnloadDriver;
???
??? OldNtCreateSection =(NTCREATESECTION)(SYSTEMSERVICE(ZwCreateSection));
??? g_pmdlSystemCall = MmCreateMdl(NULL, KeServiceDescriptorTable.ServiceTableBase, KeServiceDescriptorTable.NumberOfServices*4);
??? if(!g_pmdlSystemCall) return STATUS_UNSUCCESSFUL;
?
??? MmBuildMdlForNonPagedPool(g_pmdlSystemCall);
?
??? // Change the flags of the MDL
??? g_pmdlSystemCall->MdlFlags = g_pmdlSystemCall->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA;
?
??? pMappedSystemCallTable = MmMapLockedPages(g_pmdlSystemCall, KernelMode);
?
? ??// hook system calls
??? HOOK_SYSCALL(ZwCreateSection, NewNtCreateSection, OldNtCreateSection);
?
??? return ntStatus;
}
?
NTSTATUS NewNtCreateSection(
??? OUT PHANDLE SectionHandle,
??? IN ULONG DesiredAccess,
??? IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
??? IN PLARGE_INTEGER MaximumSize OPTIONAL,
??? IN ULONG PageAttributess,
??? IN ULONG SectionAttributes,
??? IN HANDLE FileHandle OPTIONAL)
{
??? HANDLE hHandle;
??? PFILE_OBJECT pFileObject;
??? OBJECT_HANDLE_INFORMATION HandleInformationObject;
??? ANSI_STRING asFileName;
???
??? hHandle=(HANDLE)FileHandle;
??? ObReferenceObjectByHandle(hHandle,0,0,KernelMode,&pFileObject,&HandleInformationObject);
??? if(pFileObject != NULL)
??? {
??????? RtlUnicodeStringToAnsiString(&asFileName,&(pFileObject->FileName),TRUE);
??????? DbgPrint(asFileName.Buffer);
??????? RtlFreeAnsiString(&asFileName);
??? }
?
??? return ((NTCREATESECTION)(OldNtCreateSection))(SectionHandle, DesiredAccess, ObjectAttributes, MaximumSize, PageAttributess, SectionAttributes, FileHandle);
}
以上兩個例子都是在XP SP2下測試,用來驗證第一部分我說的那些廢話。代碼本身沒任何破壞性,有興趣可以嘗試,如有疑問歡迎交流。
?
二、Anti-SSDT Hook
小學時,課本有一篇寓言《自相矛盾》,當時覺得不可思議,像現在想來,矛與盾的較量永未停止。對SSDT Hook最終都要修改掉KeServiceDescriptorTable的成員ServiceTableBase所指向的內存空間的Nt*系列函數地址,那么只要掃描這段內存空間,抓出非法居民即可。原理是這樣的。
先看看‘ROOTKITS: SUVVERING THE WINDOWS KERNEL’的高招。首先,獲取ntoskrnl.exe模塊的內存地址范圍,如果所檢測的SDT中的函數地址不在這個范圍內就是被HOOK了。不再重復人家的代碼了。
Tan Chew Keong在他的’Win2K/XP SDT Restore’大作中的基本思路是不變的,但是,他的SDT是在ntoskrnl.exe的原始文件中加載的,然后使用這個SDT跟操作系統內核中正在使用的那個進行對比,這樣更精確到位,而且可以對可疑的HOOK進行恢復。相關代碼在網絡上有提供。這種加載SDT的方法是90210在rootkit.com中‘A more stable way to locate real KiServiceTable’提出來的。
其他的方法我在師還沒有注意到,應該是有的,如果發現新方法,歡迎交流。
?
三、參考資料
1.?????? ‘ROOTKITS: SUVVERING THE WINDOWS KERNEL’, Greg Hoglund, James Butler
2.?????? ‘Defeating Kernel Native API Hookers by Direct KiServiceTable Restoration’, Tan Chew Keong
3.?????? ‘Win2K/XP SDT Restore 0.2 (Proof-Of-Concept)’, Tan Chew Keong
4.?????? ‘SDT Hooking ???? ?? ??’, Dual5651
‘A more stable way to locate real KiServiceTable’, 90210總結
以上是生活随笔為你收集整理的也谈SSDT Hook(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: docker 仓库镜像 替换_Docke
- 下一篇: 荒废的周末