首页
社区
课程
招聘
shadow ssdt hook的一段代码,求解释
发表于: 2013-4-4 10:47 5033

shadow ssdt hook的一段代码,求解释

2013-4-4 10:47
5033
http://bbs.pediy.com/showthread.php?t=56955

里面有一种获取shadow ssdt hook的方法是从KTHREAD.ServiceTable里面搜索

具体是汇编实现,贴一下如下

3。从KTHREAD.ServiceTable里面搜索
如果是GUI线程 那么就是指向ServiceDescriptorTableShadow
其实个人更加倾向这个办法 稳定安全可靠,上面那个代码也许会受到以后系统代码变化影响 但是这个肯定不会

Copy code

    GetServiceDescriptorTableShadowAddress proc uses esi edi ebx

    local dwThreadId:DWORD

        xor ebx, ebx                ; = NULL. Assume ServiceDescriptorTableShadow will be not found

        mov eax, KeServiceDescriptorTable
        mov esi, [eax]

        ; Find KTHREAD.ServiceTable field
        ; For non-GUI threads this field == KeServiceDescriptorTable
        ; and it points to ServiceDescriptorTable
        ; For GUI threads
        ; ServiceDescriptorTableShadow

        invoke KeGetCurrentThread
        mov edi, 200h-4
        .while edi
            .break .if dword ptr [eax][edi] == esi
            dec edi
        .endw

        .if edi != 0
            ; edi = offset to ServiceTable field in KTHREAD structure
            mov dwThreadId, 080h
            .while dwThreadId < 400h
                push eax                    ; reserve DWORD on stack
                invoke PsLookupThreadByThreadId, dwThreadId, esp
                pop ecx                        ; -> ETHREAD/KTHREAD
                .if eax == STATUS_SUCCESS
                    push dword ptr [ecx][edi]
                    fastcall ObfDereferenceObject, ecx
                    pop eax
                    .if eax != esi
                        mov edx, MmSystemRangeStart
                        mov edx, [edx]
                        mov edx, [edx]
                        .if eax > edx        ; some stupid error checking
                            mov ebx, eax
                            invoke DbgPrint, $CTA0("FindShadowTable: Found in thread with ID: %X\n"), dwThreadId
                            .break
                        .endif
                    .endif
                .endif
                add dwThreadId, 4
            .endw
        .endif

        mov eax, ebx
        ret

    GetServiceDescriptorTableShadowAddress endp

这个代码我看的意思好像是 通过KeGetCurrentThread获取一个KTHREAD的结构,然后找到偏移地址,获取相对偏移量。然后给定一个范围通过PsLookupThreadByThreadId去每个线程里面找一下那个值?判断是不是GUI线程(这个判断没看懂),后面 fastcall ObfDereferenceObject, ecx 这个之后就不明白是啥意思了。。

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 0
支持
分享
最新回复 (8)
雪    币: 110
活跃值: (34)
能力值: (RANK:50 )
在线值:
发帖
回帖
粉丝
2
判断是不是gui线程的方法是监测kthread.win32thread是否为0,非0就是gui线程
 fastcall ObfDereferenceObject是因为PsLookupThreadByThreadId后该线程对应的线程对象的引用计数增加了,需要减少,详情请msdn PsLookupThreadByThreadId。
这个实现方法有局限噢,64位下的kthread没有ssdt指针了
2013-4-4 11:20
0
雪    币: 48
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
3
1.刚搜了一下有这么个函数PsConvertToGuiThread 貌似可以直接转过去,那就不用遍历找GUI线程了?不过这个函数貌似没导出的 晕。。

2. kthread.win32thread 这个WRK的结构体里面貌似没这个字段啊?

3.mov edx, MmSystemRangeStart ;这三行,得到的数是80000000,特殊的可能是c0000000h.
          mov edx, [edx]
          mov edx, [edx]
这几个是想干啥呀?

4.那个还有比较通用的办法么?
2013-4-4 12:02
0
雪    币: 48
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
4
貌似又看明白了一点,好像他只是把线程的那个servicetable字段拿出来跟那个SSDT的地址比较了一下,不相等的话就当做是shadow ssdt的地址了。
2013-4-4 12:08
0
雪    币: 48
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
5
好像只是为了做参数检查??
2013-4-4 12:10
0
雪    币: 110
活跃值: (34)
能力值: (RANK:50 )
在线值:
发帖
回帖
粉丝
6
PsConvertToGuiThread是个内部函数,将一个非gui线程转换为gui线程,但不推荐自己调用它,可能会出问题。
win32thread这个域是在ethread还是kthread有点忘了,肯定是存在的,待会回去看看。。。
我的实现方式是遍历一个肯定有gui线程的进程中的线程去找。
2013-4-4 13:50
0
雪    币: 110
活跃值: (34)
能力值: (RANK:50 )
在线值:
发帖
回帖
粉丝
7
WRK中,_KTHREAD是有Win32Thread这个域的

