Skip to content

Commit

Permalink
API: PE64 - Add new functionality to Pe64Helpers to recalculate a PE …
Browse files Browse the repository at this point in the history
…file checksum.

Unpackers: (x64) Ensure all unpacked files default to a checksum of 0.
Unpackers: (x64) Add support for new RecalculateFileChecksum setting.
  • Loading branch information
atom0s committed Mar 26, 2022
1 parent 2380a4b commit 540b4b0
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 2 deletions.
92 changes: 92 additions & 0 deletions Steamless.API/PE64/Pe64Helpers.cs
Expand Up @@ -27,6 +27,7 @@ namespace Steamless.API.PE64
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;

Expand Down Expand Up @@ -89,6 +90,97 @@ public static NativeApi64.ImageSectionHeader64 GetSection(byte[] rawData, int in
return GetStructure<NativeApi64.ImageSectionHeader64>(rawData, (int)dataOffset + (index * sectionSize));
}

/// <summary>
/// Calculates the PE checksum of the opened file. (OptionalHeader.Checksum should be 0 before calling this!)
/// </summary>
/// <param name="fStream"></param>
/// <returns></returns>
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);
}

/// <summary>
/// Updates the given files PE checksum value. (Path is assumed to be a 32bit PE file.)
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static bool UpdateFileChecksum(string path)
{
FileStream fStream = null;
var data = new byte[4];

try
{
// Open the file for reading/writing..
fStream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite);

// Read the starting offset to the files NT headers..
fStream.Position = (int)Marshal.OffsetOf(typeof(NativeApi64.ImageDosHeader64), "e_lfanew");
fStream.Read(data, 0, 4);

var offset = BitConverter.ToUInt32(data, 0);

// Move to the files CheckSum position..
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 };
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
{
return false;
}
finally
{
fStream?.Dispose();
}
}

/// <summary>
/// Scans the given data for the given pattern.
///
Expand Down
30 changes: 29 additions & 1 deletion Steamless.Unpacker.Variant30.x64/Main.cs
Expand Up @@ -189,6 +189,13 @@ public override bool ProcessFile(string file, SteamlessOptions options)
if (!this.Step6())
return false;

if (this.Options.RecalculateFileChecksum)
{
this.Log("Step 7 - Rebuild unpacked file checksum.", LogMessageType.Information);
if (!this.Step7())
return false;
}

return true;
}

Expand Down Expand Up @@ -500,12 +507,13 @@ private bool Step6()
if (this.File.DosStubSize > 0)
fStream.WriteBytes(this.File.DosStubData);

// Update the entry point of the file..
// Update the NT headers..
var ntHeaders = this.File.NtHeaders;
if (this.StubHeader.HasTlsCallback != 1)
ntHeaders.OptionalHeader.AddressOfEntryPoint = this.StubHeader.OriginalEntryPoint;
else
ntHeaders.OptionalHeader.AddressOfEntryPoint = this.TlsOepOverride;
ntHeaders.OptionalHeader.CheckSum = 0;
this.File.NtHeaders = ntHeaders;

// Write the NT headers to the file..
Expand Down Expand Up @@ -558,6 +566,26 @@ private bool Step6()
}
}

/// <summary>
/// Step #7
///
/// Recalculate the file checksum.
/// </summary>
/// <returns></returns>
private bool Step7()
{
var unpackedPath = this.File.FilePath + ".unpacked.exe";
if (!Pe64Helpers.UpdateFileChecksum(unpackedPath))
{
this.Log(" --> Error trying to recalculate unpacked file checksum!", LogMessageType.Error);
return false;
}

this.Log(" --> Unpacked file updated with new checksum!", LogMessageType.Success);
return true;

}

/// <summary>
/// Gets or sets if the Tls callback is being used as the Oep.
/// </summary>
Expand Down
30 changes: 29 additions & 1 deletion Steamless.Unpacker.Variant31.x64/Main.cs
Expand Up @@ -186,6 +186,13 @@ public override bool ProcessFile(string file, SteamlessOptions options)
if (!this.Step6())
return false;

if (this.Options.RecalculateFileChecksum)
{
this.Log("Step 7 - Rebuild unpacked file checksum.", LogMessageType.Information);
if (!this.Step7())
return false;
}

return true;
}

Expand Down Expand Up @@ -452,9 +459,10 @@ private bool Step6()
if (this.File.DosStubSize > 0)
fStream.WriteBytes(this.File.DosStubData);

// Update the entry point of the file..
// Update the NT headers..
var ntHeaders = this.File.NtHeaders;
ntHeaders.OptionalHeader.AddressOfEntryPoint = (uint)this.StubHeader.OriginalEntryPoint;
ntHeaders.OptionalHeader.CheckSum = 0;
this.File.NtHeaders = ntHeaders;

// Write the NT headers to the file..
Expand Down Expand Up @@ -507,6 +515,26 @@ private bool Step6()
}
}

/// <summary>
/// Step #7
///
/// Recalculate the file checksum.
/// </summary>
/// <returns></returns>
private bool Step7()
{
var unpackedPath = this.File.FilePath + ".unpacked.exe";
if (!Pe64Helpers.UpdateFileChecksum(unpackedPath))
{
this.Log(" --> Error trying to recalculate unpacked file checksum!", LogMessageType.Error);
return false;
}

this.Log(" --> Unpacked file updated with new checksum!", LogMessageType.Success);
return true;

}

/// <summary>
/// Gets or sets if the Tls callback is being used as the Oep.
/// </summary>
Expand Down

0 comments on commit 540b4b0

Please sign in to comment.