在Windows平台用C++编程检测.exe文件的32/64位架构(无需运行)
判断Windows EXE的32/64位架构(无需运行)
当然可以做到!完全不需要运行目标EXE,我们只需要直接解析PE文件的头部结构就能准确判断它的架构——这是Windows平台下最常用的前置检测方式,比运行时分析靠谱多了。
核心原理
Windows下的EXE/DLL都遵循PE(Portable Executable)文件格式,它的头部包含了所有关键的元数据,其中就有标识处理器架构的字段:
- DOS头(
IMAGE_DOS_HEADER):文件最开头的部分,其中e_lfanew字段存储了NT头的偏移地址。 - NT头(
IMAGE_NT_HEADERS):分为两部分:IMAGE_FILE_HEADER.Machine:直接标识目标CPU架构,比如:IMAGE_FILE_MACHINE_I386(0x014C)= 32位x86IMAGE_FILE_MACHINE_AMD64(0x8664)= 64位x64
IMAGE_OPTIONAL_HEADER.Magic:可选头的魔法值,辅助验证:0x10B= PE32(32位)0x20B= PE32+(64位)
C++实现代码示例
下面是一个完整的实现,使用Win32 API直接读取文件头部,无需运行EXE:
#include <windows.h> #include <iostream> #include <string> enum class ExeArchitecture { Unknown, X86, X64 }; ExeArchitecture GetExeArchitecture(const std::wstring& filePath) { // 以只读方式打开文件 HANDLE hFile = CreateFileW(filePath.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); if (hFile == INVALID_HANDLE_VALUE) { std::cerr << "Failed to open file. Error: " << GetLastError() << std::endl; return ExeArchitecture::Unknown; } // 读取DOS头 IMAGE_DOS_HEADER dosHeader; DWORD bytesRead; if (!ReadFile(hFile, &dosHeader, sizeof(dosHeader), &bytesRead, nullptr) || bytesRead != sizeof(dosHeader)) { std::cerr << "Failed to read DOS header. Error: " << GetLastError() << std::endl; CloseHandle(hFile); return ExeArchitecture::Unknown; } // 验证DOS签名(MZ) if (dosHeader.e_magic != IMAGE_DOS_SIGNATURE) { std::cerr << "Not a valid PE file (invalid DOS signature)." << std::endl; CloseHandle(hFile); return ExeArchitecture::Unknown; } // 跳转到NT头位置 LARGE_INTEGER ntHeaderOffset; ntHeaderOffset.QuadPart = dosHeader.e_lfanew; if (!SetFilePointerEx(hFile, ntHeaderOffset, nullptr, FILE_BEGIN)) { std::cerr << "Failed to seek to NT header. Error: " << GetLastError() << std::endl; CloseHandle(hFile); return ExeArchitecture::Unknown; } // 读取NT头签名和FileHeader IMAGE_NT_HEADERS32 ntHeader32; if (!ReadFile(hFile, &ntHeader32, sizeof(IMAGE_NT_SIGNATURE) + sizeof(IMAGE_FILE_HEADER), &bytesRead, nullptr) || bytesRead != sizeof(IMAGE_NT_SIGNATURE) + sizeof(IMAGE_FILE_HEADER)) { std::cerr << "Failed to read NT header. Error: " << GetLastError() << std::endl; CloseHandle(hFile); return ExeArchitecture::Unknown; } // 验证NT签名(PE\0\0) if (ntHeader32.Signature != IMAGE_NT_SIGNATURE) { std::cerr << "Not a valid PE file (invalid NT signature)." << std::endl; CloseHandle(hFile); return ExeArchitecture::Unknown; } // 判断架构 ExeArchitecture arch = ExeArchitecture::Unknown; switch (ntHeader32.FileHeader.Machine) { case IMAGE_FILE_MACHINE_I386: arch = ExeArchitecture::X86; break; case IMAGE_FILE_MACHINE_AMD64: arch = ExeArchitecture::X64; break; default: std::cerr << "Unsupported architecture: 0x" << std::hex << ntHeader32.FileHeader.Machine << std::endl; break; } CloseHandle(hFile); return arch; } int main() { std::wstring filePath = L"C:\\Windows\\notepad.exe"; ExeArchitecture arch = GetExeArchitecture(filePath); switch (arch) { case ExeArchitecture::X86: std::cout << "32-bit (x86) EXE" << std::endl; break; case ExeArchitecture::X64: std::cout << "64-bit (x64) EXE" << std::endl; break; default: std::cout << "Unknown or invalid EXE" << std::endl; break; } return 0; }
注意事项
- 确保以只读权限打开文件,避免对原文件造成修改。
- 代码中加入了多步验证(DOS签名、NT签名),避免处理非PE文件导致的错误。
- 对于64位PE文件,
IMAGE_NT_HEADERS会使用IMAGE_NT_HEADERS64结构体,但我们只需要FileHeader.Machine字段就能判断架构,所以无需完整读取整个64位NT头。 - 若需要更细致的架构判断(比如ARM等),可以扩展
switch语句处理对应的Machine枚举值(如IMAGE_FILE_MACHINE_ARM64等)。
内容的提问来源于stack exchange,提问作者user1428926
相关产品推荐
相关产品推荐

