以PspExitThread为例介绍如何寻找未导出函数的函数地址

ntoskrnl.exe导出了很多内核例程供驱动开发人员方便的使用,它也隐藏了很多很强大的历程,防止驱动开发人员过于方便的用它们。比如PspExitThread,这个函数没什么特别的,但配合APC使用它就能杀死绝大多数的进程,包括一些杀毒软件在内。gussing.cnblogs.com

那么如何才能找到这些未导出的函数并使用它们呢?答案就是反汇编,借助强大的windbg,加上一点点汇编基础,操作系统在你面前就会变的很透明。还是以PspExitThread为例子,我们已经知道导出函数PsTerminateSystemThread会调用PspTerminateThreadByPointer()函数,PspTerminateThreadByPointer进而会调用PspExitThread,所谓的函数调用就是 call 指令加上一个函数地址,所以挖出PspExitThread的地址完全是有可能的。gussing.cnblogs.com

打开windbg的本地内核调试,把该加载的pdb都加载了,然后反汇编PsTerminateSystemThread:gussing.cnblogs.com

lkd> uf nt!PsTerminateSystemThread
nt!PsTerminateSystemThread:
805d2c36 8bff            mov     edi,edi
805d2c38 55              push    ebp
805d2c39 8bec            mov     ebp,esp
805d2c3b 64a124010000    mov     eax,dword ptr fs:[00000124h]
805d2c41 f6804802000010  test    byte ptr [eax+248h],10h
805d2c48 7507            jne     nt!PsTerminateSystemThread+0x1b (805d2c51)

nt!PsTerminateSystemThread+0x14:
805d2c4a b80d0000c0      mov     eax,0C000000Dh
805d2c4f eb09            jmp     nt!PsTerminateSystemThread+0x24 (805d2c5a)

nt!PsTerminateSystemThread+0x1b:
805d2c51 ff7508          push    dword ptr [ebp+8]
805d2c54 50              push    eax
805d2c55 e828fcffff      call    nt!PspTerminateThreadByPointer (805d2882)

nt!PsTerminateSystemThread+0x24:
805d2c5a 5d              pop     ebp
805d2c5b c20400          ret     4

地址805d2c55处的call指令可以解析出PspTerminateThreadByPointer的地址。那么该call指令的地址又是如何得到的呢?看上面那行push dword ptr [ebp+8],也就是“ff7508”,这是PspTerminateThreadByPointer函数调用的“特征码”,从PsTerminateSystemThread函数开始到PspTerminateThreadByPointer函数调用为止,该特征码都只出现一次,所以搜索到ff7508串就能很方便的定位到PspTerminateThreadByPointer。gussing.cnblogs.com

再看PspTerminateThreadByPointer函数(805d2882)的反汇编:gussing.cnblogs.com

lkd> uf 805d2882
nt!PspTerminateThreadByPointer:
805d2882 8bff            mov     edi,edi
805d2884 55              push    ebp
805d2885 8bec            mov     ebp,esp
805d2887 83ec0c          sub     esp,0Ch
805d288a 834df8ff        or      dword ptr [ebp-8],0FFFFFFFFh
805d288e 56              push    esi
805d288f 57              push    edi
805d2890 8b7d08          mov     edi,dword ptr [ebp+8]
805d2893 8db748020000    lea     esi,[edi+248h]
805d2899 f60640          test    byte ptr [esi],40h
805d289c c745f4c0bdf0ff  mov     dword ptr [ebp-0Ch],0FFF0BDC0h
805d28a3 7417            je      nt!PspTerminateThreadByPointer+0x3a (805d28bc)

nt!PspTerminateThreadByPointer+0x23:
805d28a5 8b8720020000    mov     eax,dword ptr [edi+220h]
805d28ab 0574010000      add     eax,174h
805d28b0 50              push    eax
805d28b1 57              push    edi
805d28b2 6852285d80      push    offset nt!PspExitNormalApc+0x54 (805d2852)
805d28b7 e894f1ffff      call    nt!PspCatchCriticalBreak (805d1a50)

nt!PspTerminateThreadByPointer+0x3a:
805d28bc 64a124010000    mov     eax,dword ptr fs:[00000124h]
805d28c2 3bf8            cmp     edi,eax
805d28c4 750e            jne     nt!PspTerminateThreadByPointer+0x52 (805d28d4)

nt!PspTerminateThreadByPointer+0x44:
805d28c6 33c0            xor     eax,eax
805d28c8 40              inc     eax
805d28c9 f00906          lock or dword ptr [esi],eax
805d28cc ff750c          push    dword ptr [ebp+0Ch]
805d28cf e8bef7ffff      call    nt!PspExitThread (805d2092)
。。。

如之前所述,call PspExitThread之前有一串特征码ff750c,从PspTerminateThreadByPointer函数开始到PspExitThread函数调用间只出现一次,搜索到串ff750c就能很方便的找到PspExitThreadgussing.cnblogs.com

最后提供一个寻找PspExitThread的例子,部分代码来自网上,(忘了谁写的了,谁提醒下我马上改):

 

NTSTATUS PspTerminateThreadByPointer(PETHREAD Thread, NTSTATUS status);
typedef VOID (*MyPspExitThread)(NTSTATUS status);


ULONG GetPspTerminateThreadByPointer()
{
        char * PsTerminateSystemThreadAddr;
        int iLen;
        ULONG dwAddr;
        ULONG NtTerminateThreadAddr;
        char * pAddr;
gussing.cnblogs.com
                        PsTerminateSystemThreadAddr= (char *)PsTerminateSystemThread;
                        __asm
                        {
                                        __emit 0x90;
                                        __emit 0x90;
                        }
                        for (iLen=0;iLen<50;iLen++)
                        {
                                        if (*PsTerminateSystemThreadAddr == (char)0xff
                                                && *(PsTerminateSystemThreadAddr+1) == (char)0x75
                                                && *(PsTerminateSystemThreadAddr+2) == (char)0x08
                                                )
                                        {
                                                        __asm
                                                        {
                                                                        __emit 0x90;
                                                                        __emit 0x90;
                                                        }
                                                        PsTerminateSystemThreadAddr += 5;
                                                        dwAddr = *(ULONG *)PsTerminateSystemThreadAddr + (ULONG)PsTerminateSystemThreadAddr +4;

                                                        DbgPrint("[ring0] PspTerminateThreadByPointer:: 0x%x ",dwAddr);
                                                        return dwAddr;
                                                        //break;
                                        }
                                        PsTerminateSystemThreadAddr++;
                        }
        return FALSE;
}

gussing.cnblogs.com
PVOID GetPspExitThread()

{
#ifdef XP_SP3
        char* sPtr;
        ULONG end = (ULONG)GetPspTerminateThreadByPointer() + 0x60;
        sPtr = (char*)GetPspTerminateThreadByPointer();
        while ( (ULONG)sPtr <  end) //0x60 = ±??úé? PspTerminateThreadByPointer ·ê??3ì?è
        {
                //DbgPrint("[ring0] addr: 0x%x, val: 0x%x", sPtr, *(WORD*)sPtr);
                if ( *(WORD*)sPtr == 3189 )
                {gussing.cnblogs.com
                        return (PVOID)(*(ULONG*)(sPtr + 3) + sPtr + 7);        
                }
                sPtr ++;
        }gussing.cnblogs.com
        return NULL;
#else
        return NULL;
#endif

}
posted @ 2009-08-18 14:35  gussing  阅读(3242)  评论(1编辑  收藏  举报