Note
  • Introduction
  • PWN
    • __libc_csu_init函数的通用gadget
    • _int_malloc源码分析
    • _IO_FILE利用思路总结
    • C++ 虚表分析
    • Fast_bin笔记
    • house_of_force
    • House_of_Roman
    • Linux_ShellCode
    • Return-to-dl-resolve原理及利用
    • Unlink利用原理
    • Unsorted_Bin_Attack
    • 获取libc方法
    • 利用main_arena泄露libc基址
    • 整数溢出
    • 重写.fini_array函数指针
    • Windows_SEH利用
  • Windows_Operating_System
    • Dll隐藏
    • Dll注入之远程线程注入
    • IAT_HOOK原理实现
    • Windows下通用ShellCode原理
    • 代码注入
    • inline_hook框架
    • 32位程序调用64位函数原理
    • 调试原理
    • Windows异常处理初探
    • Windows_SEH利用
  • Windows_Kernel
    • MSR_HOOK
    • SSDT_HOOK
  • Virus_Analysis
  • Program
    • Dll的生成与使用
  • Miscellaneous
    • ctf笔记
    • 常见算法特征总结
    • ELF文件笔记
  • Linux_Operating_System
    • 系统调用
    • 分页机制
    • 调试原理
    • linux无文件执行elf
    • egg hunter
    • 缺失的动态链接库
  • Linux_Kernel
    • KERNEL_PWN状态切换原理及KPTI绕过
  • IOT
    • IOT调试环境搭建
    • mips_arm汇编学习
    • Cisco RV160W系列路由器漏洞:从1day分析到0day挖掘
  • Symbolic_Execution
    • angr初探
    • angr_进阶
  • Fuzz
    • UAF_overflow_check
    • intel-pin
  • CVE
    • Cisco RV160W系列路由器漏洞:从1day分析到0day挖掘
  • Assembly
    • Junk_Code_Analysis
    • opcode
  • Andriod_Security
Powered by GitBook
On this page

Was this helpful?

  1. Windows_Kernel

MSR_HOOK

32 位下 HOOk SYSENTER 实现进程保护。

OpenProcess的调用过程如下:

kernel32.OpenProcess -> kernelBa.OpenProcess -> ntdll.ZwOpenProcess -> ntdll.KiFastSystemCall ->(Ring0) _KiFastCallEntry -> (Ring0)NtOpenProcess

ZwOpenProcess中的代码如下:

mov eax,0xeb  //调用号
mov edx,KUSER_SHARED_SYSCALL 
// cpu初始化时,根据架构不同,KUSER_SHARED_SYSCALL里面的实现的内核函数指针接口也不同,可能是 KiIntSystemCall中断式系统调用 也可能是 KiFastSystemCall快速系统调用
call [edx]
ret 0x10

这里edx保存的是KiFastSystemCall函数,继续跟进KiFastSystemCall函数

mov edx,esp
sysenter 
retn

简单的三条指令,mov edx,esp 因为下一条指令SYSENTER就是进入内核层,由于每个线程都有一套线程上下文,都有一个独立的栈.。进入到内核后,内核也会使用自己的内核栈,所以这里先用edx保存栈顶esp。

SYSENTER 执行的时候,会读取三个特殊寄存器,从这三个特殊寄存器中取出内核栈的栈顶( esp ) ,内核代码段段选择子( cs ) ,以及代码的首地址( eip ),保存这三个值得寄存器是MSR寄存器组。这组寄存器没有名字,只有编号,由于没有名字,无法通过正常的汇编指令来存取值,Intel提供了两条指令来读写这些寄存器:

  • rdmsr 读取MSR寄存器 其中高32位存放在EDX 低32位存放在EAX(64位和32位是一样,只是64位时rdx和rcx的高32位会被清零),使用ECX传递寄存器编号

  • wrmsr 写入MSR寄存器,和读取一样写入时是用EDX表示高32位,EAX表示低32位,使用ECX传递寄存器编号

