【免杀技术】WinApi规避 - 字符串HASH与动态调用 (完美的IAT隐藏技术)
字数 1511 2025-08-22 12:23:30

WinAPI规避技术:字符串HASH与动态调用实现完美IAT隐藏

1. 技术概述

本文介绍一种高级的WinAPI规避技术,通过字符串HASH与动态调用相结合的方式实现完美的IAT(Import Address Table)隐藏。该技术不仅能有效规避杀毒软件的静态分析,还能避免敏感信息在可执行文件中暴露。

2. 技术核心组件

2.1 CRT库删除

必要性

  • 标准CRT库会引入大量不必要的API调用(如GetModuleHandle和GetProcAddress)
  • CRT库会残留大量字符串硬编码在可执行文件中
  • 删除CRT可减少被溯源的风险

Visual Studio编译参数设置

/GS- /Zl /Oy- /Oi /GL /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /Gm- /EHsc /MT /W3 /nologo /c /Zi /Fd"Debug\vc141.pdb" /errorReport:none

影响

  • 标准库函数如memcpy、memset、printf等将无法使用
  • 需要自行实现这些功能或寻找替代API

示例:自实现memset

void* __cdecl my_memset(void* Destination, int Value, size_t Size) {
    unsigned char* p = (unsigned char*)Destination;
    while (Size > 0) {
        *p = (unsigned char)Value;
        p++;
        Size--;
    }
    return Destination;
}

2.2 自定义HASH算法

HASH算法设计

#define INITIAL_HASH 520
#define SEED 6

// ANSI字符串版本
DWORD HashStringLoseLoseA(_In_ PCHAR String) {
    ULONG Hash = INITIAL_HASH;
    INT c;
    while (c = *String++) {
        Hash += c;
        Hash *= c + SEED; // 更新哈希值
    }
    return Hash;
}

// 宽字符版本
DWORD64 HashStringLoseLoseW(_In_ PWCHAR String) {
    ULONG Hash = INITIAL_HASH;
    INT c;
    while (c = *String++) {
        Hash += c;
        Hash *= c + SEED;
    }
    return Hash;
}

特点

  • INITIAL_HASH和SEED可自定义
  • 算法简单高效,适合运行时计算
  • 提供ANSI和Unicode两个版本

3. 核心API自实现

3.1 自实现GetModuleHandleH

功能:通过HASH值而非明文字符串查找模块基址

实现代码

HMODULE GetModuleHandleH(DWORD dwModuleNameHash) {
    if (dwModuleNameHash == NULL) return NULL;
    
    // 64位下PEB,进程环境块
    PPEB pPeb = (PPEB)(__readgsqword(0x60));
    // 获取LDR
    PPEB_LDR_DATA pLdr = (PPEB_LDR_DATA)(pPeb->Ldr);
    // 获取链表第一个元素(包含第一个模块的信息)
    PLDR_DATA_TABLE_ENTRY pDte = (PLDR_DATA_TABLE_ENTRY)(pLdr->InMemoryOrderModuleList.Flink);
    
    while (pDte) {
        if (pDte->FullDllName.Length != NULL) {
            // 比较HASH值而非明文字符串
            if (HashStringLoseLoseW(pDte->FullDllName.Buffer) == dwModuleNameHash) {
                return pDte->Reserved2[0];
            }
        } else {
            break;
        }
        pDte = *(PLDR_DATA_TABLE_ENTRY*)(pDte);
    };
    return NULL;
}

关键点

  • 通过PEB结构遍历已加载模块
  • 使用__readgsqword(0x60)获取PEB地址(x64架构)
  • 比较模块名的HASH值而非明文字符串

3.2 自实现GetProcAddressH

功能:通过HASH值查找导出函数地址

实现代码

