inline hook

我们一般把给代码打补丁的技术称作inline hook,代码补丁分静态(磁盘PE文件)和动态(内存映像),这里说的是动态热补丁。原理不必讲,下面一张图可以帮助理解这项技术:

inline hook_第1张图片

inline hook是给代码打补丁,这和hook调用表(IAT/IDT/SSDT等)技术有着本质区别。补丁出现在代码位置的任意性和跳转指令的多样性,导致inline hook比hook调用表更难被检测到。

其中跳转指令可以是jmp/call/ret等。使用inline hook来编写rootkit时,关键还是要识别Anti-rootkit软件是使用什么技术来做的检测。下面是hook NtCreateFile函数的代码:

#include <ntddk.h>
#include <windef.h>
 
ULONG g_addr_NtCreateFile; /* Save NtCreateFile address */
ULONG g_uCr0;
 
BYTE g_PatchCode[5] = { 0xE9, 0×00, 0×00, 0×00, 0×00 };
BYTE g_SavedCode[5] = { 0×00 };
 
BYTE g_JmpBackCode[7] = /* long jmp:0×08, 0×00 */
{ 0xEA, 0×00, 0×00, 0×00, 0×00, 0×08, 0×00 };
 
void DisableWriteProtect();
void EnableWriteProtect();
VOID OnUnload(IN PDRIVER_OBJECT DriverObject);
ULONG GetFuncAddr(IN PCWSTR funcName);
VOID HookNtCreateFile();
VOID UnHookNtCreateFile();
 
__declspec (naked) VOID proxy_NtCreateFile()
{
    __asm {
        _emit 0×90
        _emit 0×90
        _emit 0×90
        _emit 0×90
        _emit 0×90 /*5 byte g_SavedCode*/
        _emit 0×90 /*7 byte g_JmpBackCode*/
        _emit 0×90
        _emit 0×90
        _emit 0×90
        _emit 0×90
        _emit 0×90
        _emit 0×90
    }
}
 
__declspec (naked) VOID fake_NtCreateFile()
{
    //to do: hook功能代码
    //DbgPrint(“NtCreateFile calling…\n”);
    __asm
    {
        jmp proxy_NtCreateFile
    }
}
 
NTSTATUS DriverEntry(IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath)
{
    DbgPrint(“Inline hook begin.”);
    theDriverObject->DriverUnload = OnUnload;
 
    g_addr_NtCreateFile = GetFuncAddr(L”NtCreateFile”);
    HookNtCreateFile();
 
    return STATUS_SUCCESS;
}
 
VOID OnUnload(IN PDRIVER_OBJECT DriverObject)
{
    DbgPrint(“Inline hook end.”);
    UnHookNtCreateFile();
}
 
VOID HookNtCreateFile()
{
    KIRQL oldIrql;
 
    if (g_addr_NtCreateFile == (ULONG)NULL) {
        DbgPrint(“\n***NtCreateFile addr is NULL.***\n”);
        return;
    }
 
    DbgPrint(“NtCreateFile’s addr: 0x%08x\n”, (ULONG)g_addr_NtCreateFile);
 
    /* 保存原始指令*/
    RtlCopyMemory(g_SavedCode, (BYTE*)g_addr_NtCreateFile, 5);
 
    /* 构造并写入跳转指令(函数内近jmp,使用相对地址)*/
    *((ULONG*)(g_PatchCode + 1)) = (ULONG)fake_NtCreateFile – (ULONG)g_addr_NtCreateFile – 5;
    DisableWriteProtect(); /*禁止系统写保护*/
    oldIrql = KeRaiseIrqlToDpcLevel(); /*提升IRQL到DPC*/
    RtlCopyMemory((BYTE*)g_addr_NtCreateFile, g_PatchCode, 5);
 
    /* 构造Patch代码 */
    *((ULONG*)(g_JmpBackCode + 1)) = (ULONG)((BYTE*)g_addr_NtCreateFile + 5);
    RtlCopyMemory((BYTE*)proxy_NtCreateFile, g_SavedCode, 5);
    RtlCopyMemory((BYTE*)proxy_NtCreateFile + 5, g_JmpBackCode, 7);
 
    KeLowerIrql(oldIrql);
    EnableWriteProtect();
}
 
VOID UnHookNtCreateFile()
{
    KIRQL oldIrql;
 
    DisableWriteProtect();
    oldIrql = KeRaiseIrqlToDpcLevel();
    RtlCopyMemory((BYTE*)g_addr_NtCreateFile, g_SavedCode, 5);
 
    KeLowerIrql(oldIrql);
    EnableWriteProtect();
}
 
ULONG GetFuncAddr(IN PCWSTR funcName)
{
    UNICODE_STRING _toUniCode;
    RtlInitUnicodeString(&_toUniCode, funcName);
    return (ULONG)MmGetSystemRoutineAddress(&_toUniCode);
}
 
void DisableWriteProtect()
{
    ULONG uAttr;
    _asm
    {
        push eax;
        mov eax, cr0;
        mov uAttr, eax;
        and eax, 0FFFEFFFFh;
        mov cr0, eax;
        pop eax;
        cli
    };
    g_uCr0 = uAttr;
}
 
VOID EnableWriteProtect()
{
    _asm
    {
        sti
        push eax;
        mov eax, g_uCr0;
        mov cr0, eax;
        pop eax;
    };
}


你可能感兴趣的:(inline hook)