挂钩SSDT

来源:互联网 发布:大数据与信息泄漏 编辑:程序博客网 时间:2024/04/27 18:58

一、原理篇

1.            关于系统服务。

系统服务是由操作系统提供一组函数,使得开发者能够通过APIs直接或间接的调用。一个API可以对应一个系统服务,也可以一个API依赖多个系统服务。比如,WriteFile API对应的系统服务是ntoskrnl.exe中的NtWriteFile。系统服务分发属于陷阱分发的范畴,更详细的资料可参考’Windows Internal(4th edition)’相关章节。从APIs到系统服务的分发过程可简化为图1:

 

 

 

图1

图1只表现了ntdll.dll分发系统服务陷阱的过程,对于GDI/USER过程,它是负责管理图形界面的,暂不作考虑。要钩住系统服务当然要修改服务分发表了(要搞系统服务当然不只值一个方法,但是本文只考虑怎样通过SSDT来做),所以,关键是要找到服务分发列表的索引号(0,1,2,…,n),就可以找到相应的系统服务内存入口地址。系统服务分发表的结构可以直观的简化为图2:

 

图2

 

Windows系统服务是Nt*系列的Native APIs,他们在内存中的入口地址保存在SSDT中。另外,还应该注意Zw*系列的Native APIs,这是以Nt开头的系统服务入口点的镜像,它把原先的访问模式设置为内核模式,从而消除了参数的有效性检查过程,因为Nt系统服务只有当原来的访问模式为ring 3时才进行参数检查。多说几句,除了在ring 0的ntoskrnl.exe有导出中,在ring 3的ntdll.dll中也有这个两系列的函数。这四者的关系怎样呢?以NtQuerySystemInformation系统服务为例:

 

Ring 3

lkd>  u ntdll!ZwQuerySystemInformation L4

ntdll!ZwQuerySystemInformation:

7c92e1aa b8ad000000      mov     eax,0ADh

7c92e1af ba0003fe7f      mov     edx,offset SharedUserData!SystemCallStub (7ffe0300)

7c92e1b4 ff12            call    dword ptr [edx]

7c92e1b6 c21000          ret     10h

 

lkd> u ntdll!NtQuerySystemInformation L4

ntdll!ZwQuerySystemInformation:

7c92e1aa b8ad000000      mov     eax,0ADh

7c92e1af ba0003fe7f      mov     edx,offset SharedUserData!SystemCallStub (7ffe0300)

7c92e1b4 ff12            call    dword ptr [edx]

7c92e1b6 c21000          ret     10h

 

由此可见,在Ring 3下ntdll.dll中,这两个函数是完全一样的。

Ring 0

lkd> u nt!ZwQuerySystemInformation L6

nt!ZwQuerySystemInformation:

804de440 b8ad000000      mov     eax,0ADh

804de445 8d542404        lea     edx,[esp+4]

804de449 9c              pushfd

804de44a 6a08            push    8

804de44c e8e0110000      call    nt!KiSystemService (804df631)

804de451 c21000          ret     10h

 

lkd> u nt!NtQuerySystemInformation

nt!NtQuerySystemInformation:

8057e786 6810020000      push    210h

8057e78b 6830ab4e80      push    offset nt!ExTraceAllTables+0x1eb (804eab30)

8057e790 e8a64cf6ff      call    nt!_SEH_prolog (804e343b)

8057e795 33c0            xor     eax,eax

8057e797 8945e4          mov     dword ptr [ebp-1Ch],eax

8057e79a 8945dc          mov     dword ptr [ebp-24h],eax

8057e79d 8945fc          mov     dword ptr [ebp-4],eax

8057e7a0 64a124010000    mov     eax,dword ptr fs:[00000124h]

 

在Ring 0下,ZwQuerySystemInformation实现了对KiSystemService(系统服务分发器)的调用,并在阿函数开始的时候将索引号放入eax寄存器(mov eax,0ADh),这是我们需要的,通过0ADh可以找到系统服务NtQuerySystemInformation,下节详细讨论。

在’ Undocumented Windows 2000 Secrets’中有所阐述,这里让大家看到事实了。找几个其他的APIs尝试一下,自己去悟吧,没悟性成不了佛的。

 

1.            找到Hook入口

