mirror of
https://github.com/SabreTools/SabreTools.Serialization.git
synced 2026-04-26 08:10:08 +00:00
Port more PE extraction
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.IO.Compression.zlib;
|
||||
using SabreTools.IO.Extensions;
|
||||
using SabreTools.Matching;
|
||||
using SabreTools.Serialization.Interfaces;
|
||||
@@ -1084,12 +1085,140 @@ namespace SabreTools.Serialization.Wrappers
|
||||
#region Extraction
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <remarks>This only extracts overlay and resource data</remarks>
|
||||
/// <remarks>
|
||||
/// This extracts the following data:
|
||||
/// - Archives and executables in the overlay
|
||||
/// - Archives and executables in resource data
|
||||
/// - CExe-compressed resource data
|
||||
/// </remarks>
|
||||
public bool Extract(string outputDirectory, bool includeDebug)
|
||||
{
|
||||
bool cexe = ExtractCExe(outputDirectory, includeDebug);
|
||||
bool overlay = ExtractFromOverlay(outputDirectory, includeDebug);
|
||||
bool resources = ExtractFromResources(outputDirectory, includeDebug);
|
||||
return overlay || resources;
|
||||
return cexe || overlay || resources;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract a CExe-compressed executable
|
||||
/// </summary>
|
||||
/// <param name="outputDirectory">Output directory to write to</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>True if extraction succeeded, false otherwise</returns>
|
||||
public bool ExtractCExe(string outputDirectory, bool includeDebug)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Get all resources of type 99 with index 2
|
||||
var resources = FindResourceByNamedType("99, 2");
|
||||
if (resources == null || resources.Count == 0)
|
||||
return false;
|
||||
|
||||
// Get the first resource of type 99 with index 2
|
||||
var payload = resources[0];
|
||||
if (payload == null || payload.Length == 0)
|
||||
return false;
|
||||
|
||||
// Create the output data buffer
|
||||
byte[]? data = [];
|
||||
|
||||
// If we had the decompression DLL included, it's zlib
|
||||
if (FindResourceByNamedType("99, 1").Count > 0)
|
||||
data = ExtractCExeZlib(payload);
|
||||
else
|
||||
data = ExtractCExeLZ(payload);
|
||||
|
||||
// If we have no data
|
||||
if (data == null)
|
||||
return false;
|
||||
|
||||
// Create the temp filename
|
||||
string tempFile = string.IsNullOrEmpty(Filename) ? "temp.sxe" : $"{Path.GetFileNameWithoutExtension(Filename)}.sxe";
|
||||
tempFile = Path.Combine(outputDirectory, tempFile);
|
||||
var directoryName = Path.GetDirectoryName(tempFile);
|
||||
if (directoryName != null && !Directory.Exists(directoryName))
|
||||
Directory.CreateDirectory(directoryName);
|
||||
|
||||
// Write the file data to a temp file
|
||||
var tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
|
||||
tempStream.Write(data, 0, data.Length);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.Error.WriteLine(ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract CExe data compressed with LZ
|
||||
/// </summary>
|
||||
/// <param name="resource">Resource data to inflate</param>
|
||||
/// <returns>Inflated data on success, null otherwise</returns>
|
||||
private byte[]? ExtractCExeLZ(byte[] resource)
|
||||
{
|
||||
try
|
||||
{
|
||||
var decompressor = IO.Compression.SZDD.Decompressor.CreateSZDD(resource);
|
||||
var dataStream = new MemoryStream();
|
||||
decompressor.CopyTo(dataStream);
|
||||
return dataStream.ToArray();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Reset the data
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract CExe data compressed with zlib
|
||||
/// </summary>
|
||||
/// <param name="resource">Resource data to inflate</param>
|
||||
/// <returns>Inflated data on success, null otherwise</returns>
|
||||
private byte[]? ExtractCExeZlib(byte[] resource)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Inflate the data into the buffer
|
||||
var zstream = new ZLib.z_stream_s();
|
||||
byte[] data = new byte[resource.Length * 4];
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* payloadPtr = resource)
|
||||
fixed (byte* dataPtr = data)
|
||||
{
|
||||
zstream.next_in = payloadPtr;
|
||||
zstream.avail_in = (uint)resource.Length;
|
||||
zstream.total_in = (uint)resource.Length;
|
||||
zstream.next_out = dataPtr;
|
||||
zstream.avail_out = (uint)data.Length;
|
||||
zstream.total_out = 0;
|
||||
|
||||
ZLib.inflateInit_(zstream, ZLib.zlibVersion(), resource.Length);
|
||||
int zret = ZLib.inflate(zstream, 1);
|
||||
ZLib.inflateEnd(zstream);
|
||||
}
|
||||
}
|
||||
|
||||
// Trim the buffer to the proper size
|
||||
uint read = zstream.total_out;
|
||||
#if NETFRAMEWORK
|
||||
var temp = new byte[read];
|
||||
Array.Copy(data, temp, read);
|
||||
data = temp;
|
||||
#else
|
||||
data = new ReadOnlySpan<byte>(data, 0, (int)read).ToArray();
|
||||
#endif
|
||||
return data;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Reset the data
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1097,7 +1226,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
/// </summary>
|
||||
/// <param name="outputDirectory">Output directory to write to</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
private bool ExtractFromOverlay(string outputDirectory, bool includeDebug)
|
||||
public bool ExtractFromOverlay(string outputDirectory, bool includeDebug)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -1152,7 +1281,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
/// </summary>
|
||||
/// <param name="outputDirectory">Output directory to write to</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
private bool ExtractFromResources(string outputDirectory, bool includeDebug)
|
||||
public bool ExtractFromResources(string outputDirectory, bool includeDebug)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user