也就是说, Windows在启动,进行初始化的时候会将内核栈栈顶,内核CS段选择子,以及代码段地址(KiFastCallEntry 函数)的地址一一存放到MSR寄存器组的这几个编号的寄存器中。当 SYSENTER 被执行,,CPU就直接使用这些寄存器的值来初始化真正的CS , EIP , ESP 寄存器。因此, SYSENTER 执行之后, 就跑到内核的 KiFastCallEntry 函数中执行代码了。

而进行SYSENTER-HOOK时我们只需要关注代码的地址( SYSENTER_EIP_MSR )即可,它的编号是0x176。用类似于3环的Inline-Hook的方法,直接把该地址改为我们自己的函数地址,过滤检查传入的参数,这样就能实现HOOK保护进程了。具体用法如下:

#include <ntddk.h>

ULONG OldAddr;
VOID DriverUnload(PDRIVER_OBJECT pDriver_Object);
VOID OnHook();
UINT32 g_Pid = 2652;

void _declspec(naked) MyKiFastCallEntry()  //过滤参数
{
    __asm
    {
        cmp eax, 0xbe;//对比是否是NtOpenProcess的调用号
        jne _End;     //不是则不处理
        push eax;     //保存寄存器
        mov eax, [edx + 0x14];//获取第4个参数PCLIENT_ID
        mov eax, [eax];//获取PCLIENT_ID第一个字段PID
        //PCLIENT_ID->UniqueProcess的值       
        cmp eax, g_Pid;//判断是否是要保护的进程
        pop eax;
        jne _End;
        cmp[edx + 0xc], 1;//判断是否是关闭操作
        jne _End;
        mov[edx + 0xc], 0;//是就把访问权限设为无
    _End:
        jmp OldAddr;//调用原来的_KiFastCallEntry函数
    }
}

VOID OnHook(){
    KAFFINITY ActiveProcessors, CurrentAffinity;
    ActiveProcessors = KeQueryActiveProcessors();
    for (CurrentAffinity = 1; ActiveProcessors; CurrentAffinity <<= 1)  //考虑多核同步下,msr逻辑分离,所以修改每个内核的msr
    {
        if (ActiveProcessors & CurrentAffinity)
        {
            ActiveProcessors &= ~CurrentAffinity;
            KeSetSystemAffinityThread(CurrentAffinity);
            _asm
            {
                cli      // 锁,防止中断
                    push ecx
                    push eax
                    mov ecx, 0x176
                    rdmsr
                    mov OldAddr, eax //保存原来的 SYSENTER_EIP_MSR中的_KiFastCallEntry
                    xor eax, eax
                    mov eax, MyKiFastCallEntry // 将 SYSENTER_EIP_MSR寄存器的值设置为我们的过滤函数
                    wrmsr
                    xor eax, eax
                    xor ecx, ecx
                    pop eax
                    pop ecx
                    sti
            }
        }
    }
    DbgPrint("NewKiFastCallEntry Addr:%08x\n", MyKiFastCallEntry);

}


VOID DriverUnload(PDRIVER_OBJECT pDriver_Object)  //恢复HOOK
{
    KAFFINITY ActiveProcessors, CurrentAffinity;
    ActiveProcessors = KeQueryActiveProcessors();
    for (CurrentAffinity = 1; ActiveProcessors; CurrentAffinity <<= 1)
    {
        if (ActiveProcessors & CurrentAffinity)
        {
            ActiveProcessors &= ~CurrentAffinity;
            KeSetSystemAffinityThread(CurrentAffinity);
            _asm
            {
                cli
                    push ecx
                    push eax
                    mov ecx, 0x176
                    mov eax, OldAddr
                    wrmsr
                    xor ecx, ecx
                    xor eax, eax
                    pop eax
                    pop ecx
                    sti
            }
        }
    }
    DbgPrint("驱动卸载成功\n");
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver_Object, PUNICODE_STRING pRegstryString)
{
    OnHook();
    pDriver_Object->DriverUnload = DriverUnload;
    return STATUS_SUCCESS;

}
PreviousWindows_KernelNextSSDT_HOOK

Last updated 5 years ago

Was this helpful?