FARPROC GetProcAddressH(HMODULE hModule, DWORD dwApiNameHash) {
    if (hModule == NULL || dwApiNameHash == NULL) return NULL;
    
    PBYTE pBase = (PBYTE)hModule;
    PIMAGE_DOS_HEADER pImgDosHdr = (PIMAGE_DOS_HEADER)pBase;
    if (pImgDosHdr->e_magic != IMAGE_DOS_SIGNATURE) return NULL;
    
    PIMAGE_NT_HEADERS pImgNtHdrs = (PIMAGE_NT_HEADERS)(pBase + pImgDosHdr->e_lfanew);
    if (pImgNtHdrs->Signature != IMAGE_NT_SIGNATURE) return NULL;
    
    IMAGE_OPTIONAL_HEADER ImgOptHdr = pImgNtHdrs->OptionalHeader;
    PIMAGE_EXPORT_DIRECTORY pImgExportDir = (PIMAGE_EXPORT_DIRECTORY)(pBase + ImgOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
    
    PDWORD FunctionNameArray = (PDWORD)(pBase + pImgExportDir->AddressOfNames);
    PDWORD FunctionAddressArray = (PDWORD)(pBase + pImgExportDir->AddressOfFunctions);
    PWORD FunctionOrdinalArray = (PWORD)(pBase + pImgExportDir->AddressOfNameOrdinals);
    
    for (DWORD i = 0; i < pImgExportDir->NumberOfFunctions; i++) {
        CHAR* pFunctionName = (CHAR*)(pBase + FunctionNameArray[i]);
        PVOID pFunctionAddress = (PVOID)(pBase + FunctionAddressArray[FunctionOrdinalArray[i]]);
        
        // 比较函数名的HASH值
        if (dwApiNameHash == HashStringLoseLoseA(pFunctionName)) {
            return pFunctionAddress;
        }
    }
    return NULL;
}

关键点

  • 解析PE文件结构定位导出表
  • 遍历导出函数名称并计算HASH
  • 匹配HASH值返回对应函数地址

4. 技术使用示例

4.1 HASH值计算

在使用前需要预先计算API名称和DLL名称的HASH值,可以编写一个简单的计算工具:

// 示例:计算MessageBoxA的HASH
DWORD hashMessageBoxA = HashStringLoseLoseA("MessageBoxA");
DWORD hashUser32 = HashStringLoseLoseW(L"user32.dll");

printf("MessageBoxA hash: 0x%X\n", hashMessageBoxA);
printf("user32.dll hash: 0x%X\n", hashUser32);

4.2 动态调用示例

// 定义函数类型
typedef int (WINAPI* MessageBoxAType)(HWND, LPCSTR, LPCSTR, UINT);

void ShowMessage() {
    // 获取模块句柄
    HMODULE hUser32 = GetModuleHandleH(hashUser32);
    if (!hUser32) return;
    
    // 获取函数地址
    MessageBoxAType pMessageBoxA = (MessageBoxAType)GetProcAddressH(hUser32, hashMessageBoxA);
    if (!pMessageBoxA) return;
    
    // 调用函数
    pMessageBoxA(NULL, "Hello", "World", MB_OK);
}

5. 技术优势分析

5.1 IAT表隐藏效果

  • 完全消除了IAT表中的API名称
  • 没有显式的GetModuleHandle/GetProcAddress调用
  • 静态分析工具无法识别导入的函数

5.2 字符串隐藏效果

  • 可执行文件中不包含API名称和DLL名称的明文字符串
  • 所有敏感字符串都以HASH形式存在
  • 极大增加了逆向工程难度

5.3 反检测能力

  • 规避基于字符串特征的静态检测
  • 规避基于IAT表的导入函数分析
  • 规避常见的API调用模式检测

6. 技术局限性

  1. 兼容性问题

    • 不同Windows版本PEB/LDR结构可能有差异
    • 需要针对不同架构(x86/x64)调整偏移量
  2. 开发复杂度

    • 需要预先计算所有API的HASH值
    • 缺少标准库支持,需要自行实现基础功能
  3. 调试难度

    • 错误难以追踪和调试
    • 需要额外的日志机制辅助开发

7. 进阶优化建议

  1. HASH算法增强

    • 使用更复杂的HASH算法(如MurmurHash)
    • 增加随机种子提高混淆效果
  2. 延迟加载

    • 仅在需要时加载DLL
    • 使用异常处理机制应对加载失败
  3. 反调试措施

    • 结合反调试技术保护关键代码
    • 动态修改HASH算法参数
  4. 代码混淆

    • 结合控制流混淆技术
    • 动态生成部分代码

8. 总结

本文介绍的WinAPI规避技术通过结合字符串HASH与动态调用,实现了完美的IAT隐藏效果。该技术核心在于:

  1. 完全移除CRT库依赖
  2. 自实现关键API函数(GetModuleHandleH/GetProcAddressH)
  3. 使用HASH值替代明文字符串
  4. 通过PEB遍历实现模块查找

这种技术能有效规避杀毒软件的静态分析,显著提高恶意代码的隐蔽性,但同时也会增加开发和维护的复杂度。在实际应用中,建议根据具体需求进行适当调整和优化。

WinAPI规避技术:字符串HASH与动态调用实现完美IAT隐藏 1. 技术概述 本文介绍一种高级的WinAPI规避技术,通过字符串HASH与动态调用相结合的方式实现完美的IAT(Import Address Table)隐藏。该技术不仅能有效规避杀毒软件的静态分析,还能避免敏感信息在可执行文件中暴露。 2. 技术核心组件 2.1 CRT库删除 必要性 : 标准CRT库会引入大量不必要的API调用(如GetModuleHandle和GetProcAddress) CRT库会残留大量字符串硬编码在可执行文件中 删除CRT可减少被溯源的风险 Visual Studio编译参数设置 : 影响 : 标准库函数如memcpy、memset、printf等将无法使用 需要自行实现这些功能或寻找替代API 示例:自实现memset 2.2 自定义HASH算法 HASH算法设计 : 特点 : INITIAL_ HASH和SEED可自定义 算法简单高效,适合运行时计算 提供ANSI和Unicode两个版本 3. 核心API自实现 3.1 自实现GetModuleHandleH 功能 :通过HASH值而非明文字符串查找模块基址 实现代码 : 关键点 : 通过PEB结构遍历已加载模块 使用 __readgsqword(0x60) 获取PEB地址(x64架构) 比较模块名的HASH值而非明文字符串 3.2 自实现GetProcAddressH 功能 :通过HASH值查找导出函数地址 实现代码 : 关键点 : 解析PE文件结构定位导出表 遍历导出函数名称并计算HASH 匹配HASH值返回对应函数地址 4. 技术使用示例 4.1 HASH值计算 在使用前需要预先计算API名称和DLL名称的HASH值,可以编写一个简单的计算工具: 4.2 动态调用示例 5. 技术优势分析 5.1 IAT表隐藏效果 完全消除了IAT表中的API名称 没有显式的GetModuleHandle/GetProcAddress调用 静态分析工具无法识别导入的函数 5.2 字符串隐藏效果 可执行文件中不包含API名称和DLL名称的明文字符串 所有敏感字符串都以HASH形式存在 极大增加了逆向工程难度 5.3 反检测能力 规避基于字符串特征的静态检测 规避基于IAT表的导入函数分析 规避常见的API调用模式检测 6. 技术局限性 兼容性问题 : 不同Windows版本PEB/LDR结构可能有差异 需要针对不同架构(x86/x64)调整偏移量 开发复杂度 : 需要预先计算所有API的HASH值 缺少标准库支持,需要自行实现基础功能 调试难度 : 错误难以追踪和调试 需要额外的日志机制辅助开发 7. 进阶优化建议 HASH算法增强 : 使用更复杂的HASH算法(如MurmurHash) 增加随机种子提高混淆效果 延迟加载 : 仅在需要时加载DLL 使用异常处理机制应对加载失败 反调试措施 : 结合反调试技术保护关键代码 动态修改HASH算法参数 代码混淆 : 结合控制流混淆技术 动态生成部分代码 8. 总结 本文介绍的WinAPI规避技术通过结合字符串HASH与动态调用,实现了完美的IAT隐藏效果。该技术核心在于: 完全移除CRT库依赖 自实现关键API函数(GetModuleHandleH/GetProcAddressH) 使用HASH值替代明文字符串 通过PEB遍历实现模块查找 这种技术能有效规避杀毒软件的静态分析,显著提高恶意代码的隐蔽性,但同时也会增加开发和维护的复杂度。在实际应用中,建议根据具体需求进行适当调整和优化。