1. PE文件映射 (MapFileToMemory)

这个函数负责将PE文件手动映射到内存中,而不是使用系统的LoadLibrary:

  • 打开并读取PE文件
  • 分配足够的虚拟内存来容纳整个映像
  • 复制PE头部和所有节数据到分配的内存中
2. 重定位处理 (ProcessRelocations)

当DLL的实际加载地址与其首选映像基址不同时,需要进行重定位:

  • 遍历重定位表中的所有重定位项
  • 根据地址差异调整需要重定位的地址
  • 支持32位和64位重定位条目
3. 导入表解析 (ProcessImports)

处理DLL的依赖关系:

  • 遍历导入表中的每个依赖DLL
  • 递归调用ManualLoadLibrary加载依赖项
  • 解析按名称和按序号导入的函数
  • 更新导入地址表(IAT)
4. 导出表处理 (ProcessExports)

构建导出函数索引以供后续查询:

  • 解析导出表结构
  • 构建函数地址、名称和序号的索引
5. 函数地址查询 (ManualGetProcAddress)

根据函数名称或序号查找函数地址:

  • 支持按名称和按序号查找
  • 使用预先构建的导出表索引快速定位

关键技术点

  1. 线程安全:使用临界区保护共享数据结构
  2. 循环依赖预防:通过已加载模块列表避免重复加载
  3. 引用计数管理:确保正确的资源管理和释放
  4. PE结构解析:手动解析复杂的PE文件结构

转发函数处理详解

在Windows DLL中,有一种特殊的导出函数称为"转发函数"。这些函数不是实际的代码实现,而是将函数调用转发到另一个DLL中的函数。转发函数在导出表中的地址指向一个字符串,格式为"DLL名称.函数名称"或"DLL名称.#序号"。

处理流程

  1. 在处理导出表时,检查每个导出函数是否为转发函数
  2. 如果是转发函数,解析其目标DLL和函数信息
  3. 加载目标DLL并获取目标函数地址
  4. 将转发函数信息存储在模块的转发函数列表中
  5. 在GetProcAddress时,如果请求的是转发函数,则返回预先解析的目标函数地址

示例代码

manual_loadlibrary.h

#ifndef MANUAL_LOADLIBRARY_H
#define MANUAL_LOADLIBRARY_H

#include <windows.h>

#ifdef __cplusplus
extern "C" {
#endif

// 手动实现的LoadLibrary函数,不调用系统LoadLibrary
HMODULE ManualLoadLibrary(LPCSTR lpLibFileName);

// 获取函数地址
FARPROC ManualGetProcAddress(HMODULE hModule, LPCSTR lpProcName);

// 释放库资源
BOOL ManualFreeLibrary(HMODULE hModule);

VOID CallDllMain(HMODULE hModule, DWORD dwReason);


#ifdef __cplusplus
}
#endif

#endif // MANUAL_LOADLIBRARY_H

pe_loader.c

#include "manual_loadlibrary.h"
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// PE结构相关常量和结构体定义
#define IMAGE_SIZEOF_BASE_RELOCATION ((DWORD)sizeof(IMAGE_BASE_RELOCATION))

// 已加载模块信息结构
typedef struct _FORWARDER_INFO
{
    char szForwarderName[256];    // 转发函数名称 "DLL.Name"
    HMODULE hTargetModule;        // 目标模块句柄
    char szTargetFunction[128];   // 目标函数名称或序号字符串
    DWORD dwTargetOrdinal;        // 目标函数序号(如果是按序号)
    BOOL bIsOrdinal;              // 是否按序号查找
    FARPROC pResolvedAddress;     // 解析后的函数地址
    struct _FORWARDER_INFO *next; // 链表指针
} FORWARDER_INFO, *PFORWARDER_INFO;

typedef struct _LOADED_MODULE {
    CHAR szFullPath[MAX_PATH];           // 完整路径
    HMODULE hModule;                     // 模块基址
    DWORD dwRefCount;                    // 引用计数
    IMAGE_NT_HEADERS* pNtHeaders;        // NT头指针
    IMAGE_EXPORT_DIRECTORY* pExportDir;  // 导出表指针
    DWORD* pAddressOfFunctions;          // 函数地址数组
    DWORD* pAddressOfNames;              // 函数名称数组
    WORD* pAddressOfNameOrdinals;        // 函数序号数组
    DWORD dwNumberOfFunctions;           // 函数总数
    DWORD dwNumberOfNames;               // 命名函数数
    PFORWARDER_INFO pForwarders;         // 转发函数列表
    struct _LOADED_MODULE* next;         // 链表指针
} LOADED_MODULE, *PLOADED_MODULE;

// 全局变量
static PLOADED_MODULE g_pLoadedModules = NULL; // 已加载模块列表
static CRITICAL_SECTION g_cs;                  // 临界区
static BOOL g_bCSInitialized = FALSE;          // 临界区初始化标志

// 函数声明
static HMODULE InternalLoadLibrary(LPCSTR lpLibFileName);
static HMODULE GetLoadedModule(LPCSTR lpLibFileName);
static void AddLoadedModule(LPCSTR lpLibFileName, HMODULE hModule, PIMAGE_NT_HEADERS pNtHeaders);
static void RemoveLoadedModule(HMODULE hModule);
static BOOL IsSystemLibrary(LPCSTR lpLibFileName);
static BOOL ResolveFullpath(LPSTR lpFullPath, LPCSTR lpLibFileName);
static HMODULE MapFileToMemory(LPCSTR lpLibFileName);
static BOOL ProcessRelocations(HMODULE hModule, PIMAGE_NT_HEADERS pNtHeaders);
static BOOL ProcessImports(PLOADED_MODULE pModule);
static BOOL ProcessExports(PLOADED_MODULE pModule);
static PLOADED_MODULE FindLoadedModuleByHandle(HMODULE hModule);

