其实所有的HOOK,都基本是一样道理。就是勾住你的目标函数,实现你自己的功能。只要你掌握了,HOOK的原理。剩下的就是寻找目标函数了。

今天回忆一下 HOOK SYSENTER,目的当然还是继续充实自己的BLOG,继续灌水。

一:认识SYSENTER

SYSENTER是一个东西?大家都知道调用门,陷阱门,任务门(这里没有照片!_!).。通过他们我们可以从R3到达R0。简单的说SYSENTER就是他们的替代品。SYSENTER是一个入的

过程,SYSEXIT是他的反过程。

我们以OpenProcess为例,看看他是怎么从R3-R0

kernel32!OpenProcess -> ntdll!ZwOpenProcess -> ntdll!KiFastSystemCall -> sysenter -> nt!KiFastCallEntry -> nt!NtOpenProcess -> nt!KiFastCallEntry> nt!

KiServiceExit -> sysexit -> ntdll!KiFastSystemCallRet -> kernel32!OpenProcess

现在来看看SYSENTER是怎么样处理的。

R3-R0需要把相关的工作交给R0层的。包括:设置CS,IP,SS,SP。SYSENTER有三个特殊的寄存器(MSR)来帮助我们完成。

SYSENTER_CS_MSR

SYSENTER_ESP_MSR

SYSENTER_EIP_MSR

他们的地址分别是:0x174,0x175,0x176。我们可以通过指令rdmsr/wrmsr。来读写这三个寄存器。相关代码如下:

_asm
{

mov ecx,0x176
    rdmsr
    mov OldKiFastCallEntry,eax

}

我们来看看SYSENTER的工作流程。

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例程

SYSEXIT的工作流程

1. SYSENTER_CS_MSR+16装载到 CS寄存器
2. 将EDX的值送入EIP
3. SYSENTER_CS_MSR+24 装载到SS寄存器
4. 将ECX的值送入ESP
5. 切换回RING3
6. 执行EIP处的RING3指令

这样就完成了R3-RO-R3的过程。

二:相关代码

//
// Hook SysEnter.cpp文件

extern "C"
{
#include <ntddk.h>
}

VOID UnloadDriver(PDRIVER_OBJECT pDriverObj);

ULONG OldKiFastCallEntry;

VOID NewKiFastCallEntry()
{
DbgPrint("一个系统调用...\n");
_asm
{
   jmp DWORD PTR[OldKiFastCallEntry]

}
}

// 驱动程序加载时调用DriverEntry例程
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegistryString)
{
pDriverObj->DriverUnload = UnloadDriver;
//
_asm
{
   mov ecx,0x176
   rdmsr
   mov OldKiFastCallEntry,eax
   mov eax,NewKiFastCallEntry
   wrmsr
}

// 请视情况返回DriverEntry例程执行结果
return STATUS_SUCCESS;
}

VOID UnloadDriver(PDRIVER_OBJECT pDriverObj)
{
_asm
{
   mov ecx,0x176
   xor edx,edx
   mov eax,OldKiFastCallEntry
   wrmsr

}

}

=============================================================================================

呵呵,今天这篇内容少,比较简单。

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个寄存器。步骤如下:

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例程


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,如图:

后面贴上一篇堕落天才写的文章链接:http://bbs.pediy.com/showthread.php?t=42705,
他inline hook 了KiFastCallEntry,采用detour方式,写得很不错。

简单Hook SYSENTER相关推荐

  1. python xposed_xposed与frida简单使用对比

    Hooks Xposed 两种方法分别使用了Android.python+JS作为开发语言进行hook. APP 这个APP是在学习frida的时候看到的,非常简单,有源码,有apk,用来作一个这种类 ...

  2. (4.6.29.3)插件化之代码加载:启动Activity等四大组件之hook方式

    文章目录 一.代理模式和Hook原理 1.1 Hook 原理 1.2 代理模式 二.Binder Hook 2.1 分析:系统服务的获取过程 2.2 寻找Hook点 2.3 hook Binder示例 ...

  3. Windows下x86和x64平台的Inline Hook介绍

    原文链接:https://blog.csdn.net/PeaZomboss/article/details/129095200?spm=1001.2014.3001.5501 前言 我在之前研究文明6 ...

  4. 在NP下用OD调试游戏的方法

    一.NP用户层监视原理 NP启动后通过WriteProcessMemory跟CreateRemoteThread向所有进程注入代码(除了系统进程smss.exe),代码通过np自己的LoadLibra ...

  5. 在NP下用OD调试游戏的方法(转)

    一.NP用户层监视原理 NP启动后通过WriteProcessMemory跟CreateRemoteThread向所有进程注入代码(除了系统进程smss.exe),代码通过np自己的LoadLibra ...

  6. 反NP监视原理并有实例说明

    ******************************************* *标题:[原创]反NP监视原理 *作者:堕落天才 *日期:2007年1月3号 *版权声明:请保存文章的完整,转Q ...

  7. WL 2009 professional【已解决】谢谢nooby跟海风

    WL 2009 professional[已解决]谢谢nooby跟海风 研究这个好久了,从中也学习到了不少东西 帮朋友研究XX的反调试,一个没见过的反调试,不能断点,输出是WL 2009 首先当然是用 ...

  8. Android 插件化原理解析——Service的插件化

    在 Activity生命周期管理 以及 广播的管理 中我们详细探讨了Android系统中的Activity.BroadcastReceiver组件的工作原理以及它们的插件化方案,相信读者已经对Andr ...

  9. 如何通过 Tampermonkey 快速查找 JavaScript 加密入口

    在很多情况下,我们可能想要在网页中自动执行某些代码,帮助我们完成一些操作.如自动抢票.自动刷单.自动爬虫等等,这些操作绝大部分都是借助 JavaScript 来实现的.那么问题来了?在浏览器里面怎样才 ...

最新文章

  1. 教你用Python解决非平衡数据问题(附代码)
  2. 卓越软件工程--《微软360度》读后感
  3. windows下配置cvs服务端
  4. PyCUDA Documentation
  5. 苹果移动设备用什么管理比较好?有什么推荐?
  6. LeetCode Map Sum Pairs
  7. 【元胞自动机】基于matlab元胞自动机单边教室疏散【含Matlab源码 1207期】
  8. opencv的第一个lena图片显示
  9. linux sipp 呼叫转移_★★★★盲转接业务的sipp脚本实现
  10. java模拟新浪微博_用java程序模拟登陆新浪微博
  11. httpwatch使用_使用JavaScript的HTTPWatch自动化
  12. led灯选用什么品牌的比较好?2022最新led光源品牌排行榜
  13. 说一说递归里的return返回!!!
  14. radosgw bucket index sharding
  15. 微型计算机第六章课后答案,微型计算机原理及其接口技术第六章部分习题.doc...
  16. jpg格式图片打不开怎么办
  17. scala学习之scala中一些集合的常用函数
  18. 一种串口接收完成判断方法
  19. liunx服务配置 详细版
  20. 映射html源码,[译] 源代码映射(Source Map)简介

热门文章

  1. 用户操作-登录流程分析
  2. GraphQL入门之graphql-java项目的介绍
  3. 请使用日期时间相关的API,计算出一个人已经出生了多少天
  4. spring事务管理-Transaction模板(了解)
  5. 非对称加密算法 - Java加密与安全
  6. Bootstrap组件_按钮组
  7. AtomicStampedReference实现
  8. h5的fetch方法_你不需要jQuery(三):新AJAX方法fetch()
  9. python matlib库_python matplotlib 库学习
  10. 09 Softmax 回归 + 损失函数 + 图片分类数据集【动手学深度学习v2】