简单Hook SYSENTER
其實(shí)所有的HOOK,都基本是一樣道理。就是勾住你的目標(biāo)函數(shù),實(shí)現(xiàn)你自己的功能。只要你掌握了,HOOK的原理。剩下的就是尋找目標(biāo)函數(shù)了。
?????今天回憶一下 HOOK SYSENTER,目的當(dāng)然還是繼續(xù)充實(shí)自己的BLOG,繼續(xù)灌水。
一:認(rèn)識(shí)SYSENTER
???SYSENTER是一個(gè)東西?大家都知道調(diào)用門,陷阱門,任務(wù)門(這里沒有照片!_!).。通過他們我們可以從R3到達(dá)R0。簡(jiǎn)單的說SYSENTER就是他們的替代品。SYSENTER是一個(gè)入的
過程,SYSEXIT是他的反過程。
我們以O(shè)penProcess為例,看看他是怎么從R3-R0
kernel32!OpenProcess -> ntdll!ZwOpenProcess -> ntdll!KiFastSystemCall -> sysenter -> nt!KiFastCallEntry -> nt!NtOpenProcess -> nt!KiFastCallEntry> nt!
KiServiceExit -> sysexit -> ntdll!KiFastSystemCallRet -> kernel32!OpenProcess
現(xiàn)在來看看SYSENTER是怎么樣處理的。
R3-R0需要把相關(guān)的工作交給R0層的。包括:設(shè)置CS,IP,SS,SP。SYSENTER有三個(gè)特殊的寄存器(MSR)來幫助我們完成。
SYSENTER_CS_MSR
SYSENTER_ESP_MSR
SYSENTER_EIP_MSR
他們的地址分別是:0x174,0x175,0x176。我們可以通過指令rdmsr/wrmsr。來讀寫這三個(gè)寄存器。相關(guān)代碼如下:
_asm
{
mov ecx,0x176
????rdmsr
????mov OldKiFastCallEntry,eax
}
我們來看看SYSENTER的工作流程。
1. 裝載SYSENTER_CS_MSR 到CS 寄存器,設(shè)置目標(biāo)代碼段
2. 裝載SYSENTER_EIP_MSR到 EIP寄存器,設(shè)置目標(biāo)指令
3. SYSENTER_CS_MSR+8 裝載到SS寄存器 ,設(shè)置棧段
4. 裝載SYSENTER_ESP_MSR 到ESP寄存器,設(shè)置棧幀
5. 切換RING0.
6. 清除 EFLAGS的 VM標(biāo)志
7. 執(zhí)行RING0例程
SYSEXIT的工作流程
1. SYSENTER_CS_MSR+16裝載到 CS寄存器
2. 將EDX的值送入EIP
3. SYSENTER_CS_MSR+24 裝載到SS寄存器
4. 將ECX的值送入ESP
5. 切換回RING3
6. 執(zhí)行EIP處的RING3指令
這樣就完成了R3-RO-R3的過程。
二:相關(guān)代碼
//
// Hook SysEnter.cpp文件
extern "C"
{
#include <ntddk.h>
}
VOID UnloadDriver(PDRIVER_OBJECT pDriverObj);
ULONG OldKiFastCallEntry;
VOID NewKiFastCallEntry()
{
DbgPrint("一個(gè)系統(tǒng)調(diào)用...\n");
_asm
{
???jmp DWORD PTR[OldKiFastCallEntry]
}
}
// 驅(qū)動(dòng)程序加載時(shí)調(diào)用DriverEntry例程
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegistryString)
{
pDriverObj->DriverUnload = UnloadDriver;
//
_asm
{
???mov ecx,0x176
???rdmsr
???mov OldKiFastCallEntry,eax
???mov eax,NewKiFastCallEntry
???wrmsr
}
// 請(qǐng)視情況返回DriverEntry例程執(zhí)行結(jié)果
return STATUS_SUCCESS;
}
VOID UnloadDriver(PDRIVER_OBJECT pDriverObj)
{
_asm
{
???mov ecx,0x176
???xor edx,edx
???mov eax,OldKiFastCallEntry
???wrmsr
}
}
=============================================================================================
呵呵,今天這篇內(nèi)容少,比較簡(jiǎn)單。
SYSENETER是一條匯編指令,它是在Pentium? II 處理器及以上處理器中提供的,是快速系統(tǒng)調(diào)用的一部分。SYSENTER/SYSEXIT這對(duì)指令專門用于實(shí)現(xiàn)快速調(diào)用。在這之前是采用INT 0x2E來實(shí)現(xiàn)的。INT 0x2E在系統(tǒng)調(diào)用的時(shí)候,需要進(jìn)行棧切換的工作。由于Interrupt/Exception Handler的調(diào)用都是通過 call/trap/task這一類的gate來實(shí)現(xiàn)的,這種方式會(huì)進(jìn)行棧切換,并且系統(tǒng)棧的地址等信息由TSS提供。這種方式可能會(huì)引起多次內(nèi)存訪問 (來獲取這些切換信息),因此,從PentiumII開始,IA-32引入了新指令:SYSENTER/SYSEXIT。 有了這兩條指令,
從用戶級(jí)到特權(quán)級(jí)的堆棧以及指令指針的轉(zhuǎn)換,可以通過這一條指令來實(shí)現(xiàn),并且,需要切換到的新堆棧的地址,以及相應(yīng)過程的第一條指令的位置,都有一組特殊寄存器來實(shí)現(xiàn),這類特殊寄存器在IA-32中稱為MSR(Model Specific Register)。這里牽涉到3個(gè)特殊寄存器:?
SYSENTER_CS_MSR: New code segment selector? ?0x174?
SYSENTER_ESP_MSR: New Stack Pointer? ?? ?? ?? ?? ? 0x175?
SYSENTER_EIP_MSR: New Instruction Pointer? ?? ???0x176?
這里標(biāo)出的3個(gè)16進(jìn)制數(shù)分別對(duì)應(yīng)這3個(gè)寄存器的地址,該地址用于Kernel debug時(shí),通過rdmsr/wrmsr指令來讀/寫這3個(gè)寄存器。步驟如下:
1. 裝載SYSENTER_CS_MSR 到CS 寄存器,設(shè)置目標(biāo)代碼段
2. 裝載SYSENTER_EIP_MSR到 EIP寄存器,設(shè)置目標(biāo)指令?
3. SYSENTER_CS_MSR+8 裝載到SS寄存器 ,設(shè)置棧段
4. 裝載SYSENTER_ESP_MSR 到ESP寄存器,設(shè)置棧幀?
5. 切換RING0.?
6. 清除 EFLAGS的 VM標(biāo)志?
7. 執(zhí)行RING0例程?
1. SYSENTER_CS_MSR+16裝載到 CS寄存器?
2. 將EDX的值送入EIP?
3. SYSENTER_CS_MSR+24 裝載到SS寄存器?
4. 將ECX的值送入ESP?
5. 切換回RING3?
6. 執(zhí)行EIP處的RING3指令?
我們?cè)趙indbg中可以看看這個(gè)三個(gè)寄存器的情況,這個(gè)是我機(jī)器里的情況。
lkd> rdmsr 176
msr[176] = 00000000`8053dad0
lkd> rdmsr 175
msr[175] = 00000000`ba4e0000
lkd> rdmsr 174
msr[174] = 00000000`00000008
可以看到,我的機(jī)器里面當(dāng)前SYSENTER_EIP_MSR,SYSENTER_ESP_MSR,SYSENTER_CS_MSR這三個(gè)寄存器的值。
我們?cè)谖④浌_的內(nèi)核WRK中發(fā)現(xiàn)關(guān)于這三個(gè)寄存器的設(shè)置,其中SYSENTER_EIP_MSR設(shè)置的值是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上的一個(gè)例子,這個(gè)例子有點(diǎn)不厚道,在你卸載的時(shí)候會(huì)bsod.我簡(jiǎn)單修改了下,貼代碼如下:
#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;
}
注意一點(diǎn),大家用windbg的時(shí)候,配置symbol path,如圖:
后面貼上一篇墮落天才寫的文章鏈接:http://bbs.pediy.com/showthread.php?t=42705,
他inline hook 了KiFastCallEntry,采用detour方式,寫得很不錯(cuò)。
總結(jié)
以上是生活随笔為你收集整理的简单Hook SYSENTER的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 简单的IDT HOOK介绍
- 下一篇: 网上一个仿TP挂钩内核的源码