// 初始化临界区
static void InitializeCriticalSectionIfNeeded()
{
    if (!g_bCSInitialized)
    {
        InitializeCriticalSection(&g_cs);
        g_bCSInitialized = TRUE;
    }
}

// 手动LoadLibrary实现
HMODULE ManualLoadLibrary(LPCSTR lpLibFileName) {
    HMODULE hModule = NULL;
    
    if (lpLibFileName == NULL) {
        SetLastError(ERROR_INVALID_PARAMETER);
        return NULL;
    }
    
    // 初始化临界区
    InitializeCriticalSectionIfNeeded();
    
    // 进入临界区
    EnterCriticalSection(&g_cs);
    
    // 检查模块是否已经加载
    hModule = GetLoadedModule(lpLibFileName);
    if (hModule != NULL) {
        // 增加引用计数
        PLOADED_MODULE pModule = g_pLoadedModules;
        while (pModule != NULL) {
            if (pModule->hModule == hModule) {
                pModule->dwRefCount++;
                break;
            }
            pModule = pModule->next;
        }
        LeaveCriticalSection(&g_cs);
        return hModule;
    }
    
    // 退出临界区
    LeaveCriticalSection(&g_cs);
    
    // 实际加载模块
    return InternalLoadLibrary(lpLibFileName);
}

// 内部加载库函数
static HMODULE InternalLoadLibrary(LPCSTR lpLibFileName) {
    CHAR szFullPath[MAX_PATH];
    HMODULE hModule = NULL;
    HANDLE hFile = INVALID_HANDLE_VALUE;
    HANDLE hMapping = NULL;
    LPVOID lpFileBase = NULL;
    PIMAGE_DOS_HEADER pDosHeader;
    PIMAGE_NT_HEADERS pNtHeaders;
    
    // 解析完整路径
    if (!ResolveFullpath(szFullPath, lpLibFileName)) {
        SetLastError(ERROR_MOD_NOT_FOUND);
        return NULL;
    }
    
    // 进入临界区
    EnterCriticalSection(&g_cs);
    
    // 再次检查模块是否已经加载(双重检查锁定模式)
    hModule = GetLoadedModule(szFullPath);
    if (hModule != NULL) {
        // 增加引用计数
        PLOADED_MODULE pModule = g_pLoadedModules;
        while (pModule != NULL) {
            if (pModule->hModule == hModule) {
                pModule->dwRefCount++;
                break;
            }
            pModule = pModule->next;
        }
        LeaveCriticalSection(&g_cs);
        return hModule;
    }
    
    // 手动映射文件到内存
    hModule = MapFileToMemory(szFullPath);
    if (hModule == NULL) {
        LeaveCriticalSection(&g_cs);
        return NULL;
    }
    
    // 检查DOS头
    pDosHeader = (PIMAGE_DOS_HEADER)hModule;
    if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
        // 无效的DOS签名
        VirtualFree(hModule, 0, MEM_RELEASE);
        LeaveCriticalSection(&g_cs);
        SetLastError(ERROR_BAD_EXE_FORMAT);
        return NULL;
    }
    
    // 获取NT头
    pNtHeaders = (PIMAGE_NT_HEADERS)((LPBYTE)hModule + pDosHeader->e_lfanew);
    if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE) {
        // 无效的NT签名
        VirtualFree(hModule, 0, MEM_RELEASE);
        LeaveCriticalSection(&g_cs);
        SetLastError(ERROR_BAD_EXE_FORMAT);
        return NULL;
    }
    
    // 处理重定位
    if (!ProcessRelocations(hModule, pNtHeaders)) {
        VirtualFree(hModule, 0, MEM_RELEASE);
        LeaveCriticalSection(&g_cs);
        return NULL;
    }
    
    // 添加到已加载模块列表
    AddLoadedModule(szFullPath, hModule, pNtHeaders);
    
    // 查找刚添加的模块
    PLOADED_MODULE pModule = FindLoadedModuleByHandle(hModule);
    if (pModule == NULL) {
        VirtualFree(hModule, 0, MEM_RELEASE);
        LeaveCriticalSection(&g_cs);
        return NULL;
    }
    
    // 处理导入表
    if (!ProcessImports(pModule)) {
        RemoveLoadedModule(hModule);
        VirtualFree(hModule, 0, MEM_RELEASE);
        LeaveCriticalSection(&g_cs);
        return NULL;
    }
    
    // 处理导出表
    ProcessExports(pModule);

    DWORD ulOld;
    VirtualProtect(hModule, pNtHeaders->OptionalHeader.SizeOfImage, PAGE_EXECUTE_READWRITE, &ulOld);

    
    pNtHeaders->OptionalHeader.ImageBase = (DWORD_PTR)hModule;
    // 调用DllMain
    //CallDllMain(hModule, DLL_PROCESS_ATTACH);
    
    // 退出临界区
    LeaveCriticalSection(&g_cs);
    
    return hModule;
}

// 获取已加载的模块句柄
static HMODULE GetLoadedModule(LPCSTR lpLibFileName) {
    PLOADED_MODULE pModule = g_pLoadedModules;
    CHAR szFullPath[MAX_PATH];
    
    // 解析完整路径
    if (!ResolveFullpath(szFullPath, lpLibFileName)) {
        return NULL;
    }
    
    // 遍历已加载模块列表
    while (pModule != NULL) {
        if (_stricmp(pModule->szFullPath, szFullPath) == 0) {
            return pModule->hModule;
        }
        pModule = pModule->next;
    }
    
    return NULL;
}

