【问题标题】:Get checksum of managed PE32 file using C#使用 C# 获取托管 PE32 文件的校验和
【发布时间】:2017-05-04 11:59:45
【问题描述】:

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

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

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

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

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

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

【问题讨论】:

  • 要打开一个二进制文件(一个 exe 或 dll)你不需要“不安全”的代码...你只需要用FileStream打开它。
  • 你知道我从来没有真正想过这个,那应该只是一个字节流。
  • 您可以使用此 Windows API:ImageNtHeader。它将返回一个指向IMAGE_NT_HEADERS 的指针,在OptionalHeader 内部有Checksum
  • @xanatos 您是否碰巧知道 .NET 是否在任何地方使用该 API?如果您可以发布一个如何使用FileStream 阅读标题的示例,我将非常乐意接受它作为答案。虽然如果我必须以这种方式读出它,我更愿意使用一个将它作为属性返回的 API,这就是我要做的。
  • @xanatos 感谢您对FileStream 的建议。真的让我免于过度复杂化。

标签: c# .net checksum portable-executable


【解决方案1】:

这是我构建的控制台应用程序,用于从我正在使用的 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 编写的。这就是为什么有些字节数组被反转而有些没有被反转的原因。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-30
    • 2023-04-03
    • 1970-01-01
    • 2016-11-23
    • 1970-01-01
    • 2010-09-23
    • 1970-01-01
    相关资源
    最近更新 更多