如何要求加载时链接的DLL必须设置/INTEGRITYCHECK选项?
验证隐式加载DLL的/INTEGRITYCHECK标志
实现方案
由于隐式链接的DLL由Windows加载器在应用代码运行前完成加载,要在应用逻辑启动前验证目标DLL的IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY标志,可通过静态链接的全局初始化逻辑实现,具体步骤如下:
1. 解析PE头检查标志
编写函数解析DLL的PE结构,提取DllCharacteristics字段并验证是否包含IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY(值为0x0080):
#include <Windows.h> #include <vector> #include <string> bool HasIntegrityCheckFlag(HMODULE hModule) { if (!hModule) return false; // 定位PE头起始 PIMAGE_DOS_HEADER pDosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(hModule); if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) return false; PIMAGE_NT_HEADERS pNtHeaders = reinterpret_cast<PIMAGE_NT_HEADERS>( reinterpret_cast<BYTE*>(hModule) + pDosHeader->e_lfanew ); if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE) return false; // 验证FORCE_INTEGRITY标志 return (pNtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY) != 0; }
2. 在应用启动前执行检查
利用C++全局对象的构造函数特性(构造逻辑在main/WinMain入口点前执行),遍历当前进程已加载的所有模块,筛选出自研DLL并验证标志:
class IntegrityChecker { public: IntegrityChecker() { HMODULE hModules[1024]; DWORD cbNeeded; if (!EnumProcessModules(GetCurrentProcess(), hModules, sizeof(hModules), &cbNeeded)) return; DWORD moduleCount = cbNeeded / sizeof(HMODULE); for (DWORD i = 0; i < moduleCount; ++i) { char szModulePath[MAX_PATH]; if (!GetModuleFileNameA(hModules[i], szModulePath, sizeof(szModulePath))) continue; std::string path(szModulePath); // 替换为你的自研DLL文件名/路径规则 if (path.find("MySelfLibA.dll") != std::string::npos || path.find("MySelfLibB.dll") != std::string::npos) { if (!HasIntegrityCheckFlag(hModules[i])) { // 验证失败,立即终止进程 MessageBoxA(NULL, "自研DLL完整性校验失败!", "错误", MB_ICONERROR); TerminateProcess(GetCurrentProcess(), 0x1); } } } } }; // 全局对象,确保在应用代码运行前执行校验 static IntegrityChecker g_integrityChecker;
关键注意事项
- 静态链接:校验逻辑必须静态链接到主应用,不能作为独立DLL,否则会被隐式加载,无法保证在目标DLL之后执行。
- 精准筛选:仅对自研DLL做校验,系统DLL或第三方依赖不一定启用
/INTEGRITYCHECK选项,避免误判。 - 防篡改强化:可将自研DLL的名单加密存储,直接硬编码文件名存在被篡改的风险。
- 进程终止:验证失败后调用
TerminateProcess是最直接的阻断方式,避免恶意DLL的代码被执行。
原理说明
/INTEGRITYCHECK选项会让Windows加载器强制验证DLL的数字签名有效性,若签名无效或文件被篡改,加载器会拒绝加载。但如果攻击者修改PE头移除该标志,加载器会跳过强制校验。通过上述方法,我们在应用启动前确认该标志存在,确保加载器已执行过签名校验,从而阻断恶意替换的DLL。
内容的提问来源于stack exchange,提问作者Aaron Huskerson
相关产品推荐
相关产品推荐