// 添加已加载模块到列表
static void AddLoadedModule(LPCSTR lpLibFileName, HMODULE hModule, PIMAGE_NT_HEADERS pNtHeaders)
{
    PLOADED_MODULE pNewModule = (PLOADED_MODULE)malloc(sizeof(LOADED_MODULE));
    if (pNewModule == NULL)
    {
        return;
    }

    ZeroMemory(pNewModule, sizeof(LOADED_MODULE));
    strcpy_s(pNewModule->szFullPath, MAX_PATH, lpLibFileName);
    pNewModule->hModule = hModule;
    pNewModule->dwRefCount = 1;
    pNewModule->pNtHeaders = pNtHeaders;
    pNewModule->next = g_pLoadedModules;
    g_pLoadedModules = pNewModule;
}

// 移除已加载模块(引用计数减到0时)
static void RemoveLoadedModule(HMODULE hModule)
{
    PLOADED_MODULE pPrev = NULL;
    PLOADED_MODULE pCurrent = g_pLoadedModules;

    while (pCurrent != NULL)
    {
        if (pCurrent->hModule == hModule)
        {
            pCurrent->dwRefCount--;

            if (pCurrent->dwRefCount == 0)
            {
                // 引用计数为0,调用DllMain并释放资源
                //CallDllMain(hModule, DLL_PROCESS_DETACH);

                // 释放转发函数信息
                PFORWARDER_INFO pForwarder = pCurrent->pForwarders;
                while (pForwarder != NULL)
                {
                    PFORWARDER_INFO pNext = pForwarder->next;
                    // 释放目标模块引用
                    ManualFreeLibrary(pForwarder->hTargetModule);
                    free(pForwarder);
                    pForwarder = pNext;
                }

                // 从链表中移除
                if (pPrev != NULL)
                {
                    pPrev->next = pCurrent->next;
                }
                else
                {
                    g_pLoadedModules = pCurrent->next;
                }

                // 释放内存
                VirtualFree(hModule, 0, MEM_RELEASE);
                free(pCurrent);
            }
            return;
        }

        pPrev = pCurrent;
        pCurrent = pCurrent->next;
    }
}

// 判断是否为系统库
static BOOL IsSystemLibrary(LPCSTR lpLibFileName) {
    // 简单判断:如果文件名中包含路径分隔符,则不是系统库
    // 否则可能是系统库(需要进一步在当前目录和系统目录中查找)
    if (strchr(lpLibFileName, '\\') != NULL || strchr(lpLibFileName, '/') != NULL) {
        return FALSE;
    }
    return TRUE;
}

// 解析完整路径
static BOOL ResolveFullpath(LPSTR lpFullPath, LPCSTR lpLibFileName) {
    DWORD dwResult;
    
    if (IsSystemLibrary(lpLibFileName)) {
        // 对于可能是系统库的文件(不包含路径分隔符的文件名)
        // 1. 首先尝试在当前目录查找
        dwResult = GetCurrentDirectoryA(MAX_PATH, lpFullPath);
        if (dwResult != 0 && dwResult < MAX_PATH) {
            strcat_s(lpFullPath, MAX_PATH, "\\");
            strcat_s(lpFullPath, MAX_PATH, lpLibFileName);
            
            // 检查当前目录是否存在该文件
            if (GetFileAttributesA(lpFullPath) != INVALID_FILE_ATTRIBUTES) {
                return TRUE;
            }
        }
        
        // 2. 如果当前目录找不到,则在系统目录查找
        dwResult = GetSystemDirectoryA(lpFullPath, MAX_PATH);
        if (dwResult == 0 || dwResult >= MAX_PATH) {
            return FALSE;
        }
        
        // 添加路径分隔符和文件名
        strcat_s(lpFullPath, MAX_PATH, "\\");
        strcat_s(lpFullPath, MAX_PATH, lpLibFileName);
    } else {
        // 非系统库,尝试获取完整路径
        if (!GetFullPathNameA(lpLibFileName, MAX_PATH, lpFullPath, NULL)) {
            // 如果无法获取完整路径,直接复制
            strcpy_s(lpFullPath, MAX_PATH, lpLibFileName);
        }
    }
    
    return TRUE;
}

// 解析转发函数名称
static BOOL ParseForwarderName(LPCSTR szForwarder, LPSTR szDllName, LPSTR szFunctionName, PDWORD pdwOrdinal, PBOOL pbIsOrdinal)
{
    // 转发函数名称格式为 "DLL.Name" 或 "DLL.#123"
    const char *pDot = strchr(szForwarder, '.');
    if (pDot == NULL)
    {
        return FALSE;
    }

    // 提取DLL名称
    DWORD dwDllNameLen = (DWORD)(pDot - szForwarder);
    if (dwDllNameLen >= MAX_PATH)
    {
        return FALSE;
    }

    strncpy_s(szDllName, MAX_PATH, szForwarder, dwDllNameLen);
    szDllName[dwDllNameLen] = '\0';
    
    // 检查DLL名称是否包含扩展名,如果没有则添加默认的.dll扩展名
    if (strrchr(szDllName, '.') == NULL)
    {
        strncat_s(szDllName, MAX_PATH, ".dll", 5);
    }

    // 检查是否按序号转发
    if (pDot[1] == '#')
    {
        // 按序号转发
        *pbIsOrdinal = TRUE;
        *pdwOrdinal = (DWORD)atoi(pDot + 2);
    }
    else
    {
        // 按名称转发
        *pbIsOrdinal = FALSE;
        strcpy_s(szFunctionName, 128, pDot + 1);
    }

    return TRUE;
}

