详解PE文件(二十六)手写Loadlibrary
在Windows DLL中,有一种特殊的导出函数称为"转发函数"。这些函数不是实际的代码实现,而是将函数调用转发到另一个DLL中的函数。转发函数在导出表中的地址指向一个字符串,格式为"DLL名称.函数名称"或"DLL名称.#序号"。该代码在执行dllmain时存在崩溃现象,目前代码跳过了dllmain的执行,对于绝大多数动态库的加载并没有影响,但对于特殊的动态库可能会存在问题,此处可能需要进一步完
1. PE文件映射 (MapFileToMemory)
这个函数负责将PE文件手动映射到内存中,而不是使用系统的LoadLibrary:
- 打开并读取PE文件
- 分配足够的虚拟内存来容纳整个映像
- 复制PE头部和所有节数据到分配的内存中
2. 重定位处理 (ProcessRelocations)
当DLL的实际加载地址与其首选映像基址不同时,需要进行重定位:
- 遍历重定位表中的所有重定位项
- 根据地址差异调整需要重定位的地址
- 支持32位和64位重定位条目
3. 导入表解析 (ProcessImports)
处理DLL的依赖关系:
- 遍历导入表中的每个依赖DLL
- 递归调用ManualLoadLibrary加载依赖项
- 解析按名称和按序号导入的函数
- 更新导入地址表(IAT)
4. 导出表处理 (ProcessExports)
构建导出函数索引以供后续查询:
- 解析导出表结构
- 构建函数地址、名称和序号的索引
5. 函数地址查询 (ManualGetProcAddress)
根据函数名称或序号查找函数地址:
- 支持按名称和按序号查找
- 使用预先构建的导出表索引快速定位
关键技术点
- 线程安全:使用临界区保护共享数据结构
- 循环依赖预防:通过已加载模块列表避免重复加载
- 引用计数管理:确保正确的资源管理和释放
- PE结构解析:手动解析复杂的PE文件结构
转发函数处理详解
在Windows DLL中,有一种特殊的导出函数称为"转发函数"。这些函数不是实际的代码实现,而是将函数调用转发到另一个DLL中的函数。转发函数在导出表中的地址指向一个字符串,格式为"DLL名称.函数名称"或"DLL名称.#序号"。
处理流程
- 在处理导出表时,检查每个导出函数是否为转发函数
- 如果是转发函数,解析其目标DLL和函数信息
- 加载目标DLL并获取目标函数地址
- 将转发函数信息存储在模块的转发函数列表中
- 在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函数。
更多推荐



所有评论(0)