任何人都可以定义Windows PE校验和算法吗?

Kra*_*ram 6 c# algorithm checksum portable-executable

我想在C#中实现这个

我看过这里:http: //www.codeproject.com/KB/cpp/PEChecksum.aspx

并且我知道ImageHlp.dll MapFileAndCheckSum函数.

但是,出于各种原因,我想自己实现.

我找到的最好的是:http: //forum.sysinternals.com/optional-header-checksum-calculation_topic24214.html

但是,我不明白这个解释.任何人都可以澄清如何计算校验和吗?

谢谢!

更新

我从代码示例中,我不明白这意味着什么,以及如何将其转换为C#

sum -= sum < low 16 bits of CheckSum in file // 16-bit borrow 
sum -= low 16 bits of CheckSum in file 
sum -= sum < high 16 bits of CheckSum in file 
sum -= high 16 bits of CheckSum in file 
Run Code Online (Sandbox Code Playgroud)

更新#2

谢谢,遇到了一些Python代码,不会太相似这里

    def generate_checksum(self):

    # This will make sure that the data representing the PE image
    # is updated with any changes that might have been made by
    # assigning values to header fields as those are not automatically
    # updated upon assignment.
    #
    self.__data__ = self.write()

    # Get the offset to the CheckSum field in the OptionalHeader
    #
    checksum_offset = self.OPTIONAL_HEADER.__file_offset__ + 0x40 # 64

    checksum = 0

    # Verify the data is dword-aligned. Add padding if needed
    #
    remainder = len(self.__data__) % 4
    data = self.__data__ + ( '\0' * ((4-remainder) * ( remainder != 0 )) )

    for i in range( len( data ) / 4 ):

        # Skip the checksum field
        #
        if i == checksum_offset / 4:
            continue

        dword = struct.unpack('I', data[ i*4 : i*4+4 ])[0]
        checksum = (checksum & 0xffffffff) + dword + (checksum>>32)
        if checksum > 2**32:
            checksum = (checksum & 0xffffffff) + (checksum >> 32)

    checksum = (checksum & 0xffff) + (checksum >> 16)
    checksum = (checksum) + (checksum >> 16)
    checksum = checksum & 0xffff

    # The length is the one of the original data, not the padded one
    #
    return checksum + len(self.__data__)
Run Code Online (Sandbox Code Playgroud)

但是,它仍然不适合我 - 这是我对此代码的转换:

using System;
using System.IO;

namespace CheckSumTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var data = File.ReadAllBytes(@"c:\Windows\notepad.exe");

            var PEStart = BitConverter.ToInt32(data, 0x3c);
            var PECoffStart = PEStart + 4;
            var PEOptionalStart = PECoffStart + 20;
            var PECheckSum = PEOptionalStart + 64;
            var checkSumInFile = BitConverter.ToInt32(data, PECheckSum);
            Console.WriteLine(string.Format("{0:x}", checkSumInFile));

            long checksum = 0;

            var remainder = data.Length % 4;
            if (remainder > 0)
            {
                Array.Resize(ref data, data.Length + (4 - remainder));
            }

            var top = Math.Pow(2, 32);

            for (int i = 0; i < data.Length / 4; i++)
            {
                if (i == PECheckSum / 4)
                {
                    continue;
                }
                var dword = BitConverter.ToInt32(data, i * 4);
                checksum = (checksum & 0xffffffff) + dword + (checksum >> 32);
                if (checksum > top)
                {
                    checksum = (checksum & 0xffffffff) + (checksum >> 32);
                }
            }

            checksum = (checksum & 0xffff) + (checksum >> 16);
            checksum = (checksum) + (checksum >> 16);
            checksum = checksum & 0xffff;

            checksum += (uint)data.Length; 
            Console.WriteLine(string.Format("{0:x}", checksum));

            Console.ReadKey();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

谁能告诉我我在哪里傻了?

use*_*116 5

论坛帖子中的代码与实际反汇编 Windows PE 代码期间注意到的代码并不完全相同。您引用CodeProject 文章将“将 32 位值折叠为 16 位”为:

mov edx,eax    ; EDX = EAX
shr edx,10h    ; EDX = EDX >> 16    EDX is high order
and eax,0FFFFh ; EAX = EAX & 0xFFFF EAX is low order
add eax,edx    ; EAX = EAX + EDX    High Order Folded into Low Order
mov edx,eax    ; EDX = EAX
shr edx,10h    ; EDX = EDX >> 16    EDX is high order
add eax,edx    ; EAX = EAX + EDX    High Order Folded into Low Order
and eax,0FFFFh ; EAX = EAX & 0xFFFF EAX is low order 16 bits  
Run Code Online (Sandbox Code Playgroud)

您可以将其转换为 C# 为:

// given: uint sum = ...;
uint high = sum >> 16; // take high order from sum
sum &= 0xFFFF;         // clear out high order from sum
sum += high;           // fold high order into low order

high = sum >> 16;      // take the new high order of sum
sum += high;           // fold the new high order into sum
sum &= 0xFFFF;         // mask to 16 bits
Run Code Online (Sandbox Code Playgroud)


Kra*_*ram 5

好的,终于让它工作正常...我的问题是我使用的是不是uint !!! 因此,这段代码可以工作(假设数据是4字节对齐的,否则你必须将它填平一点) - 而PECheckSum是PE中CheckSum值的位置(在计算校验和时显然不会使用它! !)

static uint CalcCheckSum(byte[] data, int PECheckSum)
{
    long checksum = 0;
    var top = Math.Pow(2, 32);

    for (var i = 0; i < data.Length / 4; i++)
    {
        if (i == PECheckSum / 4)
        {
            continue;
        }
        var dword = BitConverter.ToUInt32(data, i * 4);
        checksum = (checksum & 0xffffffff) + dword + (checksum >> 32);
        if (checksum > top)
        {
            checksum = (checksum & 0xffffffff) + (checksum >> 32);
        }
    }

    checksum = (checksum & 0xffff) + (checksum >> 16);
    checksum = (checksum) + (checksum >> 16);
    checksum = checksum & 0xffff;

    checksum += (uint)data.Length;
    return (uint)checksum;

}
Run Code Online (Sandbox Code Playgroud)

  • 这是不正确的。它与 ImageHlp.dll `MapFileAndCheckSum` 输出不匹配。使用 http://www.codeproject.com/Articles/19326/An-Analysis-of-the-Windows-PE-Checksum-Algorithm 中提供的 PE Checksum 可执行文件检查输出 (2认同)