// 添加转发函数信息
static BOOL AddForwarderInfo(PLOADED_MODULE pModule, LPCSTR szForwarderName, DWORD dwFunctionRVA) {
    // 创建新的转发函数信息节点
    PFORWARDER_INFO pForwarder = (PFORWARDER_INFO)malloc(sizeof(FORWARDER_INFO));
    if (pForwarder == NULL) {
        return FALSE;
    }
    
    ZeroMemory(pForwarder, sizeof(FORWARDER_INFO));
    strcpy_s(pForwarder->szForwarderName, 256, szForwarderName);
    
    // 解析转发函数名称
    char szDllName[MAX_PATH] = {0};
    char szFunctionName[128] = {0};
    DWORD dwOrdinal = 0;
    BOOL bIsOrdinal = FALSE;
    
    if (!ParseForwarderName(szForwarderName, szDllName, szFunctionName, &dwOrdinal, &bIsOrdinal)) {
        free(pForwarder);
        return FALSE;
    }
    
    // 加载目标DLL
    HMODULE hTargetModule = ManualLoadLibrary(szDllName);
    if (hTargetModule == NULL) {
        free(pForwarder);
        return FALSE;
    }
    
    pForwarder->hTargetModule = hTargetModule;
    pForwarder->bIsOrdinal = bIsOrdinal;
    
    if (bIsOrdinal) {
        pForwarder->dwTargetOrdinal = dwOrdinal;
    } else {
        strcpy_s(pForwarder->szTargetFunction, 128, szFunctionName);
    }
    
    // 获取目标函数地址
    FARPROC pTargetFunc = NULL;
    if (bIsOrdinal) {
        pTargetFunc = ManualGetProcAddress(hTargetModule, (LPCSTR)(DWORD_PTR)dwOrdinal);
    } else {
        pTargetFunc = ManualGetProcAddress(hTargetModule, szFunctionName);
    }
    
    if (pTargetFunc == NULL) {
        ManualFreeLibrary(hTargetModule);
        free(pForwarder);
        return FALSE;
    }
    
    pForwarder->pResolvedAddress = pTargetFunc;
    
    // 添加到转发函数列表
    pForwarder->next = pModule->pForwarders;
    pModule->pForwarders = pForwarder;
    
    return TRUE;
}

// 查找已加载模块(根据句柄)
static PLOADED_MODULE FindLoadedModuleByHandle(HMODULE hModule)
{
    PLOADED_MODULE pModule = g_pLoadedModules;

    while (pModule != NULL)
    {
        if (pModule->hModule == hModule)
        {
            return pModule;
        }
        pModule = pModule->next;
    }

    return NULL;
}

// 处理重定位
static BOOL ProcessRelocations(HMODULE hModule, PIMAGE_NT_HEADERS pNtHeaders)
{
    DWORD_PTR dwImageBase = pNtHeaders->OptionalHeader.ImageBase;
    DWORD dwRelocVA = pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
    DWORD dwRelocSize = pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;

    // 如果没有重定位表,则无需处理
    if (dwRelocVA == 0 || dwRelocSize == 0)
    {
        return TRUE;
    }

    PIMAGE_BASE_RELOCATION pReloc = (PIMAGE_BASE_RELOCATION)((LPBYTE)hModule + dwRelocVA);

    // 处理所有重定位块
    while (pReloc->VirtualAddress != 0)
    {
        DWORD dwBlockRVA = pReloc->VirtualAddress;
        DWORD dwBlockSize = pReloc->SizeOfBlock;

        // 计算块中重定位项的数量
        DWORD dwEntryCount = (dwBlockSize - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);

        // 获取重定位项数组
        PWORD pEntries = (PWORD)((LPBYTE)pReloc + sizeof(IMAGE_BASE_RELOCATION));

        // 处理每个重定位项
        for (DWORD i = 0; i < dwEntryCount; i++)
        {
            WORD wEntry = pEntries[i];
            WORD wType = wEntry >> 12;      // 高4位是类型
            WORD wOffset = wEntry & 0xFFF;  // 低12位是偏移

            // 只处理基于页面的重定位
            if (wType == IMAGE_REL_BASED_HIGHLOW)
            {
                // 计算需要重定位的地址
                DWORD* pdwAddress = (DWORD*)((LPBYTE)hModule + dwBlockRVA + wOffset);
                
                // 应用重定位(调整地址)
                *pdwAddress = (DWORD)((*pdwAddress) - dwImageBase + (DWORD_PTR)hModule);
            }
            else if (wType == IMAGE_REL_BASED_DIR64)
            {
                // 对于64位重定位
                ULONGLONG* pullAddress = (ULONGLONG*)((LPBYTE)hModule + dwBlockRVA + wOffset);
                *pullAddress = (*pullAddress) - dwImageBase + (ULONGLONG)(DWORD_PTR)hModule;
            }
        }

        // 移动到下一个重定位块
        pReloc = (PIMAGE_BASE_RELOCATION)((LPBYTE)pReloc + dwBlockSize);
    }

    return TRUE;
}

