免杀基础-hook
Arcueid 发表于 浙江 二进制安全 262浏览 · 2024-12-11 01:13

hook

什么是hook 用于拦截函数的执行过程,以获取或修改其执行时的数据 更改执行流程的一种技术

大体分两种

修改函数代码和修改函数地址

InlineHook

第一种我们称之为INLINE HOOK(内联hook) 它的特点是直接修改目标函数的代码,例如在函数入口处插入跳转指令,将控制流引导至自定义的处理逻辑,从而实现对函数行为的拦截和修改

32位下patch 目标函数前7个字节 目的是替换成自己的汇编 跳转到指定地址 这里用0x00占位

0xB8, 0x00, 0x00, 0x00, 0x00,     // mov eax, lpMem
0xFF, 0xE0                        // jmp eax

编写代替函数 在函数内解除hook防止无限循环 再重新挂钩

int myMessageBoxW(
    _In_opt_ HWND hWnd,
    _In_opt_ LPCWSTR lpText,
    _In_opt_ LPCWSTR lpCaption,
    _In_ UINT uType) {
    printf("111111111\n");

    memcpy(Hookedfunc, originalBytes, 7);
    int res = MessageBoxW(hWnd, lpText, lpCaption, uType);
    installHook(Hookedfunc, myMessageBoxW);
    return res;
};

hook 直接将函数开始的地方改为我们需要的硬编码 jmp到指定函数

void installHook(LPVOID Hookedfunc,LPVOID targetFunc) {

    DWORD oldProtection;

    char code[] = { 0xB8, 0x00, 0x00, 0x00, 0x00,     // mov eax, lpMem
                    0xFF, 0xE0                        // jmp eax
    };
    memcpy(originalBytes, Hookedfunc, 7); 

    DWORD_PTR lpMem = (DWORD_PTR)targetFunc;
    memcpy(&code[1], &lpMem, sizeof(lpMem));

    VirtualProtect(Hookedfunc, sizeof(code), PAGE_EXECUTE_READWRITE, &oldProtection);
    memcpy(Hookedfunc, code, sizeof(code));

}

64位的也差不多

int myMessageBoxW(
    _In_opt_ HWND hWnd,
    _In_opt_ LPCWSTR lpText,
    _In_opt_ LPCWSTR lpCaption,
    _In_ UINT uType) {
    printf("111111111\n");

    memcpy(Hookedfunc, originalBytes, 13);
    int res = MessageBoxW(hWnd, lpText, lpCaption, uType);
    installHook(Hookedfunc, myMessageBoxW);
    return res;
};

void installHook(LPVOID Hookedfunc,LPVOID targetFunc) {

    DWORD oldProtection;
    char code[] = { 0x49, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r10, lpMem
                    0x41, 0xFF, 0xE2                                            // jmp r10
    };

    memcpy(originalBytes, Hookedfunc, 13);
    DWORD_PTR lpMem = (DWORD_PTR)targetFunc;
    memcpy(&code[2], &lpMem, sizeof(lpMem));

    VirtualProtect(Hookedfunc, sizeof(code), PAGE_EXECUTE_READWRITE, &oldProtection);
    memcpy(Hookedfunc, code, sizeof(code));

}

这里还有很多优化的空间 但是对免杀来说已经够用了

IAT HOOK

第二种是修改函数的地址 比如常说的IAT hook SSDT hook

这类的特点是函数地址需要查表得到 那么我们可以篡改这个表来达到修改执行函数的目的

这里以IAT HOOK举例 通常是往目标进程注入dll 这里为了方便直接在当前进程搞了

首先获取到IAT 获取要hook的函数的地址

HMODULE hModule = GetModuleHandle(NULL);
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule;
    PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)hModule + pDosHeader->e_lfanew);
    PIMAGE_DATA_DIRECTORY pDataDir = (PIMAGE_DATA_DIRECTORY)&pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
    PIMAGE_IMPORT_DESCRIPTOR pimport = (PIMAGE_IMPORT_DESCRIPTOR)(pDataDir->VirtualAddress + (DWORD_PTR)hModule);


    FARPROC funcAddr = NULL;

    while (pimport->Name != 0) {

        PIMAGE_THUNK_DATA pOriginalThunk = (PIMAGE_THUNK_DATA)((DWORD_PTR)hModule + pimport->OriginalFirstThunk);
        PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)((DWORD_PTR)hModule + pimport->FirstThunk);

        while (pOriginalThunk->u1.AddressOfData != 0) {

             PIMAGE_IMPORT_BY_NAME pImportByName = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)hModule + pOriginalThunk->u1.AddressOfData);
             if (_stricmp(pImportByName->Name, "MessageBoxW")==0) {
                 funcAddr = (FARPROC)pThunk->u1.Function;
                 break;
             }

            pOriginalThunk++;
            pThunk++;
        }
        pimport++;
    }

    MessageBoxW(0, 0, 0, 0);

定义恶意函数 替换掉IAT中的目标函数为恶意函数

PVOID oldMessageBox = MessageBoxW;

typedef int (WINAPI* pMessageBoxW)(
    _In_opt_ HWND hWnd,
    _In_opt_ LPCWSTR lpText,
    _In_opt_ LPCWSTR lpCaption,
    _In_ UINT uType);