系统服务分发表是一个C的数据结构,ntolkrnl.exe导出了该结构的指针(符号为KeServiceDescriptorTable)。其实,内核还维护了一个替代的SDT,其名称为:KeServiceDescriptorTableShadow,但这个SDT并没有被ntolkrnl.exe导出。KeServiceDescriptorTable定义如下:

struct _KeServiceDescriptorTableEntry

{

unsigned int *ServiceTableBase;

unsigned int *ServiceCounterTableBase; //Used only in checked build

nsigned int NumberOfServices;

unsigned char *ParamTableBase;

} KeServiceDescriptorTableEntry, *PKeServiceDescriptorTableEntry

其第一个成员ServiceTableBase就是系统服务列表数组的其实地址。

首先,就是要获取KeServiceDescriptorTableEntry的内存地址。由于KeServiceDescriptorTable已经被导出,所以导入KeServiceDescriptorTable即可:

extern PServiceDescriptorTableEntry KeServiceDescriptorTable;

创建访问参考:

PServiceDescriptorTableEntry pSDT = KeServiceDescriptorTable;

不过,hoglund是这样做的

__declspec(dllimport)  ServiceDescriptorTableEntry_t KeServiceDescriptorTable;

异曲同工,都是导入KeServiceDescriptorTable。

现在找到了SDT,有了一个好的开头,接下来就是要找到关注的系统服务了,才能做一些想做的事情。回到ZwQuerySystemInformation的那段反汇编的代码:

lkd> u nt!ZwQuerySystemInformation L6

nt!ZwQuerySystemInformation:

804de440 b8ad000000      mov     eax,0ADh

804de445 8d542404        lea     edx,[esp+4]

804de449 9c              pushfd

804de44a 6a08            push    8

804de44c e8e0110000      call    nt!KiSystemService (804df631)

804de451 c21000          ret     10h

它索引号0ADh放到了eax寄存器,dd一下:

lkd> dd nt!ZwQuerySystemInformation

804de440  0000adb8 24548d00 086a9c04 0011e0e8

804de450  0010c200 0000aeb8 24548d00 086a9c04

804de440是它的入口地址,AD就存放在那段机器码里。这样就可以了:

DWORD dwIndex= *(*ULONG)((UCHAR*)ZwQuerySystemInformation+1);

好多小星星(*),慢慢理解吧。转换成汇编就容易理解了:

mov     ecx, DWORD PTR [ZwQuerySystemInformation];

mov     edx, [ecx+1];

最后,有了KeServiceDescriptorTable.ServiceTableBase的地址,又找到了索引号,这样所关注系统服务就找到了。

KeServiceDescriptorTable.ServiceTableBase+ dwIndex*4

手工试一下,还是以ZwQuerySystemInformation为例子。

通过KeServiceDescriptorTable.ServiceTableBase获取系统服务数组的起始地址

lkd> dd KeServiceDescriptorTable

8055a680  804e36a8 00000000 0000011c 80513eb8

是这里804e36a8,可以先都为快:

lkd> dd 804e36a8

804e36a8  80580302 80579b8c 8058b7ae 805907e4

804e36b8  805905fe 806377a0 80639931 8063997a

804e36c8  8057560b 806481cf 80636f5f 8058fb85

804e36d8  8062f0a4 8057be31 8058cc26 806261bd

804e36e8  805dcf20 80568f9d 805d9ac1 805a2bb0

804e36f8  804e3cb4 806481bb 805ca22c 804f0e28

804e3708  80569649 80567d49 8058fff3 8064e1c1

804e3718  8058f8f5 80581225 8064e42f f584dc90

试一下第一个系统服务80580302是谁呢?

lkd> u 80580302

nt!NtAcceptConnectPort:

80580302 689c000000      push    9Ch

80580307 68d8224f80      push    offset nt!_real+0x128 (804f22d8)

8058030c e82a31f6ff      call    nt!_SEH_prolog (804e343b)

80580311 64a124010000    mov     eax,dword ptr fs:[00000124h]

80580317 8a8040010000    mov     al,byte ptr [eax+140h]

8058031d 884590          mov     byte ptr [ebp-70h],al

80580320 84c0            test    al,al

