From 411f4f711c55a9a73483b565d1b9d60563a4544a Mon Sep 17 00:00:00 2001 From: atom0s Date: Fri, 23 Sep 2022 15:57:55 -0700 Subject: [PATCH] PE32: Replace manual PE checksum calculations with Win32 API call instead. PE64: Replace manual PE checksum calculations with Win32 API call instead. I was trying to avoid using Win32 API calls in this project for the most part, however, this calculation has multiple conditions that can alter its result. Steamless was only producing proper checksums about 40% of the time as a result of this. Instead, the project will now use the system API call 'MapFileAndCheckSum' to calculate the checksum properly. --- Steamless.API/PE32/Pe32Helpers.cs | 59 +++--------------------- Steamless.API/PE64/Pe64Helpers.cs | 59 +++--------------------- Steamless.API/Properties/AssemblyInfo.cs | 4 +- 3 files changed, 16 insertions(+), 106 deletions(-) diff --git a/Steamless.API/PE32/Pe32Helpers.cs b/Steamless.API/PE32/Pe32Helpers.cs index 8d33b5a..4874bac 100644 --- a/Steamless.API/PE32/Pe32Helpers.cs +++ b/Steamless.API/PE32/Pe32Helpers.cs @@ -90,49 +90,6 @@ namespace Steamless.API.PE32 return GetStructure(rawData, dataOffset + (index * sectionSize)); } - /// - /// Calculates the PE checksum of the opened file. (OptionalHeader.Checksum should be 0 before calling this!) - /// - /// - /// - private static byte[] CalculateChecksum(FileStream fStream) - { - fStream.Position = 0; - - var dataSize = fStream.Length; - var totalWords = dataSize / 2; - var sumTotal = 0; - - // Process the file data in uint16_t chunks.. - while (totalWords > 0) - { - var sumChunk = 0; - var chunkWords = totalWords; - - // Prepare next chunk size.. - if (chunkWords > UInt16.MaxValue) - chunkWords = UInt16.MaxValue; - - totalWords -= chunkWords; - - do - { - var data = new byte[2]; - fStream.Read(data, 0, 2); - sumChunk += BitConverter.ToUInt16(data, 0); - } while (--chunkWords != 0); - - sumTotal += (sumChunk >> 16) + (sumChunk & 0xFFFF); - } - - if ((dataSize % 2) != 0) - sumTotal += fStream.ReadByte(); - - var checksum = (uint)(((sumTotal >> 16) + (sumTotal & 0xFFFF)) + dataSize); - - return BitConverter.GetBytes(checksum); - } - /// /// Updates the given files PE checksum value. (Path is assumed to be a 32bit PE file.) /// @@ -140,6 +97,11 @@ namespace Steamless.API.PE32 /// public static bool UpdateFileChecksum(string path) { + // Obtain the proper checksum for the file.. + var ret = NativeApi32.MapFileAndCheckSum(path, out uint HeaderSum, out uint Checksum); + if (ret != 0) + return false; + FileStream fStream = null; var data = new byte[4]; @@ -158,17 +120,10 @@ namespace Steamless.API.PE32 offset += 4 + (uint)Marshal.SizeOf(typeof(NativeApi32.ImageFileHeader32)) + (uint)Marshal.OffsetOf(typeof(NativeApi32.ImageOptionalHeader32), "CheckSum").ToInt32(); fStream.Position = offset; - // Ensure the checksum is 0 to start.. - data = new byte[4] { 0, 0, 0, 0 }; + // Overwrite the file checksum.. + data = BitConverter.GetBytes(Checksum); fStream.Write(data, 0, 4); - // Calculate the new checksum.. - var checksum = CalculateChecksum(fStream); - - // Update the checksum value.. - fStream.Position = offset; - fStream.Write(checksum, 0, 4); - return true; } catch diff --git a/Steamless.API/PE64/Pe64Helpers.cs b/Steamless.API/PE64/Pe64Helpers.cs index d3e8289..4ac472f 100644 --- a/Steamless.API/PE64/Pe64Helpers.cs +++ b/Steamless.API/PE64/Pe64Helpers.cs @@ -90,49 +90,6 @@ namespace Steamless.API.PE64 return GetStructure(rawData, (int)dataOffset + (index * sectionSize)); } - /// - /// Calculates the PE checksum of the opened file. (OptionalHeader.Checksum should be 0 before calling this!) - /// - /// - /// - private static byte[] CalculateChecksum(FileStream fStream) - { - fStream.Position = 0; - - var dataSize = fStream.Length; - var totalWords = dataSize / 2; - var sumTotal = 0; - - // Process the file data in uint16_t chunks.. - while (totalWords > 0) - { - var sumChunk = 0; - var chunkWords = totalWords; - - // Prepare next chunk size.. - if (chunkWords > UInt16.MaxValue) - chunkWords = UInt16.MaxValue; - - totalWords -= chunkWords; - - do - { - var data = new byte[2]; - fStream.Read(data, 0, 2); - sumChunk += BitConverter.ToUInt16(data, 0); - } while (--chunkWords != 0); - - sumTotal += (sumChunk >> 16) + (sumChunk & 0xFFFF); - } - - if ((dataSize % 2) != 0) - sumTotal += fStream.ReadByte(); - - var checksum = (uint)(((sumTotal >> 16) + (sumTotal & 0xFFFF)) + dataSize); - - return BitConverter.GetBytes(checksum); - } - /// /// Updates the given files PE checksum value. (Path is assumed to be a 32bit PE file.) /// @@ -140,6 +97,11 @@ namespace Steamless.API.PE64 /// public static bool UpdateFileChecksum(string path) { + // Obtain the proper checksum for the file.. + var ret = NativeApi64.MapFileAndCheckSum(path, out uint HeaderSum, out uint Checksum); + if (ret != 0) + return false; + FileStream fStream = null; var data = new byte[4]; @@ -158,17 +120,10 @@ namespace Steamless.API.PE64 offset += 4 + (uint)Marshal.SizeOf(typeof(NativeApi64.ImageFileHeader64)) + (uint)Marshal.OffsetOf(typeof(NativeApi64.ImageOptionalHeader64), "CheckSum").ToInt32(); fStream.Position = offset; - // Ensure the checksum is 0 to start.. - data = new byte[4] { 0, 0, 0, 0 }; + // Overwrite the file checksum.. + data = BitConverter.GetBytes(Checksum); fStream.Write(data, 0, 4); - // Calculate the new checksum.. - var checksum = CalculateChecksum(fStream); - - // Update the checksum value.. - fStream.Position = offset; - fStream.Write(checksum, 0, 4); - return true; } catch diff --git a/Steamless.API/Properties/AssemblyInfo.cs b/Steamless.API/Properties/AssemblyInfo.cs index 5bc7c92..1e09250 100644 --- a/Steamless.API/Properties/AssemblyInfo.cs +++ b/Steamless.API/Properties/AssemblyInfo.cs @@ -36,5 +36,5 @@ using System.Runtime.InteropServices; [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: Guid("56c95629-3b34-47fe-b988-04274409294f")] -[assembly: AssemblyVersion("1.0.0.5")] -[assembly: AssemblyFileVersion("1.0.0.5")] \ No newline at end of file +[assembly: AssemblyVersion("1.0.0.6")] +[assembly: AssemblyFileVersion("1.0.0.6")] \ No newline at end of file