编写驱动Hook SSDT


编写驱动Hook SSDT

查找函数偏移

要hook SSDT中的函数,就必须先找到这个函数在SSDT表中的偏移才能修改这个偏移上的地址

随意打开一个程序,下个API调用时候的断点,这里下writeFile的断点

下断点

F8调试指导出现调用ntdll中的系统函数NtWirteFile,F7步入,0x112就是WriteFile在SSDT中的偏移

F8调试

0x112偏移

在Windbg中查看是否正确

找到NtWriteFile

编写驱动

这里Hook了NtOpenProcess函数,查找过程与上一节相似,不再赘述

#include <ntddk.h>

typedef struct _ServiceDescriptorTable // SSDT结构体
{
    PVOID ServiceTableBase;
    PVOID ServiceCount;
    ULONG NumberOfService;
    PVOID PararmTableBase;
} *PServiceDescriptorTable;

//导出KeServiceDescriptorTable,使系统能够修改该结构体
extern PServiceDescriptorTable KeServiceDescriptorTable;  

ULONG FunAddress;
ULONG OldServiceTable;
ULONG JmpAddress;

VOID Hook();
VOID Unhook();
VOID DriverUnload(PDRIVER_OBJECT pDriverObject);

//新的NtOpenProcess函数,与原来的函数参数结构保持一样
_declspec(naked) VOID _stdcall newNtOpenProcess(
    _Out_ PHANDLE ProcessHandle,
    _In_ ACCESS_MASK DesiredAccess,
    _In_ POBJECT_ATTRIBUTES ObjectAttributes,
    _In_opt_ PCLIENT_ID ClientId
) {
    /*这里编写Hook内容*/
    KdPrint(("进入Hook函数\n"));
    /****************/


    //在执行完自己写的函数之后执行Hook前的函数并跳转到原来的地址
    _asm
    {
        push 0xc4  
        push 0x804f52d8
        jmp[JmpAddress]
    }
}

//main函数
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING reg_path)
{
    KdPrint(("驱动加载成功\n"));
    Hook();
    pDriverObject->DriverUnload = DriverUnload; //驱动卸载函数
    return STATUS_SUCCESS;
}

_declspec(naked) VOID CLOSE_INT() {
    _asm
    {
        cli  //关中断
        mov eax, cr0
        and eax, 0xfffeffff //修改cr0写保护位为r3不可写
        mov cr0, eax
        ret
    }
}

_declspec(naked) VOID OPEN_INT() {
    _asm
    {
        mov eax, cr0
        or eax, 0x10000 //恢复cr0
        mov cr0, eax
        sti //开中断
        ret
    }
}

VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
    KdPrint(("驱动卸载成功\n"));
    Unhook();
}

VOID Hook() {
    FunAddress = (ULONG)KeServiceDescriptorTable->ServiceTableBase + 0x7a * 4; //基址 + 函数编号 x 4
    KdPrint(("FunAddress = % x\n", FunAddress));

    OldServiceTable = *(ULONG*)FunAddress;  //保存原始地址,以便卸载后恢复原始地址
    KdPrint(("OldServiceTable = % x\n", OldServiceTable));

    //保存Hook执行完的跳转地址,定为NtOpenProcess第二条指令之后
    //8058270a 68c4000000      push    0C4h
    //8058270f 68d8524f80      push    offset nt!ObWatchHandles+0x25c (804f52d8)
    JmpAddress = (ULONG)NtOpenProcess + 10; 
    KdPrint(("JmpAddress = % x\n", JmpAddress));

    CLOSE_INT();

    *(ULONG*)FunAddress = (ULONG)newNtOpenProcess; //修改原来的地址为新的Hook地址

    OPEN_INT();
}

VOID Unhook() {
    FunAddress = (ULONG)KeServiceDescriptorTable->ServiceTableBase + 0x7a * 4;
    CLOSE_INT();

    *(ULONG*)FunAddress = (ULONG)OldServiceTable; //将地址恢复成原来的地址

    OPEN_INT();

    KdPrint(("Hook恢复成功"));
}

文章作者: Kevin。
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Kevin。 !
评论
 上一篇
Windows进程和线程 Windows进程和线程
Windows进程和线程众所周知,进程是空间,线程是任务 进程结构体进程有两个结构体_kprocess和_eprocess,_eprocess继承了_kprocess 在Windbg中可以使用dt _kprocess [ADDR] 和dt
2022-05-14
下一篇 
int 0x2e和sysenter int 0x2e和sysenter
int 0x2e和sysenterint 0x2eint 0x2e是一个自陷(Trap)指令,告诉CPU将用户态切换成系统态。从TSS中装入本线程的系统空间堆栈段寄存器SS和堆栈指针寄存器ESP,再将SS、ESP、EFLAGS、CS、EIP
2022-04-29
  目录