也谈SSDT Hook(二)

一、实战篇

本不想摘代码,既然实战,就不多讲废话了,还是贴上吧,谁都有违背原则的时候:)

代码一:经典案例,替换NtQuerySystemInformation,列取所有查询到的进程名,我使用修改CR0寄存器的方法。

#include

 

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;

}

 

案例二:修改SDTNtCreateSection的地址,列出所有创建SECTION的文件名称,我使用了MDL。其实,搞进程很麻烦凡的,windows的大麻烦之一。

#include

 

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的方法是90210rootkit.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 

你可能感兴趣的:(技术文章)