了解 hook_finder

Understanding hook_finder

我正在尝试了解 PE 格式和此处“hook_finder”的源代码 "https://github.com/Mr-Un1k0d3r/EDRs/blob/main/hook_finder64.c"

在这个片段中,我现在正在尝试计算 Export_Table 偏移量:

VOID DumpListOfExport(VOID *lib, BOOL bNt) {
    DWORD dwIter = 0;
    CHAR* base = (CHAR*)lib;
    CHAR* PE = base + (unsigned char)*(base + 0x3c); 
    DWORD ExportDirectoryOffset = *((DWORD*)PE + (0x8a / 4));
    CHAR* ExportDirectory = base + ExportDirectoryOffset;
    DWORD dwFunctionsCount = *((DWORD*)ExportDirectory + (0x14 / 4));
    DWORD OffsetNamesTableOffset = *((DWORD*)ExportDirectory + (0x20 / 4));
    CHAR* OffsetNamesTable = base + OffsetNamesTableOffset;

    printf("------------------------------------------\nBASE\t\t\t0x%p\t%s\nPE\t\t\t0x%p\t%s\nExportTableOffset\t0x%p\nOffsetNameTable\t\t0x%p\nFunctions Count\t\t0x%x (%d)\n------------------------------------------\n",
    base, base, PE, PE, ExportDirectory, OffsetNamesTable, dwFunctionsCount, dwFunctionsCount);

    for(dwIter; dwIter < dwFunctionsCount - 1; dwIter++) {
        DWORD64 offset = *((DWORD*)OffsetNamesTable + dwIter);
        CHAR* current = base + offset;
        GetBytesByName((HANDLE)lib, current, bNt);
    }
}

ox3c 是 e_lfnew 偏移量。但是,无法理解其他十六进制值是什么以及为什么除以 4 字节?

此外,

VOID GetBytesByName(HANDLE hDll, CHAR *name, BOOL bNt) {
    FARPROC ptr = GetProcAddress((HMODULE)hDll, name);
    DWORD* opcode = (DWORD*)*ptr;

    if(bNt) {
        if(name[0] != 'N' && name[1] != 't') {
            return;
        }
    }
    
    if((*opcode << 24) >> 24 == 0xe9) {
        if(!IsFalsePositive(name)) {
            printf("%s is hooked\n", name);
        }
    }
}

什么是左右移动,为什么是 24? 根据我对EDR的理解,它在函数的最开头添加了一条JMP指令,这就是为什么条件试图检查它是否是(0xe9),但是它如何遵循并确定函数流程?

这是否仅适用于 ntdll.dll?

抱歉,我开始研究 PE 行为并试图让事情变得非常清楚。

提前致谢

函数DumpListOfExport假设NtHeaders从基址的偏移量0x3c开始,但是,根据大小的不同,情况并非总是如此DOS存根。可能,这段代码对 ntdll.dll.

做了这样的假设

并且在函数 GetBytesByName 中,如果过程的第一个字节以 JMP 开头(在这种情况下,它是 near,相对 jmp,其操作码以 开头” E9") 指令且过程名称不在误报列表中,则该函数决定该函数被挂钩。

设为opcode 0xca0e4be9指向的4个字节的值,左移24将得到0xe9000000,然后右移 24,结果将是 0x000000e9,这是 ptr.

处第一个字节的值

该程序可以简化如下。

VOID GetBytesByName(HANDLE hDll, CHAR *name, BOOL bNt) {
    FARPROC ptr = GetProcAddress((HMODULE)hDll, name);
    BYTE* opcode = (BYTE*)ptr;

    if(bNt) {
        if(name[0] != 'N' && name[1] != 't') {
            return;
        }
    }
    
    if(!IsFalsePositive(name) && *opcode == 0xe9) {
        printf("%s is hooked\n", name);
    }
}

: 我可以说代码写得不好,也没有遵循任何好的编码风格。