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方式,写得很不错。
  • 相关阅读:
    poj 2528 Mayor's posters (线段树+离散化)
    poj 1201 Intervals (差分约束)
    hdu 4109 Instrction Arrangement (差分约束)
    poj 1195 Mobile phones (二维 树状数组)
    poj 2983 Is the Information Reliable? (差分约束)
    树状数组 讲解
    poj 2828 Buy Tickets (线段树)
    hdu 1166 敌兵布阵 (树状数组)
    Ubuntu网络配置
    Button控制窗体变量(开关控制灯的状态)
  • 原文地址:https://www.cnblogs.com/dflower/p/1572526.html
Copyright © 2011-2022 走看看