Skip to content

Commit ef6ff85

Browse files
committed
Port more PE extraction
1 parent bb93792 commit ef6ff85

File tree

1 file changed

+133
-4
lines changed

1 file changed

+133
-4
lines changed

SabreTools.Serialization/Wrappers/PortableExecutable.cs

Lines changed: 133 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.IO;
44
using System.Text;
5+
using SabreTools.IO.Compression.zlib;
56
using SabreTools.IO.Extensions;
67
using SabreTools.Matching;
78
using SabreTools.Serialization.Interfaces;
@@ -1084,20 +1085,148 @@ private void ParseDebugTable()
10841085
#region Extraction
10851086

10861087
/// <inheritdoc/>
1087-
/// <remarks>This only extracts overlay and resource data</remarks>
1088+
/// <remarks>
1089+
/// This extracts the following data:
1090+
/// - Archives and executables in the overlay
1091+
/// - Archives and executables in resource data
1092+
/// - CExe-compressed resource data
1093+
/// </remarks>
10881094
public bool Extract(string outputDirectory, bool includeDebug)
10891095
{
1096+
bool cexe = ExtractCExe(outputDirectory, includeDebug);
10901097
bool overlay = ExtractFromOverlay(outputDirectory, includeDebug);
10911098
bool resources = ExtractFromResources(outputDirectory, includeDebug);
1092-
return overlay || resources;
1099+
return cexe || overlay || resources;
1100+
}
1101+
1102+
/// <summary>
1103+
/// Extract a CExe-compressed executable
1104+
/// </summary>
1105+
/// <param name="outputDirectory">Output directory to write to</param>
1106+
/// <param name="includeDebug">True to include debug data, false otherwise</param>
1107+
/// <returns>True if extraction succeeded, false otherwise</returns>
1108+
public bool ExtractCExe(string outputDirectory, bool includeDebug)
1109+
{
1110+
try
1111+
{
1112+
// Get all resources of type 99 with index 2
1113+
var resources = FindResourceByNamedType("99, 2");
1114+
if (resources == null || resources.Count == 0)
1115+
return false;
1116+
1117+
// Get the first resource of type 99 with index 2
1118+
var payload = resources[0];
1119+
if (payload == null || payload.Length == 0)
1120+
return false;
1121+
1122+
// Create the output data buffer
1123+
byte[]? data = [];
1124+
1125+
// If we had the decompression DLL included, it's zlib
1126+
if (FindResourceByNamedType("99, 1").Count > 0)
1127+
data = ExtractCExeZlib(payload);
1128+
else
1129+
data = ExtractCExeLZ(payload);
1130+
1131+
// If we have no data
1132+
if (data == null)
1133+
return false;
1134+
1135+
// Create the temp filename
1136+
string tempFile = string.IsNullOrEmpty(Filename) ? "temp.sxe" : $"{Path.GetFileNameWithoutExtension(Filename)}.sxe";
1137+
tempFile = Path.Combine(outputDirectory, tempFile);
1138+
var directoryName = Path.GetDirectoryName(tempFile);
1139+
if (directoryName != null && !Directory.Exists(directoryName))
1140+
Directory.CreateDirectory(directoryName);
1141+
1142+
// Write the file data to a temp file
1143+
var tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
1144+
tempStream.Write(data, 0, data.Length);
1145+
1146+
return true;
1147+
}
1148+
catch (Exception ex)
1149+
{
1150+
if (includeDebug) Console.Error.WriteLine(ex);
1151+
return false;
1152+
}
1153+
}
1154+
1155+
/// <summary>
1156+
/// Extract CExe data compressed with LZ
1157+
/// </summary>
1158+
/// <param name="resource">Resource data to inflate</param>
1159+
/// <returns>Inflated data on success, null otherwise</returns>
1160+
private byte[]? ExtractCExeLZ(byte[] resource)
1161+
{
1162+
try
1163+
{
1164+
var decompressor = IO.Compression.SZDD.Decompressor.CreateSZDD(resource);
1165+
var dataStream = new MemoryStream();
1166+
decompressor.CopyTo(dataStream);
1167+
return dataStream.ToArray();
1168+
}
1169+
catch
1170+
{
1171+
// Reset the data
1172+
return null;
1173+
}
1174+
}
1175+
1176+
/// <summary>
1177+
/// Extract CExe data compressed with zlib
1178+
/// </summary>
1179+
/// <param name="resource">Resource data to inflate</param>
1180+
/// <returns>Inflated data on success, null otherwise</returns>
1181+
private byte[]? ExtractCExeZlib(byte[] resource)
1182+
{
1183+
try
1184+
{
1185+
// Inflate the data into the buffer
1186+
var zstream = new ZLib.z_stream_s();
1187+
byte[] data = new byte[resource.Length * 4];
1188+
unsafe
1189+
{
1190+
fixed (byte* payloadPtr = resource)
1191+
fixed (byte* dataPtr = data)
1192+
{
1193+
zstream.next_in = payloadPtr;
1194+
zstream.avail_in = (uint)resource.Length;
1195+
zstream.total_in = (uint)resource.Length;
1196+
zstream.next_out = dataPtr;
1197+
zstream.avail_out = (uint)data.Length;
1198+
zstream.total_out = 0;
1199+
1200+
ZLib.inflateInit_(zstream, ZLib.zlibVersion(), resource.Length);
1201+
int zret = ZLib.inflate(zstream, 1);
1202+
ZLib.inflateEnd(zstream);
1203+
}
1204+
}
1205+
1206+
// Trim the buffer to the proper size
1207+
uint read = zstream.total_out;
1208+
#if NETFRAMEWORK
1209+
var temp = new byte[read];
1210+
Array.Copy(data, temp, read);
1211+
data = temp;
1212+
#else
1213+
data = new ReadOnlySpan<byte>(data, 0, (int)read).ToArray();
1214+
#endif
1215+
return data;
1216+
}
1217+
catch
1218+
{
1219+
// Reset the data
1220+
return null;
1221+
}
10931222
}
10941223

10951224
/// <summary>
10961225
/// Extract data from the overlay
10971226
/// </summary>
10981227
/// <param name="outputDirectory">Output directory to write to</param>
10991228
/// <param name="includeDebug">True to include debug data, false otherwise</param>
1100-
private bool ExtractFromOverlay(string outputDirectory, bool includeDebug)
1229+
public bool ExtractFromOverlay(string outputDirectory, bool includeDebug)
11011230
{
11021231
try
11031232
{
@@ -1152,7 +1281,7 @@ private bool ExtractFromOverlay(string outputDirectory, bool includeDebug)
11521281
/// </summary>
11531282
/// <param name="outputDirectory">Output directory to write to</param>
11541283
/// <param name="includeDebug">True to include debug data, false otherwise</param>
1155-
private bool ExtractFromResources(string outputDirectory, bool includeDebug)
1284+
public bool ExtractFromResources(string outputDirectory, bool includeDebug)
11561285
{
11571286
try
11581287
{

0 commit comments

Comments
 (0)