使用 C# 获取托管 PE32 文件的校验和

Get checksum of managed PE32 file using C#

在我的托管 PE 文件上使用 dumpbin 我可以看到它在可选的 header 值中包含一个校验和。

我希望能够获得该校验和,以便我可以存储它并确保没有人替换我们构建机器生成的 PE 文件。我不担心这个校验和是否加密安全,因为我们只是用它来确定是否有人错误地将 PE 文件放在错误的位置,我们没有防范蓄意攻击。不过,我不确定如何从 PE 文件中获取校验和。 C# 是否有用于获取 PE 文件校验和的托管 API?

如果这个 diagram 是正确的,我可以只使用 FileStream 并检查 PE 文件的正确字节,但如果可能的话,我更愿意使用 .NET 框架来获得这个信息。

这是命令 dumpbin /HEADERS MyDLL.dll 中的字段图像。我在要检索的字段周围放置了一个黄色方块。

编辑1: 当我说我可以使用不安全的 C# 项目来读取 header 时,我把事情复杂化了。正如@xanatos 指出的那样,我可以只使用文件流来读取 header.

的字节

编辑2: 我删除了关于这是否是 PE32(+) 文件的问题,因为我能够确定它只是一个 PE32 文件。

这是我构建的控制台应用程序,用于从我正在使用的 PE 文件中获取校验和。

using System;
using System.IO;
using System.Text;

namespace ConsoleApp1
{
   class Program
   {
      public const int PeHeaderOffset = 0x003C;
      public const int CheckSumOffset = 0x0058;

      static void Main(string[] args)
      {
         while (true)
         {
            Console.Write("Path to PE file: ");
            string path = Console.ReadLine();

            using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read))
            {
               byte[] peHeaderPointer = new byte[4];
               byte[] checkSum = new byte[4];

               peHeaderPointer = ReadPeHeaderPointer(fileStream);

               int checkSumOffSet = BitConverter.ToInt32(peHeaderPointer, 0);
               checkSum = ReadChecksum(fileStream, checkSumOffSet);

               string hex = ByteArrayToHexString(checkSum);

               Console.WriteLine($"Checksum: {hex}");
               Console.ReadLine();
            }
         }
      }

      //This will not reverse the bytes because the BitConvert.ToInt32 is already reading it in the correct order.
      public static byte[] ReadPeHeaderPointer(FileStream fileStream)
      {
         byte[] bytes = new byte[4];

         fileStream.Seek(PeHeaderOffset, SeekOrigin.Begin);
         fileStream.Read(bytes, 0, 4);

         return bytes;
      }

      //This reverses the bytes to that this tool will match dumpbin /headers and dotPeek
      public static byte[] ReadChecksum(FileStream fileStream, int offSet)
      {
         byte[] bytes = new byte[4];

         fileStream.Seek(offSet + CheckSumOffset, SeekOrigin.Begin);
         fileStream.Read(bytes, 0, 4);

         bytes = ReverseBytes(bytes);

         return bytes;
      }

      //The PE file seems to be written to the file system in Big Endian 
      //I need to read them in Small Endian to match dumpbin and dotPeek
      public static byte[] ReverseBytes(byte[] bytes)
      {
         byte[] tempBytes = new byte[4];

         tempBytes[0] = bytes[3];
         tempBytes[1] = bytes[2];
         tempBytes[2] = bytes[1];
         tempBytes[3] = bytes[0];

         return tempBytes;
      }

      public static string ByteArrayToHexString(byte[] ba)
      {
         StringBuilder hex = new StringBuilder(ba.Length * 2);
         foreach (byte b in ba)
            hex.AppendFormat("{0:x2}", b);
         return hex.ToString().ToUpper();
      }
   }
}

我不完全确定为什么 BitConverter 使用 Little Endian 但 dll 是用 Big Endian 编写的。这就是为什么一些字节数组被反转而一些字节数组没有被反转的原因。