typedef struct _KTHREAD {

    //
    // The dispatcher header and mutant listhead are fairly infrequently
    // referenced.
    //

    DISPATCHER_HEADER Header;
    LIST_ENTRY MutantListHead;

    //
    // The following fields are referenced during context switches and wait
    // operatings. They have been carefully laid out to get the best cache
    // hit ratios.
    //

    PVOID InitialStack;
    PVOID StackLimit;
    PVOID KernelStack;

    KSPIN_LOCK ThreadLock;
    union {
        KAPC_STATE ApcState;
        struct {
            UCHAR ApcStateFill[KAPC_STATE_ACTUAL_LENGTH];
            BOOLEAN ApcQueueable;
            volatile UCHAR NextProcessor;
            volatile UCHAR DeferredProcessor;
            UCHAR AdjustReason;
            SCHAR AdjustIncrement;
        };
    };

    KSPIN_LOCK ApcQueueLock;

#if !defined(_AMD64_)

    ULONG ContextSwitches;
    volatile UCHAR State;
    UCHAR NpxState;
    KIRQL WaitIrql;
    KPROCESSOR_MODE WaitMode;

#endif

    LONG_PTR WaitStatus;
    union {
        PKWAIT_BLOCK WaitBlockList;
        PKGATE GateObject;
    };

    BOOLEAN Alertable;
    BOOLEAN WaitNext;
    UCHAR WaitReason;
    SCHAR Priority;
    UCHAR EnableStackSwap;
    volatile UCHAR SwapBusy;
    BOOLEAN Alerted[MaximumMode];
    union {
        LIST_ENTRY WaitListEntry;
        SINGLE_LIST_ENTRY SwapListEntry;
    };

    PRKQUEUE Queue;

#if !defined(_AMD64_)

    ULONG WaitTime;
    union {
        struct {
            SHORT KernelApcDisable;
            SHORT SpecialApcDisable;
        };

        ULONG CombinedApcDisable;
    };

#endif

    PVOID Teb;
    union {
        KTIMER Timer;
        struct {
            UCHAR TimerFill[KTIMER_ACTUAL_LENGTH];

            //
            // N.B. The following bit number definitions must match the
            //      following bit field.
            //
            // N.B. These bits can only be written with interlocked
            //      operations.
            //
    
#define KTHREAD_AUTO_ALIGNMENT_BIT 0
#define KTHREAD_DISABLE_BOOST_BIT 1
    
            union {
                struct {
                    LONG AutoAlignment : 1;
                    LONG DisableBoost : 1;
                    LONG ReservedFlags : 30;
                };
        
                LONG ThreadFlags;
            };
        };
    };

    union {
        KWAIT_BLOCK WaitBlock[THREAD_WAIT_OBJECTS + 1];
        struct {
            UCHAR WaitBlockFill0[KWAIT_BLOCK_OFFSET_TO_BYTE0];
            BOOLEAN SystemAffinityActive;
        };

        struct {
            UCHAR WaitBlockFill1[KWAIT_BLOCK_OFFSET_TO_BYTE1];
            CCHAR PreviousMode;
        };

        struct {
            UCHAR WaitBlockFill2[KWAIT_BLOCK_OFFSET_TO_BYTE2];
            UCHAR ResourceIndex;
        };

        struct {
            UCHAR WaitBlockFill3[KWAIT_BLOCK_OFFSET_TO_BYTE3];
            UCHAR LargeStack;
        };

#if defined(_AMD64_)

        struct {
            UCHAR WaitBlockFill4[KWAIT_BLOCK_OFFSET_TO_LONG0];
            ULONG ContextSwitches;
        };

        struct {
            UCHAR WaitBlockFill5[KWAIT_BLOCK_OFFSET_TO_LONG1];
            volatile UCHAR State;
            UCHAR NpxState;
            KIRQL WaitIrql;
            KPROCESSOR_MODE WaitMode;
        };

        struct {
            UCHAR WaitBlockFill6[KWAIT_BLOCK_OFFSET_TO_LONG2];
            ULONG WaitTime;
        };

        struct {
            UCHAR WaitBlockFill7[KWAIT_BLOCK_OFFSET_TO_LONG3];
             union {
                 struct {
                     SHORT KernelApcDisable;
                     SHORT SpecialApcDisable;
                 };
         
                 ULONG CombinedApcDisable;
             };
        };

#endif

    };

    LIST_ENTRY QueueListEntry;

    //
    // The following fields are accessed during system service dispatch.
    //

    PKTRAP_FRAME TrapFrame;
    PVOID CallbackStack;
    PVOID ServiceTable;

#if defined(_AMD64_)

    ULONG KernelLimit;

#endif

    //
    // The following fields are referenced during ready thread and wait
    // completion.
    //

    UCHAR ApcStateIndex;
    UCHAR IdealProcessor;
    BOOLEAN Preempted;
    BOOLEAN ProcessReadyQueue;

#if defined(_AMD64_)

    PVOID Win32kTable;
    ULONG Win32kLimit;

#endif

    BOOLEAN KernelStackResident;
    SCHAR BasePriority;
    SCHAR PriorityDecrement;
    CHAR Saturation;
    KAFFINITY UserAffinity;
    PKPROCESS Process;
    KAFFINITY Affinity;

    //
    // The below fields are infrequently referenced.
    //

    PKAPC_STATE ApcStatePointer[2];
    union {
        KAPC_STATE SavedApcState;
        struct {
            UCHAR SavedApcStateFill[KAPC_STATE_ACTUAL_LENGTH];
            CCHAR FreezeCount;
            CCHAR SuspendCount;
            UCHAR UserIdealProcessor;
            UCHAR CalloutActive;

#if defined(_AMD64_)

            BOOLEAN CodePatchInProgress;

#elif defined(_X86_)

            UCHAR Iopl;

#else

            UCHAR OtherPlatformFill;

#endif

        };
    };

   [COLOR="Red"] PVOID Win32Thread;[/COLOR]
    PVOID StackBase;
    union {
        KAPC SuspendApc;
        struct {
            UCHAR SuspendApcFill0[KAPC_OFFSET_TO_SPARE_BYTE0];
            SCHAR Quantum;
        };

        struct {
            UCHAR SuspendApcFill1[KAPC_OFFSET_TO_SPARE_BYTE1];
            UCHAR QuantumReset;
        };

        struct {
            UCHAR SuspendApcFill2[KAPC_OFFSET_TO_SPARE_LONG];
            ULONG KernelTime;
        };

        struct {
            UCHAR SuspendApcFill3[KAPC_OFFSET_TO_SYSTEMARGUMENT1];
            PVOID TlsArray;
        };

        struct {
            UCHAR SuspendApcFill4[KAPC_OFFSET_TO_SYSTEMARGUMENT2];
            PVOID BBTData;
        };

        struct {
            UCHAR SuspendApcFill5[KAPC_ACTUAL_LENGTH];
            UCHAR PowerState;
            ULONG UserTime;
        };
    };

    union {
        KSEMAPHORE SuspendSemaphore;
        struct {
            UCHAR SuspendSemaphorefill[KSEMAPHORE_ACTUAL_LENGTH];
            ULONG SListFaultCount;
        };
    };

    LIST_ENTRY ThreadListEntry;
    PVOID SListFaultAddress;

#if defined(_WIN64)

    LONG64 ReadOperationCount;
    LONG64 WriteOperationCount;
    LONG64 OtherOperationCount;
    LONG64 ReadTransferCount;
    LONG64 WriteTransferCount;
    LONG64 OtherTransferCount;

#endif

} KTHREAD, *PKTHREAD, *PRKTHREAD;