int myMessageBoxW(
    _In_opt_ HWND hWnd,
    _In_opt_ LPCWSTR lpText,
    _In_opt_ LPCWSTR lpCaption,
    _In_ UINT uType) {
    printf("111111111\n");
    pMessageBoxW MsgBox = (pMessageBoxW)oldMessageBox;
    return MsgBox(hWnd, lpText, lpCaption, uType);
};
....

PIMAGE_IMPORT_BY_NAME pImportByName = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)hModule + pOriginalThunk->u1.AddressOfData);
             if (_stricmp(pImportByName->Name, "MessageBoxW")==0) {
                 VirtualProtect(&pThunk->u1.Function, 8, PAGE_READWRITE, &oldProtect);
                 pThunk->u1.Function = (DWORD_PTR)myMessageBoxW;
                 VirtualProtect(&pThunk->u1.Function, 8, oldProtect, &oldProtect);
                 break;
             }

SSDT Hook

首先是获取SSDT

直接使用导出的全局变量KeServiceDescriptorTable即可

typedef struct _ServiceDescriptorTable{
    PVOID pSSDTBase;
    PVOID pServiceCounterTable;
    ULONG ulNumberOfServices;
    PVOID pParamTableBase;
} ServiceDescriptorTable, * PServiceDescriptorTable;

extern PServiceDescriptorTable KeServiceDescriptorTable;

这里我们选择hook NtAllocateVirtualMemory

调用号13

获取NtAllocateVirtualMemory的地址

__try {
        PVOID serviceTableBase = KeServiceDescriptorTable->pSSDTBase;
        PVOID NtAllocateVirtualMemoryBase = (DWORD_PTR)serviceTableBase + (0x13 * sizeof(void*));
        DbgPrint("0x%p\n", NtAllocateVirtualMemoryBase);
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        return GetExceptionCode();
    }

修改表中函数

__try {
        PVOID serviceTableBase = KeServiceDescriptorTable->pSSDTBase;
        NtAllocateVirtualMemoryBase = (DWORD_PTR)serviceTableBase + (0x13 * sizeof(PVOID));
        DbgPrint("0x%p\n", NtAllocateVirtualMemoryBase);
        oriNtAllocateVirtualMemoryProc = *(PVOID*)NtAllocateVirtualMemoryBase;
        *(PVOID*)NtAllocateVirtualMemoryBase = myNtAllocateVirtualMemory;

        DbgPrint("Hooked!\n");

    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        return GetExceptionCode();
    }

定义替换的函数

PVOID NtAllocateVirtualMemoryBase = NULL;
PVOID oriNtAllocateVirtualMemoryProc = NULL;
NTKERNELAPI PCHAR PsGetProcessImageFileName(PEPROCESS Process);


typedef NTSTATUS (NTAPI* pNtAllocateVirtualMemory)(
    _In_ HANDLE ProcessHandle,
    _Inout_ _At_(*BaseAddress, _Readable_bytes_(*RegionSize) _Writable_bytes_(*RegionSize) _Post_readable_byte_size_(*RegionSize)) PVOID* BaseAddress,
    _In_ ULONG_PTR ZeroBits,
    _Inout_ PSIZE_T RegionSize,
    _In_ ULONG AllocationType,
    _In_ ULONG Protect
);

NTSTATUS NTAPI myNtAllocateVirtualMemory(
    _In_ HANDLE ProcessHandle,
    _Inout_ _At_(*BaseAddress, _Readable_bytes_(*RegionSize) _Writable_bytes_(*RegionSize) _Post_readable_byte_size_(*RegionSize)) PVOID* BaseAddress,
    _In_ ULONG_PTR ZeroBits,
    _Inout_ PSIZE_T RegionSize,
    _In_ ULONG AllocationType,
    _In_ ULONG Protect
) {
    HANDLE currentProcess = PsGetCurrentProcess();
    PCHAR currentProcessName = PsGetProcessImageFileName(currentProcess);
    DbgPrint("%s\n", currentProcessName);
    if (_stricmp(currentProcessName, "Console.") == 0) {
        DbgPrint("111111\n");
    } 
    pNtAllocateVirtualMemory oriNtAllocateVirtualMemory = (pNtAllocateVirtualMemory)oriNtAllocateVirtualMemoryProc;
    return oriNtAllocateVirtualMemory(ProcessHandle, BaseAddress, ZeroBits, RegionSize, AllocationType, Protect);
}

因为这里分配内存是一个很常用的功能 我们指定只有当进程名为Console.exe 调用NtAllocateVirtualMemory时才进行相关输出

卸载时unhook

NTSTATUS UnloadDriver(PDRIVER_OBJECT DriverObject){
    *(PVOID*)NtAllocateVirtualMemoryBase = oriNtAllocateVirtualMemoryProc;
    DbgPrint("Unload!");
}

基于Detours

Detours是微软开源的hook库 使用起来也非常简单

#include <Windows.h>
#include <iostream>
#include <detours.h>


int
WINAPI
MyMessageBoxA(
    _In_opt_ HWND hWnd,
    _In_opt_ LPCSTR lpText,
    _In_opt_ LPCSTR lpCaption,
    _In_ UINT uType) {
    std::cout << "Hooked!" << std::endl;
    return 0;
}


int main()
{

    auto msgbox = (void *)MessageBoxA;

    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
    DetourAttach(&msgbox, MyMessageBoxA);
    DetourTransactionCommit();

    MessageBoxA(0, 0, 0, 0);

    getchar();
}

pe文件中存在明显特征 可以通过修改disasm.cpp来修改

0 条评论
某人
表情
可输入 255