注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

熊猫正正的博客

熊猫正正的天空

 
 
 

日志

 
 

Rootkit hook之[六] sysenter Hook  

2012-03-16 14:14:13|  分类: window驱动学习 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
标 题: 【原创】rootkit hook之[六] -- sysenter Hook
作 者: combojiang
时 间: 2008-02-26,12:25:40
链 接: 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个寄存器。步骤如下:
Rootkit hook之[六] sysenter Hook - 熊猫正正 - 熊猫正正的博客
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例程 

Rootkit hook之[六] sysenter Hook - 熊猫正正 - 熊猫正正的博客
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; 
}

  评论这张
 
阅读(144)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017