80580322 0f84e9080300    je      nt!NtAcceptConnectPort+0x1df (805b0c11)

果然是NtAcceptConnectPort!套用算法公式找一下NtQuerySystemInformation:

804e36a8+0xAD*4 = 804E395C

lkd> dd 804E395C

804e395c  8057e786 80590ad0 80591857 805871f3

804e396c  f7377b46 8056d338 80570e3b 8059068f

804e397c  804e303a 806477af 805710d8 805dae6c

804e398c  8058f6a6 8057b545 8057dbee 80566809

804e399c  8058b492 80567272 8065a3d6 8064e029

804e39ac  f58647c0 8057f307 8056ae96 8056a9ae

804e39bc  80622b92 8062b803 8058aa2c f584d960

804e39cc  8062b5fc 8059d753 8053c14a f5864a50

那就是8057e786的位置了,反汇编:

lkd> u 8057e786

nt!NtQuerySystemInformation:

8057e786 6810020000      push    210h

8057e78b 6830ab4e80      push    offset nt!ExTraceAllTables+0x1eb (804eab30)

8057e790 e8a64cf6ff      call    nt!_SEH_prolog (804e343b)

8057e795 33c0            xor     eax,eax

8057e797 8945e4          mov     dword ptr [ebp-1Ch],eax

8057e79a 8945dc          mov     dword ptr [ebp-24h],eax

8057e79d 8945fc          mov     dword ptr [ebp-4],eax

8057e7a0 64a124010000    mov     eax,dword ptr fs:[00000124h]

真的是NtQuerySystemInformation。搞定了!

有些网上流传的代码将新的系统服务函数命名为NewZwQuerySystemInformation在语法角度是没有什么错误,但是实际上它并不是替换了ZwQuerySystemInformation而是NtQuerySystemInformation,这种命名让读者产生误解,应该是NewNtQuerySystemInformation更为妥当。我们只是通过ZwQuerySystemInformation来找到NtQuerySystemInformation,最终都是在Nt*系列的函数上做文章的。对于那些“钩住Zw*”文章的提法,也不敢苟同,坏事都是新的Nt*干的,Zw*只是提供了线索,有点受冤了。

 

2.            系统服务替换及还原

万事俱备,是不是可以“动手”了?不妨试一下,Windows 2000及以上必定是BSOD,伤心的蓝色海洋。Why?该内存区域写保护。点解?去掉写保护,修改标识寄存器CR0。

31
 30
 ...
 18
 17
 16
 ...
 5
 4
 3
 2
 0
 1
 
P/G
 C/D
 ...
 A/M
 
 W/P
 ...
 N/E
 E/T
 T/S
 E/M
 M/P
 P/E
 


我们主要注意这个WP这位,其他的请参考IA-32 Volume 3A;

WP——Write Protect,当设置为1时只提供读页权限;

PE——Paging,当设置为1时提供分页;

MP——Protection Enable,当设置为1时进入保护模式;

因此,只要把WP这一位设置为0时,就可以修改SSDT了。

 

去除写保护标示:

unsigned long _cr0;

_asm

{

cli;

mov eax,cr0

mov _cr0,eax

and eax,0fffeffffh

mov cr0,eax

}

恢复写保护:

_asm

{

mov eax, _cr0

mov cr0,eax

sti

}

还有更绅士的做法,将整个SSDT的存储数组映射到一个非分页MDL(Memory Description List)的内存空间,然后就方便对这块内存区域修改属性、改写内容... Greg Hoglund那个例子的做法。

lkd> dt _mdl

nt!_MDL

   +0x000 Next             : Ptr32 _MDL

   +0x004 Size             : Int2B

   +0x006 MdlFlags         : Int2B

   +0x008 Process          : Ptr32 _EPROCESS

   +0x00c MappedSystemVa   : Ptr32 Void

   +0x010 StartVa          : Ptr32 Void

   +0x014 ByteCount        : Uint4B

   +0x018 ByteOffset       : Uint4B

最后,服务卸载时当然不能忘了把SSDT修改过来,就是上述操作的逆过程,大同小异。

 

一、实战篇

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

代码一:经典案例,替换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’提出来的。

其他的方法我在师还没有注意到,应该是有的,如果发现新方法,欢迎交流。

 

原创粉丝点击