HOOK集合----SSDT Inline Hook(X86 win7)

Posted matthew-memorys

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HOOK集合----SSDT Inline Hook(X86 win7)相关的知识,希望对你有一定的参考价值。

介绍:

    SSDT InlineHook是在SSDT Hook 基础上来进一步Hook的,SSDTHook 是直接将SSDT表中的 Nt*函数替换成Fake函数,而SSDT Inline Hook是将原函数代码的前五个字节改变为 E9 _ _ _ _ ,后面跟的是Offset,也就是我们Fake函数的偏移地址,这样当Ring3层函数,比如OpenProcess在Ring3 层被调用,然后进入Ring0 层的NtOpenProcess,但是前五个字节已经被我们改变,变成了跳板,就会进入我们实现写好的Fake函数中去。

 

 

   Nt系列函数地址也是通过SSDT表来找到,上次写的SSDT Hook 中是用MmGetSystemRoutineAddress 来获取函数地址的,这次我通过手动的去找ntdll.dll中的导出表,找到的函数地址,然后找到索引,通过SSDT表找Nt*的函数地址。

 

 1 ULONG GetSSDTFunctionIndexByName(CHAR * FunctionName)
 2 {
 3     NTSTATUS Status = STATUS_UNSUCCESSFUL;
 4     ULONG    Offset = 1;
 5     WCHAR* FileFullPath = L"SystemRootSystem32
tdll.dll";
 6     ULONG  i;
 7     SIZE_T MappingViewSize = 0;
 8     PVOID MappingBaseAddress = NULL;
 9     PIMAGE_NT_HEADERS ImageNtHeader = NULL;
10     PIMAGE_EXPORT_DIRECTORY ImageExportDirectory = NULL;
11     ULONG* AddressOfFunction = NULL;
12     ULONG* AddressOfName = NULL;
13     USHORT*  AddressOfNameOrdinals = NULL;
14     CHAR*    szFunctionName = NULL;
15     ULONG FunctionOrdinal = 0;
16     ULONG FunctionAddress = 0;
17     ULONG Index = 0;
18     //将Ntdll  映射到当前内核地址空间中 
19     Status = MappingPeFile(FileFullPath, &MappingBaseAddress, &MappingViewSize);
20     if (!NT_SUCCESS(Status))
21     {
22         return 0;
23     }
24     
25     __try
26     {
27         ImageNtHeader = RtlImageNtHeader(MappingBaseAddress);
28         if (ImageNtHeader&&ImageNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress)
29         {
30             ImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((ULONG_PTR)MappingBaseAddress +
31                 ImageNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
32                  33             //函数名字表
34             AddressOfName = (ULONG*)((ULONG_PTR)MappingBaseAddress + ImageExportDirectory->AddressOfNames);
35             //函数序号表
36             AddressOfNameOrdinals = (USHORT*)((ULONG_PTR)MappingBaseAddress + ImageExportDirectory->AddressOfNameOrdinals);
37             //根据序号表中的序号   函数地址表
38             AddressOfFunction = (ULONG*)((ULONG_PTR)MappingBaseAddress + ImageExportDirectory->AddressOfFunctions);
39 
40             for (i = 0;i < ImageExportDirectory->NumberOfNames;i++)
41             {
42                 //获得函数名称
43                 szFunctionName = (CHAR*)((ULONG_PTR)MappingBaseAddress + AddressOfName[i]);
44                 if (_stricmp(szFunctionName, FunctionName) == 0)
45                 {
46                     //获得函数序号
47                     FunctionOrdinal = AddressOfNameOrdinals[i];
48                     //获得函数地址
49                     FunctionAddress = AddressOfFunction[FunctionOrdinal]+ (ULONG_PTR)MappingBaseAddress;
50                     /*
51                     2: kd> u ZwOpenProcess
52                         nt!ZwOpenProcess:
53                         8485acd8 b8be000000      mov     eax,0BEh
54                         8485acdd 8d542404        lea     edx,[esp+4]
55                         8485ace1 9c              pushfd
56                         8485ace2 6a08            push    8
57                         8485ace4 e8d5190000      call    nt!KiSystemService (8485c6be)
58                         8485ace9 c21000          ret     10h
59 
60                     */
61                     Index = SSDT_INDEX(FunctionAddress);
62                     break;
63                 }
64             }
65         }
66     }
67     __except(1)
68     {
69         return 0;
70     }
71     ZwUnmapViewOfSection(NtCurrentProcess(), MappingBaseAddress);
72 
73     return Index ;
74 }
 1 NTSTATUS MappingPeFile(WCHAR * FileFullPath, PVOID * MappingBaseAddress, SIZE_T * MappingViewSize)
 2 {
 3     NTSTATUS Status = STATUS_UNSUCCESSFUL;
 4     UNICODE_STRING FilePath;
 5     OBJECT_ATTRIBUTES ObjectAttributes;
 6     IO_STATUS_BLOCK iostatusBlock;
 7     HANDLE FileHandle = NULL;
 8     HANDLE SectionHandle = NULL;
 9     if (!MappingBaseAddress || !MappingViewSize || !FileFullPath)
10     {
11         return Status;
12 
13     }
14     RtlInitUnicodeString(&FilePath, FileFullPath);
15     InitializeObjectAttributes(&ObjectAttributes, &FilePath,
16         OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
17         NULL,
18         NULL);
19 
20     //获得文件句柄
21 
22     Status = ZwCreateFile(&FileHandle,
23         SYNCHRONIZE,
24         &ObjectAttributes,
25         &IoStatusBlock,
26         NULL,
27         FILE_ATTRIBUTE_NORMAL,
28         FILE_SHARE_READ,
29         FILE_OPEN,
30         FILE_SYNCHRONOUS_IO_NONALERT,
31         NULL,
32         0);
33     if (!NT_SUCCESS(Status))
34     {
35         goto EXIT;
36     }
37 
38     //创建一个映射对象
39     ObjectAttributes.ObjectName = NULL;
40     Status = ZwCreateSection(&SectionHandle,
41         SECTION_QUERY | SECTION_MAP_READ,
42         &ObjectAttributes,
43         NULL,
44         PAGE_WRITECOPY,  //写拷贝
45         SEC_IMAGE,       //指示内存对齐
46         FileHandle);
47     if (!NT_SUCCESS(Status))
48     {
49         goto EXIT;
50     }
51 
52     //映射到地址空间
53 
54     Status = ZwMapViewOfSection(SectionHandle,
55         NtCurrentProcess(),
56         MappingBaseAddress,
57         0, 0, 0,
58         MappingViewSize,
59         ViewUnmap,
60         0,
61         PAGE_WRITECOPY);
62 
63 
64 
65 EXIT:
66     if (FileHandle)
67     {
68         ZwClose(FileHandle);
69     }
70     if (SectionHandle)
71     {
72         ZwClose(SectionHandle);
73     }
74     return Status;
75 }

 


 (一)

 

     ?首先找到全局导出的KeServiceDescriptorTable。

     ?然后从ntdll.dll的导出表中获取ZwOpenProcess函数地址。

     ?从ZwOpenProcess中获取序号。

     ?在SSDt表中获取NtOpenProcess函数的地址。

     ?将NtOpenProcess所在页属性改为可读可写的状态。

     ?计算Fake函数与E9指令后跟着的Offset。

     ?修改NtOpenProcess函数前五个字节,完成Hook。

 

Hook前:                                                                                   Hook后:

技术图片              技术图片

 

(二)

 

extern PSYSTEM_SERVICE_DESCRIPTOR_TABLE KeServiceDescriptorTable;
 PVOID  __SSDTInlineHook_ServiceTableBase = NULL;
 ULONG  __SSDTInlineHook_ZwFunctionIndex = 0;
 LPFN_NTOPENPROCESS   __SSDTInlineHook_NtOpenProcess = 0;
 UCHAR*  __SSDTInlineHook_NtOpenProcessCode = NULL;
 UCHAR*  __SSDTInlineHook_NtOpenProcessCode_Pass = NULL;
 BOOLEAN  __SSDTInlineHook_IsHook = FALSE;
NTSTATUS SSDTInlineHook(BOOLEAN IsOk)
{
    NTSTATUS Status = STATUS_UNSUCCESSFUL;
    __SSDTInlineHook_ServiceTableBase = KeServiceDescriptorTable->ServiceTableBase;
    if (__SSDTInlineHook_ServiceTableBase == NULL)
    {
        return Status;
    }
    //获取Zw 函数索引  通过导入表
    __SSDTInlineHook_ZwFunctionIndex = GetSSDTFunctionIndexByName("ZwOpenProcess");
    if (__SSDTInlineHook_ZwFunctionIndex)
    {
        //获取NtOpenpProcess 函数地址
        __SSDTInlineHook_NtOpenProcess = (LPFN_NTOPENPROCESS)((ULONG*)__SSDTInlineHook_ServiceTableBase)[__SSDTInlineHook_ZwFunctionIndex];
        
        if (__SSDTInlineHook_NtOpenProcess == NULL)
        {
            return Status;
        }

        if (IsOk && !__SSDTInlineHook_IsHook)
        {
            //开始SSDTInlineHook 
            Status = SSDTInlineHookInternel((ULONG*)__SSDTInlineHook_NtOpenProcess, (ULONG*)SSDTInlineHook_FakeNtOpenProcess, 5);
            __SSDTInlineHook_IsHook = TRUE;
        }
        else
        {
            Status = SSDTInlineUnHookInternel((ULONG*)__SSDTInlineHook_NtOpenProcess);
            __SSDTInlineHook_IsHook = FALSE;

        }

    }
    return Status;
}

NTSTATUS SSDTInlineHookInternel(ULONG * FunctionAddress, ULONG * FakeFunctionAddress, ULONG Length)
{
    NTSTATUS Status = STATUS_UNSUCCESSFUL;
    UCHAR v1[] = "xe9x00x00x00x00";
    UCHAR v2[] = "xe9x00x00x00x00";
    ULONG Temp = 0;

    //申请空间保存原函数前5个字节指令
    __SSDTInlineHook_NtOpenProcessCode = ExAllocatePool(NonPagedPool, Length);
    if (!__SSDTInlineHook_NtOpenProcessCode)
    {
        return Status;
    }

    //关闭写保护
    OnEnableWrite();
    /*
    2: kd> u 0x84a31ba1
        nt!NtOpenProcess:
        84a31ba1 8bff            mov     edi,edi
        84a31ba3 55              push    ebp
        84a31ba4 8bec            mov     ebp,esp

    */
    memcpy(__SSDTInlineHook_NtOpenProcessCode, FunctionAddress, Length);

    //开启写保护
    OnDisableWrite();

    __SSDTInlineHook_NtOpenProcessCode_Pass = ExAllocatePool(NonPagedPool, Length + 5);

    if (__SSDTInlineHook_NtOpenProcessCode_Pass == NULL)
    {
        if (__SSDTInlineHook_NtOpenProcessCode != NULL)
        {
            ExFreePool(__SSDTInlineHook_NtOpenProcessCode);
            __SSDTInlineHook_NtOpenProcessCode = NULL;
        }
        return Status;
    }

    //0x90  NOP
    RtlFillMemory(__SSDTInlineHook_NtOpenProcessCode_Pass, Length + 5, 0x90);
    //22920
    /*
    0: kd> u NtOpenprocess
    nt!NtOpenProcess:
            84a31ba1 8bff            mov     edi,edi
            84a31ba3 55              push    ebp
            84a31ba4 8bec            mov     ebp,esp
返回地址:    84a31ba6 51              push    ecx
            84a31ba7 51              push    ecx
            84a31ba8 64a124010000    mov     eax,dword ptr fs:[00000124h]
            84a31bae 8a803a010000    mov     al,byte ptr [eax+13Ah]
            84a31bb4 8b4d14          mov     ecx,dword ptr [ebp+14h]

    */
    memcpy((PUCHAR)__SSDTInlineHook_NtOpenProcessCode_Pass, __SSDTInlineHook_NtOpenProcessCode, Length);
    //__SSDTInlineHook_NtOpenProcessCode_Pass [8b ff 55 8b ec | 90 90 90 90 90]

    //SSDTInlineHook  返回地址    
    Temp = (ULONG_PTR)FunctionAddress + Length;
    // Temp =   84a31ba6 [84a31ba1 + 5 ]
    *((ULONG*)&v2[1]) = (ULONG_PTR)Temp - ((ULONG_PTR)__SSDTInlineHook_NtOpenProcessCode_Pass + 5 + 5);
    //  白名单进程   判断后要 返回原函数执行  也就是 0x84a31ba6 处
    //

    memcpy(__SSDTInlineHook_NtOpenProcessCode_Pass + Length, v2, 5);
    //__SSDTInlineHook_NtOpenProcessCode_Pass [8b ff 55 8b ec | e9 xx xx xx xx ]


    Temp = (ULONG_PTR)FakeFunctionAddress;
    *((ULONG*)&v1[1]) = (ULONG)Temp - ((ULONG)FunctionAddress + 5);
    //FakeFunctionAddress - 0x84a31ba6
    // E9    E9当前地址 + 5 + 4字节Offset = Target
 



    OnEnableWrite();
    RtlFillMemory((PVOID)FunctionAddress, Length, 0x90);
    memcpy((PVOID)FunctionAddress, v1, 5);
    OnDisableWrite();
    Status = STATUS_SUCCESS;
    return Status;
}

NTSTATUS SSDTInlineUnHookInternel(ULONG * FunctionAddress)
{
    NTSTATUS Status = STATUS_UNSUCCESSFUL;
    if (__SSDTInlineHook_NtOpenProcessCode == NULL)
    {
        return Status;
    }
    else
    {
        OnEnableWrite();
        memcpy((PVOID)FunctionAddress, __SSDTInlineHook_NtOpenProcessCode, 5);
        OnDisableWrite();

        __SSDTInlineHook_ServiceTableBase = NULL;
        __SSDTInlineHook_ZwFunctionIndex = 0;
        __SSDTInlineHook_NtOpenProcess = 0;
        __SSDTInlineHook_NtOpenProcessCode = NULL;
        __SSDTInlineHook_NtOpenProcessCode_Pass = NULL;


        Status = STATUS_SUCCESS;
    }
    return Status;
}


NTSTATUS SSDTInlineHook_FakeNtOpenProcess(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PCLIENT_ID ClientId)
{

    __try
    {
        PEPROCESS EProcess = PsGetCurrentProcess();
        if (EProcess != NULL && IsRealProcess(EProcess))
        {
            char * ProcessName = (ULONG_PTR)EProcess + x86_IMAGEFILENAME_OFFSET;
            if (strcmp(ProcessName, "HookRing3.exe") == 0)
            {
                return STATUS_ACCESS_DENIED;
            }
        }
    }
    __except (1)
    {
        return GetExceptionCode();
    }

    //白名单进程 返回原先函数地址 + 5 处 执行
    return ((LPFN_NTOPENPROCESS)__SSDTInlineHook_NtOpenProcessCode_Pass)(ProcessHandle, DesiredAccess, ObjectAttributes, ClientId);

}

 

以上是关于HOOK集合----SSDT Inline Hook(X86 win7)的主要内容,如果未能解决你的问题,请参考以下文章

win 64 SSDT HOOK

求助WIN64 HOOK SSDT NtTerminateProcess

SSDT HOOK是啥

SSDT HOOK 框架设计思路

09SSDT概述

Kaspersky 7.0 HOOK SSDT分析