zoukankan      html  css  js  c++  java
  • 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
查看次数: 2138
文件大小:  8.0 KB
    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
查看次数: 2130
文件大小:  7.0 KB
    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
查看次数: 2149
文件大小:  17.0 KB

    后面贴上一篇堕落天才写的文章链接:http://bbs.pediy.com/showthread.php?t=42705,
    他inline hook 了KiFastCallEntry,采用detour方式,写得很不错。
  • 相关阅读:
    朴灵:基于MongoDB与NodeJS构建物联网系统
    平均年薪40万!为什么却很少见程序员炫富?
    写春联、变魔术、模仿马云唱歌_为你揭秘阿里云人工智能ET背后的技术
    Mysql查询性能优化-善用Explain语句
    numpy linspace arange函数
    vim笔记
    redis压缩列表
    tensorflow笔记之反向传播时用到的几种方法
    损失函数
    kafka 修改partition,删除topic,查询offset
  • 原文地址:https://www.cnblogs.com/dflower/p/1572526.html
Copyright © 2011-2022 走看看