#if !defined(_X86AMD64_) && defined(_AMD64_)

C_ASSERT((FIELD_OFFSET(KTHREAD, ServiceTable) + 16) == FIELD_OFFSET(KTHREAD, Win32kTable));
C_ASSERT((FIELD_OFFSET(KTHREAD, ServiceTable) + 8) == FIELD_OFFSET(KTHREAD, KernelLimit));
C_ASSERT((FIELD_OFFSET(KTHREAD, Win32kTable) + 8) == FIELD_OFFSET(KTHREAD, Win32kLimit));

#endif


//
// ccNUMA supported in multiprocessor PAE and WIN64 systems only.
//

#if (defined(_WIN64) || defined(_X86PAE_)) && !defined(NT_UP)

#define KE_MULTINODE

#endif

2013-4-4 17:08
0
雪    币: 110
活跃值: (34)
能力值: (RANK:50 )
在线值:
发帖
回帖
粉丝
8
说一下我用KTHREAD.ServiceTable获取SSDT Shadow的思路:
找到GUI线程,然后通过该线程的KTHREAD.ServiceTable获取SSDT Shadow
判断一个线程是否是GUI的线程的标准就是该线程的KTHREAD.Win32Thread是否为0。
找到GUI线程就简单了,比如遍历explorer.exe的线程表,或者去遍历线程也可以
不过个人认为最好还是少用内核对象。容易被发现。
2013-4-4 17:12
0
雪    币: 48
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
9
非常感谢大大的帮助,我再细细研究一下。
2013-4-4 18:47
0
游客
登录 | 注册 方可回帖
返回
//