// 手动映射文件到内存
static HMODULE MapFileToMemory(LPCSTR lpLibFileName) {
    HANDLE hFile = INVALID_HANDLE_VALUE;
    HANDLE hMapping = NULL;
    LPVOID lpFileBase = NULL;
    DWORD dwFileSize;
    HMODULE hModule = NULL;
    
    // 打开文件
    hFile = CreateFileA(
        lpLibFileName,
        GENERIC_READ,
        FILE_SHARE_READ,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL
    );
    
    if (hFile == INVALID_HANDLE_VALUE) {
        return NULL;
    }
    
    // 获取文件大小
    dwFileSize = GetFileSize(hFile, NULL);
    if (dwFileSize == INVALID_FILE_SIZE) {
        CloseHandle(hFile);
        return NULL;
    }
    
    // 创建文件映射对象
    hMapping = CreateFileMappingA(
        hFile,
        NULL,
        PAGE_READONLY,
        0,
        dwFileSize,
        NULL
    );
    
    if (hMapping == NULL) {
        CloseHandle(hFile);
        return NULL;
    }
    
    // 映射文件到内存
    lpFileBase = MapViewOfFile(
        hMapping,
        FILE_MAP_READ,
        0,
        0,
        0
    );
    
    if (lpFileBase == NULL) {
        CloseHandle(hMapping);
        CloseHandle(hFile);
        return NULL;
    }
    
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)lpFileBase;
    if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
        UnmapViewOfFile(lpFileBase);
        CloseHandle(hMapping);
        CloseHandle(hFile);
        SetLastError(ERROR_BAD_EXE_FORMAT);
        return NULL;
    }
    
    PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((LPBYTE)lpFileBase + pDosHeader->e_lfanew);
    if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE) {
        UnmapViewOfFile(lpFileBase);
        CloseHandle(hMapping);
        CloseHandle(hFile);
        SetLastError(ERROR_BAD_EXE_FORMAT);
        return NULL;
    }
    
    // 分配内存以容纳整个映像
    hModule = (HMODULE)VirtualAlloc(
        NULL,
        pNtHeaders->OptionalHeader.SizeOfImage,
        MEM_COMMIT | MEM_RESERVE,
        PAGE_EXECUTE_READWRITE
    );
    
    if (hModule == NULL) {
        UnmapViewOfFile(lpFileBase);
        CloseHandle(hMapping);
        CloseHandle(hFile);
        return NULL;
    }
    
    // 复制PE头
    memcpy(hModule, lpFileBase, pNtHeaders->OptionalHeader.SizeOfHeaders);
    
    // 复制各节
    PIMAGE_SECTION_HEADER pSectionHeaders = IMAGE_FIRST_SECTION(pNtHeaders);
    for (DWORD i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++) {
        if (pSectionHeaders[i].SizeOfRawData > 0) {
            memcpy(
                (LPBYTE)hModule + pSectionHeaders[i].VirtualAddress,
                (LPBYTE)lpFileBase + pSectionHeaders[i].PointerToRawData,
                pSectionHeaders[i].SizeOfRawData
            );
        }
    }
    
    // 清理资源
    UnmapViewOfFile(lpFileBase);
    CloseHandle(hMapping);
    CloseHandle(hFile);
    
    return hModule;
}

// 处理导入表
static BOOL ProcessImports(PLOADED_MODULE pModule) {
    HMODULE hModule = pModule->hModule;
    PIMAGE_NT_HEADERS pNtHeaders = pModule->pNtHeaders;
    
    // 获取导入表信息
    DWORD dwImportVA = pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
    DWORD dwImportSize = pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
    
    // 如果没有导入表,则无需处理
    if (dwImportVA == 0 || dwImportSize == 0) {
        return TRUE;
    }
    
    PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)((LPBYTE)hModule + dwImportVA);
    
    // 处理每个导入的DLL
    while (pImportDesc->Name != 0) {
        // 获取DLL名称
        char* szDllName = (char*)((LPBYTE)hModule + pImportDesc->Name);
        
        // 加载依赖的DLL
        HMODULE hImportModule = ManualLoadLibrary(szDllName);
        if (hImportModule == NULL) {
            // 如果导入的DLL无法加载,我们仍然继续处理其他导入
            // 这可以提高兼容性,避免因单个DLL缺失导致整个模块加载失败
            pImportDesc++;
            continue;
        }
        
        // 获取导入地址表(IAT)
        PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)((LPBYTE)hModule + pImportDesc->FirstThunk);
        PIMAGE_THUNK_DATA pOrigThunk = (PIMAGE_THUNK_DATA)((LPBYTE)hModule + pImportDesc->OriginalFirstThunk);
        
        // 处理每个导入函数
        while (pOrigThunk->u1.AddressOfData != 0) {
            FARPROC pFuncAddress = NULL;
            
            if (IMAGE_SNAP_BY_ORDINAL(pOrigThunk->u1.Ordinal)) {
                // 按序号导入
                DWORD dwOrdinal = (DWORD)IMAGE_ORDINAL(pOrigThunk->u1.Ordinal);
                pFuncAddress = ManualGetProcAddress(hImportModule, (LPCSTR)(DWORD_PTR)dwOrdinal);
            } else {
                // 按名称导入
                PIMAGE_IMPORT_BY_NAME pImportByName = (PIMAGE_IMPORT_BY_NAME)((LPBYTE)hModule + pOrigThunk->u1.AddressOfData);
                pFuncAddress = ManualGetProcAddress(hImportModule, (LPCSTR)pImportByName->Name);
            }
            
            if (pFuncAddress == NULL) {
                // 如果无法获取函数地址,我们继续处理其他函数
                // 这可以提高兼容性,避免因单个函数缺失导致整个模块加载失败
                pOrigThunk++;
                pThunk++;
                continue;
            }
            
            // 更新IAT
            pThunk->u1.Function = (DWORD_PTR)pFuncAddress;
            
            pOrigThunk++;
            pThunk++;
        }
        
        pImportDesc++;
    }
    
    return TRUE;
}

