Can I define a Windows PE checksum algorithm?

I would like to implement this in C #

I looked here: http://www.codeproject.com/KB/cpp/PEChecksum.aspx

And I know about the ImageHlp.dll function MapFileAndCheckSum.

However, for various reasons, I would like to implement this myself.

The best I have found is here: http://forum.sysinternals.com/optional-header-checksum-calculation_topic24214.html

But I do not understand the explanation. Can someone clarify how the checksum is calculated?

Thanks!

Update

I am from the sample code, I do not understand what this means, and how to translate it to 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 

Update # 2

Thanks, stumbled upon some Python code, which is also similar here

  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__) 

However, it still does not work for me - here is my conversion of this code:

 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(); } } } 

Can anyone tell me where I am stupid?

+6
source share
5 answers

Well finally it works fine ... my problem is that I used ints not uints !!! Thus, this code works (provided that the data is 4-byte aligned, otherwise you have to catch it a bit), and PECheckSum is the position of the CheckSum value in PE (which is not explicitly used in calculating the 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; } 
+5
source

The code in the forum post is not the same as the actual disassembly of the Windows PE code. the CodeProject article you are linking to gives a "convoluted 32-bit value of 16 bits" as:

 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 

What could you translate to C # like:

 // 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 
+2
source

The java code below from emmanuel may not work. In my case, it freezes and does not complete. I believe this is due to the heavy use of I / O in the code: in particular data.read (). This can be replaced with an array as a solution. Where RandomAccessFile reads the file completely or incrementally into byte array (s).

I tried to do this, but the calculation was too slow due to the conditional shift of the checksum to skip the bytes of the checksum header. I would suggest that the OP C # solution would have a similar problem.

This code also removes this.

public static long computeChecksum (data RandomAccessFile, int checksumOffset) throws an IOException {

  ... byte[] barray = new byte[(int) length]; data.readFully(barray); long i = 0; long ch1, ch2, ch3, ch4, dword; while (i < checksumOffset) { ch1 = ((int) barray[(int) i++]) & 0xff; ... checksum += dword = ch1 | (ch2 << 8) | (ch3 << 16) | (ch4 << 24); if (checksum > top) { checksum = (checksum & 0xffffffffL) + (checksum >> 32); } } i += 4; while (i < length) { ch1 = ((int) barray[(int) i++]) & 0xff; ... checksum += dword = ch1 | (ch2 << 8) | (ch3 << 16) | (ch4 << 24); if (checksum > top) { checksum = (checksum & 0xffffffffL) + (checksum >> 32); } } checksum = (checksum & 0xffff) + (checksum >> 16); checksum = checksum + (checksum >> 16); checksum = checksum & 0xffff; checksum += length; return checksum; } 

I still think that the code was too verbose and awkward, so I changed the raf channel and rewritten the bytes of the criminal to zero to eliminate the conditional. This code probably could still work with buffered cache-style reads.

 public static long computeChecksum2(FileChannel ch, int checksumOffset) throws IOException { ch.position(0); long sum = 0; long top = (long) Math.pow(2, 32); long length = ch.size(); ByteBuffer buffer = ByteBuffer.wrap(new byte[(int) length]); buffer.order(ByteOrder.LITTLE_ENDIAN); ch.read(buffer); buffer.putInt(checksumOffset, 0x0000); buffer.position(0); while (buffer.hasRemaining()) { sum += buffer.getInt() & 0xffffffffL; if (sum > top) { sum = (sum & 0xffffffffL) + (sum >> 32); } } sum = (sum & 0xffff) + (sum >> 16); sum = sum + (sum >> 16); sum = sum & 0xffff; sum += length; return sum; } 
+2
source

I tried to solve the same problem in Java. Here is the Mark solution translated into Java using RandomAccessFile instead of a byte array as input:

 static long computeChecksum(RandomAccessFile data, long checksumOffset) throws IOException { long checksum = 0; long top = (long) Math.pow(2, 32); long length = data.length(); for (long i = 0; i < length / 4; i++) { if (i == checksumOffset / 4) { data.skipBytes(4); continue; } long ch1 = data.read(); long ch2 = data.read(); long ch3 = data.read(); long ch4 = data.read(); long dword = ch1 + (ch2 << 8) + (ch3 << 16) + (ch4 << 24); checksum = (checksum & 0xffffffffL) + dword + (checksum >> 32); if (checksum > top) { checksum = (checksum & 0xffffffffL) + (checksum >> 32); } } checksum = (checksum & 0xffff) + (checksum >> 16); checksum = checksum + (checksum >> 16); checksum = checksum & 0xffff; checksum += length; return checksum; } 
0
source
 private unsafe static int GetSetPEChecksum(byte[] Array) { var Value = 0; var Count = Array.Length; if(Count >= 64) fixed (byte* array = Array) { var Index = 0; var Coff = *(int*)(array + 60); if(Coff >= 64 && Count >= Coff + 92) { *(int*)(array + Coff + 88) = 0; var Bound = Count >> 1; if((Count & 1) != 0) Value = array[Count & ~1]; var Short = (ushort*)array; while(Index < Bound) { Value += Short[Index++]; Value = (Value & 0xffff) + (Value >> 16); Value = (Value + (Value >> 16)) & 0xffff; } *(int*)(array + Coff + 88) = Value += Count; } } return Value; } 

If you need a short unsafe ... (No need to use double and long integers and no array alignment inside the algorithm is required)

0
source

Source: https://habr.com/ru/post/891039/


All Articles