如何查找文件是否为exe?

如何确保传递给我的程序的文件是一个有效的exe文件?

实际上我的程序将文件作为输入并运行它,但用户可以输入任何文件,所以我必须确保输入是一个有效的exe。

这取决于你对“有效性”的定义。

  • 如果要validation用户是否传递了“EXE”文件,请检查文件扩展名。
  • 如果要validation用户是否传递了可运行的 EXE文件(无论扩展名如何),请检查文件的前两个字节。 它们应包含值“MZ”。

如果你想要比“文件名以’.exe’结尾更深入的东西?” 但是你不想实际运行该程序,你可以检查PE头的存在性和有效性。 此外,检查前2个字节(PE文件的“MZ”)也将为DLL返回true。 如果你不想那样,你可以尝试这种方法。

Matt Pietrek撰写了几篇描述PE格式的精彩文章:

  • PE内部对等:Win32可移植可执行文件格式之旅
  • 深入研究Win32可移植可执行文件格式

这里的两个重要数据结构是IMAGE_DOS_HEADERIMAGE_NT_HEADERS32 / IMAGE_NT_HEADERS64 。 这些结构在Windows SDK的winnt.h中定义。 这里描述了许多这些PE结构。

您可以使用托管代码处理PE头(类似于此方法 )。 对于32-(i386)和64位(IA64,AMD64).exe PE文件,以下代码返回true(例如,对于DLL返回false)。 请参阅底部了解用法( ExeChecker.IsValidExe )。 如果需要,您可以添加其他检查以支持更多体系结构或进行更多validation。 有关更多常量,请参阅winnt.h

 using System; using System.IO; using System.Runtime.InteropServices; namespace ExeChecker { [StructLayout(LayoutKind.Sequential)] struct IMAGE_DOS_HEADER { public ushort e_magic; // Magic number public ushort e_cblp; // Bytes on last page of file public ushort e_cp; // Pages in file public ushort e_crlc; // Relocations public ushort e_cparhdr; // Size of header in paragraphs public ushort e_minalloc; // Minimum extra paragraphs needed public ushort e_maxalloc; // Maximum extra paragraphs needed public ushort e_ss; // Initial (relative) SS value public ushort e_sp; // Initial SP value public ushort e_csum; // Checksum public ushort e_ip; // Initial IP value public ushort e_cs; // Initial (relative) CS value public ushort e_lfarlc; // File address of relocation table public ushort e_ovno; // Overlay number public uint e_res1; // Reserved public uint e_res2; // Reserved public ushort e_oemid; // OEM identifier (for e_oeminfo) public ushort e_oeminfo; // OEM information; e_oemid specific public uint e_res3; // Reserved public uint e_res4; // Reserved public uint e_res5; // Reserved public uint e_res6; // Reserved public uint e_res7; // Reserved public int e_lfanew; // File address of new exe header } [StructLayout(LayoutKind.Sequential)] struct IMAGE_FILE_HEADER { public ushort Machine; public ushort NumberOfSections; public uint TimeDateStamp; public uint PointerToSymbolTable; public uint NumberOfSymbols; public ushort SizeOfOptionalHeader; public ushort Characteristics; } [StructLayout(LayoutKind.Sequential)] struct IMAGE_NT_HEADERS_COMMON { public uint Signature; public IMAGE_FILE_HEADER FileHeader; } [StructLayout(LayoutKind.Sequential)] struct IMAGE_NT_HEADERS32 { public uint Signature; public IMAGE_FILE_HEADER FileHeader; public IMAGE_OPTIONAL_HEADER32 OptionalHeader; } [StructLayout(LayoutKind.Sequential)] struct IMAGE_NT_HEADERS64 { public uint Signature; public IMAGE_FILE_HEADER FileHeader; public IMAGE_OPTIONAL_HEADER64 OptionalHeader; } [StructLayout(LayoutKind.Sequential)] struct IMAGE_OPTIONAL_HEADER32 { public ushort Magic; public byte MajorLinkerVersion; public byte MinorLinkerVersion; public uint SizeOfCode; public uint SizeOfInitializedData; public uint SizeOfUninitializedData; public uint AddressOfEntryPoint; public uint BaseOfCode; public uint BaseOfData; public uint ImageBase; public uint SectionAlignment; public uint FileAlignment; public ushort MajorOperatingSystemVersion; public ushort MinorOperatingSystemVersion; public ushort MajorImageVersion; public ushort MinorImageVersion; public ushort MajorSubsystemVersion; public ushort MinorSubsystemVersion; public uint Win32VersionValue; public uint SizeOfImage; public uint SizeOfHeaders; public uint CheckSum; public ushort Subsystem; public ushort DllCharacteristics; public uint SizeOfStackReserve; public uint SizeOfStackCommit; public uint SizeOfHeapReserve; public uint SizeOfHeapCommit; public uint LoaderFlags; public uint NumberOfRvaAndSizes; } [StructLayout(LayoutKind.Sequential)] struct IMAGE_OPTIONAL_HEADER64 { public ushort Magic; public byte MajorLinkerVersion; public byte MinorLinkerVersion; public uint SizeOfCode; public uint SizeOfInitializedData; public uint SizeOfUninitializedData; public uint AddressOfEntryPoint; public uint BaseOfCode; public ulong ImageBase; public uint SectionAlignment; public uint FileAlignment; public ushort MajorOperatingSystemVersion; public ushort MinorOperatingSystemVersion; public ushort MajorImageVersion; public ushort MinorImageVersion; public ushort MajorSubsystemVersion; public ushort MinorSubsystemVersion; public uint Win32VersionValue; public uint SizeOfImage; public uint SizeOfHeaders; public uint CheckSum; public ushort Subsystem; public ushort DllCharacteristics; public ulong SizeOfStackReserve; public ulong SizeOfStackCommit; public ulong SizeOfHeapReserve; public ulong SizeOfHeapCommit; public uint LoaderFlags; public uint NumberOfRvaAndSizes; } static class ExeChecker { public static bool IsValidExe(string fileName) { if (!File.Exists(fileName)) return false; try { using (var stream = File.OpenRead(fileName)) { IMAGE_DOS_HEADER dosHeader = GetDosHeader(stream); if (dosHeader.e_magic != IMAGE_DOS_SIGNATURE) return false; IMAGE_NT_HEADERS_COMMON ntHeader = GetCommonNtHeader(stream, dosHeader); if (ntHeader.Signature != IMAGE_NT_SIGNATURE) return false; if ((ntHeader.FileHeader.Characteristics & IMAGE_FILE_DLL) != 0) return false; switch (ntHeader.FileHeader.Machine) { case IMAGE_FILE_MACHINE_I386: return IsValidExe32(GetNtHeader32(stream, dosHeader)); case IMAGE_FILE_MACHINE_IA64: case IMAGE_FILE_MACHINE_AMD64: return IsValidExe64(GetNtHeader64(stream, dosHeader)); } } } catch (InvalidOperationException) { return false; } return true; } static bool IsValidExe32(IMAGE_NT_HEADERS32 ntHeader) { return ntHeader.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC; } static bool IsValidExe64(IMAGE_NT_HEADERS64 ntHeader) { return ntHeader.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC; } static IMAGE_DOS_HEADER GetDosHeader(Stream stream) { stream.Seek(0, SeekOrigin.Begin); return ReadStructFromStream(stream); } static IMAGE_NT_HEADERS_COMMON GetCommonNtHeader(Stream stream, IMAGE_DOS_HEADER dosHeader) { stream.Seek(dosHeader.e_lfanew, SeekOrigin.Begin); return ReadStructFromStream(stream); } static IMAGE_NT_HEADERS32 GetNtHeader32(Stream stream, IMAGE_DOS_HEADER dosHeader) { stream.Seek(dosHeader.e_lfanew, SeekOrigin.Begin); return ReadStructFromStream(stream); } static IMAGE_NT_HEADERS64 GetNtHeader64(Stream stream, IMAGE_DOS_HEADER dosHeader) { stream.Seek(dosHeader.e_lfanew, SeekOrigin.Begin); return ReadStructFromStream(stream); } static T ReadStructFromStream(Stream stream) { int structSize = Marshal.SizeOf(typeof(T)); IntPtr memory = IntPtr.Zero; try { memory = Marshal.AllocCoTaskMem(structSize); if (memory == IntPtr.Zero) throw new InvalidOperationException(); byte[] buffer = new byte[structSize]; int bytesRead = stream.Read(buffer, 0, structSize); if (bytesRead != structSize) throw new InvalidOperationException(); Marshal.Copy(buffer, 0, memory, structSize); return (T)Marshal.PtrToStructure(memory, typeof(T)); } finally { if (memory != IntPtr.Zero) Marshal.FreeCoTaskMem(memory); } } const ushort IMAGE_DOS_SIGNATURE = 0x5A4D; // MZ const uint IMAGE_NT_SIGNATURE = 0x00004550; // PE00 const ushort IMAGE_FILE_MACHINE_I386 = 0x014C; // Intel 386 const ushort IMAGE_FILE_MACHINE_IA64 = 0x0200; // Intel 64 const ushort IMAGE_FILE_MACHINE_AMD64 = 0x8664; // AMD64 const ushort IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10B; // PE32 const ushort IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20B; // PE32+ const ushort IMAGE_FILE_DLL = 0x2000; } class Program { static int Main(string[] args) { if (args.Length == 0) { Console.WriteLine("Please specify a file name to check."); return 1; } bool isValid = ExeChecker.IsValidExe(args[0]); Console.WriteLine(isValid); return 0; } } } 

一个非常原始的检查是检查文件扩展名:

 Path.GetExtension(filename).Equals(".exe", StringComparison.InvariantCultureIgnoreCase); 

但是,Windows支持可执行文件的各种扩展(例如.cmd,.com,.cpl,.scr 等等 ),因此上面的检查不会涵盖所有可执行文件。

正如其他人所提到的,您还可以检查文件头中的幻数是否存在例如MZ(以及其他一些更罕见的签名)。 除了检查扩展名之外,还可以使用第二次检查,尽管您永远无法确定该文件不是一个意外以相同文本开头的简单文本文件。

如果您要启动要检查的可执行文件,那么通过正确的exception处理启动它可能是最安全的:

 const int ERROR_BAD_EXE_FORMAT = 193; try { ProcessStartInfo psi = new ProcessStartInfo(); psi.UseShellExecute = false; psi.FileName = @"C:\tmp\testOLElocal_4.docx"; Process.Start(psi); } catch (Win32Exception ex) { if (ex.NativeErrorCode == ERROR_BAD_EXE_FORMAT) { // The exception message would be // "The specified executable is not a valid application for this OS platform." // Console.WriteLine("Not a valid executable."); } else { throw; } } 

注意:您没有提及有关您自己的应用程序的任何详细信息,但每当执行通过用户输入提供的代码时,您应该确保您的用户可以信任。

 bool IsExeFile(string path) { var twoBytes = new byte[2]; using(var fileStream = File.Open(path, FileMode.Open)) { fileStream.Read(twoBytes, 0, 2); } return Encoding.UTF8.GetString(twoBytes) == "MZ"; } 

您可以使用PE格式DLL检查文件是否是有效的PE格式文件。

PE文件不仅包含可执行代码。 它可以包含资源和代码,或者只包含资源而不包含代码。 PE文件也可以是本机的或托管的,或本机的但链接到托管代码等。根据您的想法,能够检查这些内容将非常有用。

 PE_EXE3 pef; int ok = FALSE; if (pef.openFile(fileNameAndPath)) { if (pef.IsValid()) { ok = pef.GetHasExecutableCode(); } pef.closeFile(); } 

您还可以找到以下有用的function:

 pef.GetIsOnlyResource() pef.GetHasExecutableCode() pef.GetIsPureDotNetModule() 

如果您只想检查文件扩展名:

 if (String.Equals(Path.GetExtension(filePath), ".exe", StringComparison.InvariantCultureIgnoreCase)) { ... } 

如果您需要validation文件是否真的可执行,则可以分析其标头。 有关于.exe文件头的信息: 链接 。

您也可以尝试以0xA3建议的方式运行该文件