// 处理导出表
static BOOL ProcessExports(PLOADED_MODULE pModule)
{
    HMODULE hModule = pModule->hModule;
    PIMAGE_NT_HEADERS pNtHeaders = pModule->pNtHeaders;
    
    // 获取导出表信息
    DWORD dwExportVA = pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
    DWORD dwExportSize = pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
    
    // 如果没有导出表,则无需处理
    if (dwExportVA == 0 || dwExportSize == 0)
    {
        return TRUE;
    }
    
    // 设置导出表相关信息
    pModule->pExportDir = (PIMAGE_EXPORT_DIRECTORY)((LPBYTE)hModule + dwExportVA);
    pModule->dwNumberOfFunctions = pModule->pExportDir->NumberOfFunctions;
    pModule->dwNumberOfNames = pModule->pExportDir->NumberOfNames;
    pModule->pAddressOfFunctions = (DWORD*)((LPBYTE)hModule + pModule->pExportDir->AddressOfFunctions);
    pModule->pAddressOfNames = (DWORD*)((LPBYTE)hModule + pModule->pExportDir->AddressOfNames);
    pModule->pAddressOfNameOrdinals = (WORD*)((LPBYTE)hModule + pModule->pExportDir->AddressOfNameOrdinals);
    
    return TRUE;
}

// 检查地址是否在导出节内
static BOOL IsAddressInExportSection(HMODULE hModule, DWORD dwRVA)
{
    PLOADED_MODULE pModule = FindLoadedModuleByHandle(hModule);
    if (pModule == NULL || pModule->pExportDir == NULL)
    {
        return FALSE;
    }

    DWORD dwExportStart = pModule->pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
    DWORD dwExportSize = pModule->pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;

    return (dwRVA >= dwExportStart && dwRVA < dwExportStart + dwExportSize);
}

// 查找转发函数地址
static FARPROC FindForwarderAddress(PLOADED_MODULE pModule, LPCSTR lpProcName)
{
    PFORWARDER_INFO pForwarder = pModule->pForwarders;

    while (pForwarder != NULL)
    {
        // 检查按名称匹配
        if (strcmp(pForwarder->szForwarderName, lpProcName) == 0)
        {
            return pForwarder->pResolvedAddress;
        }
        pForwarder = pForwarder->next;
    }

    return NULL;
}

