zoukankan      html  css  js  c++  java
  • SSDT表结构的深入学习

    SSDT表的知识目录:

    A、了解SSDT结构

    B、由SSDT索引号获取当前函数地址       

    C、如何获取索引号

    D、获取起源地址-判断SSDT是否被HOOK

    E、如何向内核地址写入自己代码

    A、了解SSDT结构

    SSDT的全称是 System  ServicesDescriptor Table--系统服务描述符表,是由 ntoskrnl.exe导出KeServiceDescriptorTable 这个表,是全局的,声明导出即可在编程中使用。

     

    typedef  struct  ServiceDescriptorEntry

    {
       unsigned  int  *ServiceTableBase;       //SystemService Dispatch Table 的基地址
       unsigned  int  *ServiceCounterTable(0);   

       //包含着 SSDT 中每个服务被调用次数的计数器。这个计数器一般由 sysenter  更新。
       unsigned  int   NumberOfServices;     //由 ServiceTableBase描述的服务的数目。
       unsigned  char  *ParamTableBase;    

        //包含每个系统服务参数字节数表的基地址-系统服务参数表
     } SSDT_Entry;

    用windbg 了解SSDT结构,命令:

    dp    nt!KeServiceDescriptorTable

    B、由SSDT索引号获取当前函数地址

    [[KeServiceDescriptorTable基址] + index*4]  

     

    C、如何获取SSDT索引号

    用工具查看如:狙剑、火眼等

    D、获取起源地址-判断SSDT是否被HOOK

    MmGetSystemRoutineAddress函数,得到系统导出函数的地址 

    包含头文件Wdm.h 或Ntddk.h

    //NTKERNELAPI
    PVOID
    MmGetSystemRoutineAddress (
        __in    PUNICODE_STRING   SystemRoutineName
        )
    /*++
     
    Routine Description:
     
        This functionreturns the address of the argument function pointer if
        it is in the kernelor HAL, NULL if it is not.
     
    Arguments:
     
        SystemRoutineName -Supplies the name of the desired routine.
     
    Return Value:
     
        Non-NULL functionpointer if successful.  NULL if not.
     
    Environment:
     
        Kernel mode,PASSIVE_LEVEL, arbitrary process context.
     
    --*/
    {
        PKTHREADCurrentThread;
        NTSTATUS Status;
        PKLDR_DATA_TABLE_ENTRY DataTableEntry;
        ANSI_STRINGAnsiString;
        PLIST_ENTRYNextEntry;
        UNICODE_STRINGKernelString;
        UNICODE_STRINGHalString;
        PVOIDFunctionAddress;
        LOGICAL Found;
        ULONGEntriesChecked;
     
        ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
     
        EntriesChecked = 0;
        FunctionAddress =NULL;
     
        KernelString.Buffer= (const PUSHORT) KERNEL_NAME;
        KernelString.Length= sizeof (KERNEL_NAME) - sizeof (WCHAR);
       KernelString.MaximumLength = sizeof KERNEL_NAME;
     
        HalString.Buffer =(const PUSHORT) HAL_NAME;
        HalString.Length =sizeof (HAL_NAME) - sizeof (WCHAR);
       HalString.MaximumLength = sizeof HAL_NAME;
     
        do {
            Status =RtlUnicodeStringToAnsiString (&AnsiString,
                                                   SystemRoutineName,
                                                   TRUE);
     
            if (NT_SUCCESS(Status)) {
                break;
            }
     
           KeDelayExecutionThread (KernelMode, FALSE,(PLARGE_INTEGER)&MmShortTime);
     
        } while (TRUE);
     
        //
        // Arbitraryprocess context so prevent suspend APCs now.
        //
     
        CurrentThread =KeGetCurrentThread ();
        KeEnterCriticalRegionThread(CurrentThread);
       ExAcquireResourceSharedLite (&PsLoadedModuleResource, TRUE);
     
        //
        // Check only thekernel and the HAL for exports.
        //
     
        NextEntry =PsLoadedModuleList.Flink;
        while (NextEntry !=&PsLoadedModuleList) {
     
            Found = FALSE;
     
            DataTableEntry= CONTAINING_RECORD(NextEntry,
                                              KLDR_DATA_TABLE_ENTRY,
                                              InLoadOrderLinks);
     
            if (RtlEqualUnicodeString(&KernelString,
                                      &DataTableEntry->BaseDllName,
                                      TRUE)) {
     
                Found =TRUE;
               EntriesChecked += 1;
     
            }
            else if(RtlEqualUnicodeString (&HalString,
                                           &DataTableEntry->BaseDllName,
                                           TRUE)){
     
                Found =TRUE;
               EntriesChecked += 1;
            }
     
            if (Found ==TRUE) {
     
               FunctionAddress = MiFindExportedRoutineByName(DataTableEntry->DllBase,
                                                             &AnsiString);
     
                if(FunctionAddress != NULL) {
                    break;
                }
     
                if (EntriesChecked== 2) {
                    break;
                }
            }
     
            NextEntry =NextEntry->Flink;
        }
     
       ExReleaseResourceLite (&PsLoadedModuleResource);
       KeLeaveCriticalRegionThread (CurrentThread);
     
        RtlFreeAnsiString(&AnsiString);
     
        returnFunctionAddress;
    }
    //WRK中的源码

    E、如何向内核地址写入自己代码

    在后期版本的操作系统中,要求SSDT是只读的,因此任何合法的程序都不可能修改这个表,不过聪明的大牛们还是想出了修改SSDT表的方法。

    方法一:更改注册表(需要重启)

    HKLMSYSTEMCurrentControlsetControlSessionMangerMemoryManagementEnforceWriteProtection= 0

    HKLMSYSTEMCurrentControlsetControlSessionMangerMemoryManagementDisablePagingExecutive= 1

    方法二:修改CR0寄存器的第1位即wp位置0

    //关闭内存保护 
    _asm 
    { 
        push eax 
        mov eax, CR0 
        and eax, 0FFFEFFFFh 
        mov CR0, eax 
        pop eax 
    } 
     
    //恢复内存保护 
    _asm 
    { 
        push eax 
        mov eax, CR0 
        or eax , not 0FFFEFFFFh 
        mov CR0, eax 
        pop eax 
    } 

    方法三:利用MDL(Memory Descriptor List)来绕过写保护

    //MDL reference defined inntddk.h 
    typedef struct  _MDL{ 
                          Struct  _MDL   *Next; 
                          CSHORT  Size; 
                          CSHORT  MdlFlags; 
                          Struct  _EPROCESS  *Process; 
                          PVOID   MappedSystemVa; 
                          PVOID   StartVa; 
                          ULONG   ByteCount; 
                          ULONG   ByteOffset; 
    }MDL,*PMDL; 
     
    //MDL Flags 
    #define	MDL_MAPPED_TO_SYSTEM_VA             0x0001 
    #define	MDL_PAGES_LOCKED                    0x0002 
    #define	MDL_SOURCE_IS_NONPAGED_POOL         0x0004 
    #define	MDL_ALLOCATED_FIXED_SIZE            0x0008 
    #define MDL_PARTIAL                         0x0010 
    #define	MDL_PARTIAL_HAS_BEEN_MAPPED         0x0020 
    #define	MDL_IO_PAGE_READ                    0x0040 
    #define	MDL_WRITE_OPERATION                 0x0080 
    #define	MDL_PARENT_MAPPED_SYSTEM_VA         0x0100 
    #define MDL_LOCK_HELD                       0x0200 
    #define MDL_PHYSICAL_VIEW                   0x0400 
    #define MDL_IO_SPACE                        0x0800 
    #define	MDL_NETWORK_HEADER                  0x1000 
    #define	MDL_MAPPING_CAN_FAIL                0x2000 
    #define	MDL_ALLOCATED_MUST_SUCCEED          0x4000 
     
    //声明 
    #pragma pack(1) 
    typedef struct  ServiceDescriptorEntry{ 
                                            unsigned int*   ServiceTableBase; 
    					unsigned int*   ServiceCounterTableBase; 
    					unsigned int    NumberOfService; 
    					unsigned char*  ParamTableBase; 
    }SSDT_Entry;
    #pragma pack()
    
    //导出SSDT表
    _declspec(dllimport)SSDT_Entry KeServiceDescriptorTable;
    
    //保存原始的系统调用地址
    PMDL g_pmdlSystemCall; 
    PVOID *MappedSystemCallTable;
    //创建MDL
    g_pmdlSystemCall = MmCreateMdl(NULL, KeServiceDescriptorTable, ServiceTableBase, KeServcieDescriptorTable.NumberOfService*4);
    if(!g_pmdlSystemCall) 
    {
    	return STATUS_UNSUCCESSFUL;
    }
    
    //构建非分页内存
    MmBuildMdlForNonPagedPool(g_pmdlSystemCall); 
    //改变MDL的标志 
    g_pmdlSystemCall->MdlFlags = g_pmdlSystemCall->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA ;
    //锁定内存
    MappedSystemCallTable = MmMapLockedPages(g_pmdlSystemCall, KernelMode);
    



    参考资料:

    《Windows内核的安全防护》推荐

    http://blog.csdn.net/evi10r/article/details/6840564

  • 相关阅读:
    spring----RESTful API
    spring----模块之间的通讯问题
    PHP错误与异常处理
    微信支付:curl出错,错误码:60
    jquery判断checkbox是否选中
    微信网页授权的问题
    TP5更新数据成功,但判断结果不符
    190719有个织梦专题标题长度限制问题
    判断手机浏览器还是微信浏览器(PHP)
    TP5关联模型出现疑问,待解决
  • 原文地址:https://www.cnblogs.com/csnd/p/11800742.html
Copyright © 2011-2022 走看看