// 手动GetProcAddress实现
FARPROC ManualGetProcAddress(HMODULE hModule, LPCSTR lpProcName) {
    PLOADED_MODULE pModule;
    FARPROC pFuncAddress = NULL;
    
    // 进入临界区
    EnterCriticalSection(&g_cs);
    
    // 查找模块
    pModule = FindLoadedModuleByHandle(hModule);
    if (pModule == NULL || pModule->pExportDir == NULL) {
        LeaveCriticalSection(&g_cs);
        SetLastError(ERROR_MOD_NOT_FOUND);
        return NULL;
    }
    
    if ((DWORD_PTR)lpProcName < 0x10000) {
        // 按序号查找
        DWORD dwOrdinal = (DWORD)(DWORD_PTR)lpProcName;
        DWORD dwBase = pModule->pExportDir->Base;
        
        if (dwOrdinal < dwBase || dwOrdinal >= dwBase + pModule->dwNumberOfFunctions) {
            LeaveCriticalSection(&g_cs);
            SetLastError(ERROR_PROC_NOT_FOUND);
            return NULL;
        }
        
        DWORD dwFuncRVA = pModule->pAddressOfFunctions[dwOrdinal - dwBase];
        if (dwFuncRVA == 0) {
            LeaveCriticalSection(&g_cs);
            SetLastError(ERROR_PROC_NOT_FOUND);
            return NULL;
        }
        
        // 检查是否为转发函数
        if (IsAddressInExportSection(hModule, dwFuncRVA)) {
            // 这是一个转发函数,需要特殊处理
            char* szForwarderName = (char*)((LPBYTE)hModule + dwFuncRVA);
            pFuncAddress = FindForwarderAddress(pModule, szForwarderName);
            if (pFuncAddress == NULL) {
                // 如果在转发函数列表中找不到,尝试动态解析
                // 这种情况可能发生在转发函数信息添加失败时
                PFORWARDER_INFO pForwarder = (PFORWARDER_INFO)malloc(sizeof(FORWARDER_INFO));
                if (pForwarder != NULL) {
                    ZeroMemory(pForwarder, sizeof(FORWARDER_INFO));
                    strcpy_s(pForwarder->szForwarderName, 256, szForwarderName);
                    
                    // 解析转发函数名称
                    char szDllName[MAX_PATH] = {0};
                    char szFunctionName[128] = {0};
                    DWORD dwOrdinal = 0;
                    BOOL bIsOrdinal = FALSE;
                    
                    if (ParseForwarderName(szForwarderName, szDllName, szFunctionName, &dwOrdinal, &bIsOrdinal)) {
                        // 加载目标DLL
                        HMODULE hTargetModule = ManualLoadLibrary(szDllName);
                        if (hTargetModule != NULL) {
                            pForwarder->hTargetModule = hTargetModule;
                            pForwarder->bIsOrdinal = bIsOrdinal;
                            
                            if (bIsOrdinal) {
                                pForwarder->dwTargetOrdinal = dwOrdinal;
                            } else {
                                strcpy_s(pForwarder->szTargetFunction, 128, szFunctionName);
                            }
                            
                            // 获取目标函数地址
                            FARPROC pTargetFunc = NULL;
                            if (bIsOrdinal) {
                                pTargetFunc = ManualGetProcAddress(hTargetModule, (LPCSTR)(DWORD_PTR)dwOrdinal);
                            } else {
                                pTargetFunc = ManualGetProcAddress(hTargetModule, szFunctionName);
                            }
                            
                            if (pTargetFunc != NULL) {
                                pForwarder->pResolvedAddress = pTargetFunc;
                                // 添加到转发函数列表
                                pForwarder->next = pModule->pForwarders;
                                pModule->pForwarders = pForwarder;
                                pFuncAddress = pTargetFunc;
                            } else {
                                ManualFreeLibrary(hTargetModule);
                                free(pForwarder);
                                pFuncAddress = NULL;
                            }
                        } else {
                            // 如果目标模块加载失败,我们仍然创建转发器条目
                            // 这样可以避免重复尝试加载不存在的DLL
                            pForwarder->hTargetModule = NULL;
                            pForwarder->pResolvedAddress = NULL;
                            
                            if (bIsOrdinal) {
                                pForwarder->dwTargetOrdinal = dwOrdinal;
                            } else {
                                strcpy_s(pForwarder->szTargetFunction, 128, szFunctionName);
                            }
                            
                            // 添加到转发函数列表
                            pForwarder->next = pModule->pForwarders;
                            pModule->pForwarders = pForwarder;
                            
                            // 返回NULL表示函数未找到
                            free(pForwarder);
                            pFuncAddress = NULL;
                        }
                    } else {
                        free(pForwarder);
                    }
                }
            }
        } else {
            // 普通函数
            pFuncAddress = (FARPROC)((LPBYTE)hModule + dwFuncRVA);
        }
    } else {
        // 按名称查找
        for (DWORD i = 0; i < pModule->dwNumberOfNames; i++) {
            char* szFuncName = (char*)((LPBYTE)hModule + pModule->pAddressOfNames[i]);
            if (strcmp(szFuncName, lpProcName) == 0) {
                WORD wOrdinal = pModule->pAddressOfNameOrdinals[i];
                DWORD dwFuncRVA = pModule->pAddressOfFunctions[wOrdinal];
                if (dwFuncRVA == 0) {
                    LeaveCriticalSection(&g_cs);
                    SetLastError(ERROR_PROC_NOT_FOUND);
                    return NULL;
                }
                
                // 检查是否为转发函数
                if (IsAddressInExportSection(hModule, dwFuncRVA)) {
                    // 这是一个转发函数,需要特殊处理
                    char* szForwarderName = (char*)((LPBYTE)hModule + dwFuncRVA);
                    pFuncAddress = FindForwarderAddress(pModule, szForwarderName);
                    if (pFuncAddress == NULL) {
                        // 如果在转发函数列表中找不到,尝试动态解析
                        // 这种情况可能发生在转发函数信息添加失败时
                        PFORWARDER_INFO pForwarder = (PFORWARDER_INFO)malloc(sizeof(FORWARDER_INFO));
                        if (pForwarder != NULL) {
                            ZeroMemory(pForwarder, sizeof(FORWARDER_INFO));
                            strcpy_s(pForwarder->szForwarderName, 256, szForwarderName);
                            
                            // 解析转发函数名称
                            char szDllName[MAX_PATH] = {0};
                            char szFunctionName[128] = {0};
                            DWORD dwOrdinal = 0;
                            BOOL bIsOrdinal = FALSE;
                            
                            if (ParseForwarderName(szForwarderName, szDllName, szFunctionName, &dwOrdinal, &bIsOrdinal)) {
                                // 加载目标DLL
                                HMODULE hTargetModule = ManualLoadLibrary(szDllName);
                                if (hTargetModule != NULL) {
                                    pForwarder->hTargetModule = hTargetModule;
                                    pForwarder->bIsOrdinal = bIsOrdinal;
                                    
                                    if (bIsOrdinal) {
                                        pForwarder->dwTargetOrdinal = dwOrdinal;
                                    } else {
                                        strcpy_s(pForwarder->szTargetFunction, 128, szFunctionName);
                                    }
                                    
                                    // 获取目标函数地址
                                    FARPROC pTargetFunc = NULL;
                                    if (bIsOrdinal) {
                                        pTargetFunc = ManualGetProcAddress(hTargetModule, (LPCSTR)(DWORD_PTR)dwOrdinal);
                                    } else {
                                        pTargetFunc = ManualGetProcAddress(hTargetModule, szFunctionName);
                                    }
                                    
                                    if (pTargetFunc != NULL) {
                                        pForwarder->pResolvedAddress = pTargetFunc;
                                        // 添加到转发函数列表
                                        pForwarder->next = pModule->pForwarders;
                                        pModule->pForwarders = pForwarder;
                                        pFuncAddress = pTargetFunc;
                                    } else {
                                        ManualFreeLibrary(hTargetModule);
                                        free(pForwarder);
                                    }
                                } else {
                                    free(pForwarder);
                                }
                            } else {
                                free(pForwarder);
                            }
                        }
                    }
                } else {
                    // 普通函数
                    pFuncAddress = (FARPROC)((LPBYTE)hModule + dwFuncRVA);
                }
                break;
            }
        }
    }
    
    // 退出临界区
    LeaveCriticalSection(&g_cs);
    
    if (pFuncAddress == NULL) {
        SetLastError(ERROR_PROC_NOT_FOUND);
    }
    
    return pFuncAddress;
}

// 手动FreeLibrary实现
BOOL ManualFreeLibrary(HMODULE hModule)
{
    if (hModule == NULL)
    {
        SetLastError(ERROR_INVALID_HANDLE);
        return FALSE;
    }

    // 初始化临界区
    InitializeCriticalSectionIfNeeded();

    // 进入临界区
    EnterCriticalSection(&g_cs);

    // 移除已加载模块(减少引用计数)
    RemoveLoadedModule(hModule);

    // 退出临界区
    LeaveCriticalSection(&g_cs);

    return TRUE;
}

// 调用DllMain
VOID CallDllMain(HMODULE hModule, DWORD dwReason)
{
    PLOADED_MODULE pModule = FindLoadedModuleByHandle(hModule);
    if (pModule == NULL)
    {
        return;
    }

    // 获取入口点地址
    DWORD dwEntryPointRVA = pModule->pNtHeaders->OptionalHeader.AddressOfEntryPoint;
    if (dwEntryPointRVA == 0)
    {
        // 没有入口点
        return;
    }

    // 检查入口点地址是否有效
    DWORD dwImageSize = pModule->pNtHeaders->OptionalHeader.SizeOfImage;
    if (dwEntryPointRVA >= dwImageSize)
    {
        // 入口点地址超出镜像范围,无效
        return;
    }

    // 获取DllMain函数指针
    //LPBYTE pEntryPoint = (LPBYTE)hModule + dwEntryPointRVA;

    // 获取DllMain函数指针
    typedef   BOOL(__stdcall* ProcDllMain)(HINSTANCE, DWORD, LPVOID);
    ProcDllMain pDllMain = (ProcDllMain)(dwEntryPointRVA + (PBYTE)hModule);

    // 调用DllMain
    pDllMain((HINSTANCE)hModule, dwReason, NULL);
}

test_manual_loadlibrary.c

#include <windows.h>
#include <stdio.h>
#include "manual_loadlibrary.h"

int main() {
    system("chcp 65001");
    HMODULE hKernel32;
    FARPROC pGetCurrentProcessId;
    typedef DWORD (WINAPI *GetCurrentProcessIdFunc)();
    GetCurrentProcessIdFunc getCurrentProcessId;
    
    printf("测试手动实现的LoadLibrary函数\n");
    
    // 测试加载系统库kernel32.dll
    hKernel32 = ManualLoadLibrary("kernel32.dll");
    if (hKernel32 == NULL) {
        printf("加载kernel32.dll失败,错误码:%lu\n", GetLastError());
        return 1;
    }
    printf("成功加载kernel32.dll,句柄:%p\n", hKernel32);
    
    // 测试重复加载同一个库
    HMODULE hKernel32_2 = ManualLoadLibrary("kernel32.dll");
    if (hKernel32_2 == hKernel32) {
        printf("重复加载返回相同句柄:%p\n", hKernel32_2);
    } else {
        printf("重复加载返回不同句柄:%p\n", hKernel32_2);
    }
    
    // 获取函数地址
    pGetCurrentProcessId = ManualGetProcAddress(hKernel32, "GetCurrentProcessId");
    if (pGetCurrentProcessId == NULL) {
        printf("获取函数地址失败,错误码:%lu\n", GetLastError());
        ManualFreeLibrary(hKernel32);
        ManualFreeLibrary(hKernel32_2);
        return 1;
    }
    
    // 调用函数
    getCurrentProcessId = (GetCurrentProcessIdFunc)pGetCurrentProcessId;
    DWORD processId = getCurrentProcessId();
    printf("当前进程ID:%lu\n", processId);
    
    // 测试更多函数
    // 测试GetTickCount函数
    FARPROC pGetTickCount = ManualGetProcAddress(hKernel32, "GetTickCount");
    if (pGetTickCount != NULL) {
        typedef DWORD (WINAPI *GetTickCountFunc)();
        GetTickCountFunc getTickCount = (GetTickCountFunc)pGetTickCount;
        DWORD tickCount = getTickCount();
        printf("系统启动后经过的毫秒数:%lu\n", tickCount);
    } else {
        printf("获取GetTickCount函数地址失败,错误码:%lu\n", GetLastError());
    }
    
    // 测试Sleep函数
    FARPROC pSleep = ManualGetProcAddress(hKernel32, "Sleep");
    if (pSleep != NULL) {
        typedef void (WINAPI *SleepFunc)(DWORD);
        SleepFunc sleepFunc = (SleepFunc)pSleep;
        printf("调用Sleep函数,休眠1秒...\n");
        sleepFunc(1000);  // 休眠1毫秒
        printf("休眠结束\n");
    } else {
        printf("获取Sleep函数地址失败,错误码:%lu\n", GetLastError());
    }
    
    // 释放库引用
    if (!ManualFreeLibrary(hKernel32)) {
        printf("释放库引用失败,错误码:%lu\n", GetLastError());
        return 1;
    }
    printf("第一次释放库引用成功\n");
    
    // 再次释放库引用(应完全卸载)
    if (!ManualFreeLibrary(hKernel32_2)) {
        printf("第二次释放库引用失败,错误码:%lu\n", GetLastError());
        return 1;
    }
    printf("第二次释放库引用成功,库应该已被卸载\n");
    printf("测试完成\n");
    return 0;
}

待完善功能

该代码在执行dllmain时存在崩溃现象,目前代码跳过了dllmain的执行,对于绝大多数动态库的加载并没有影响,但对于特殊的动态库可能会存在问题,此处可能需要进一步完善。

注意:\color{#0000FF}{注意:}注意:

本代码并未经过充分测试,仅用于对PE格式的学习练习使用。\color{#FF0000}{本代码并未经过充分测试,仅用于对PE格式的学习练习使用。}本代码并未经过充分测试,仅用于对PE格式的学习练习使用。
生产环境,非必要请使用系统库中的Loadlibrary函数。\color{#FF0000}{生产环境,非必要请使用系统库中的Loadlibrary函数。}生产环境,非必要请使用系统库中的Loadlibrary函数。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