Skip to content

Commit ed90670

Browse files
committed
Mfuscator plugin: Search in parallel
1 parent 1a78124 commit ed90670

3 files changed

Lines changed: 46 additions & 13 deletions

File tree

Cpp2IL.Core/Api/PluginLogger.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ internal PluginLogger(Cpp2IlPlugin plugin)
1313
_name = $"Plugin: {plugin.Name}";
1414
}
1515

16+
public void VerboseNewlineIfDebug(string message, string source = "Program") => Logger.VerboseNewlineIfDebug($"{message}", _name);
17+
1618
public void VerboseNewline(string message, string source = "Program") => Logger.VerboseNewline($"{message}", _name);
1719

1820
public void Verbose(string message, string source = "Program") => Logger.Verbose($"{message}", _name);

Cpp2IL.Core/Logging/Logger.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,11 @@ public static void Error(string message, string source = "Program")
3838
{
3939
ErrorLog(message, source);
4040
}
41+
42+
public static void VerboseNewlineIfDebug(string message, string source = "Program")
43+
{
44+
#if DEBUG
45+
VerboseNewline(message, source);
46+
#endif
47+
}
4148
}

Cpp2IL.Plugin.Mfuscator/MfuscatorSupportPlugin.cs

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Runtime.InteropServices;
1+
using System.Collections.Concurrent;
2+
using System.Runtime.InteropServices;
23
using AssetRipper.Primitives;
34
using Cpp2IL.Core.Api;
45
using Cpp2IL.Core.Attributes;
@@ -335,8 +336,8 @@ private Dictionary<int, byte[]> DecryptEncryptedSections(byte[] encryptedMetadat
335336

336337
if (!decryptedSectionBytes.ContainsKey(StringLiteralsSectionIndex))
337338
throw new Exception("Failed to determine whether section keys are based on offsets or sizes");
338-
339-
Logger.VerboseNewline($"Section keys are based on {(usingOffsetNotSize ? "offsets" : "sizes")}, with addend 0x{sectionsXorKeyAddend:X2}");
339+
340+
Logger.VerboseNewlineIfDebug($"Section keys are based on {(usingOffsetNotSize ? "offsets" : "sizes")}, with addend 0x{sectionsXorKeyAddend:X2}");
340341

341342
//String literal data starts with 2 00 bytes, so we can get the direction from that
342343
var stringLiteralDataStart = sections[StringLiteralsDataSectionIndex].Start;
@@ -569,36 +570,60 @@ private byte[] RebuildMetadata(byte[] encryptedMetadata, List<(int Start, int En
569570
Logger.InfoNewline($"Mfuscator header decrypted successfully. Header length: {headerLength} bytes. String literals XOR key: 0x{stringLiteralsXorKey:X2}. String literals use {(stringLiteralsIsPlus ? "plus" : "minus")} rotation. Will rebuild as version {MetadataVersion} metadata with assemblies section at index {assembliesSectionIndex}.");
570571

571572
Logger.VerboseNewline("Decrypted header: " + string.Join("", decryptedHeader.Select(b => b.ToString("X2"))));
573+
574+
var lengthsToTry = Enumerable.Sequence(metadataLength, headerLength, -4).ToArray();
575+
byte[]? rebuiltMetadata = null;
576+
var winningIndex = long.MaxValue;
577+
var rebuiltMetadataLock = new object();
572578

573-
while (metadataLength > headerLength)
579+
// Preserve the original highest-length-first behavior while still stopping lower-priority work once a candidate is found.
580+
Parallel.ForEach(Partitioner.Create(lengthsToTry, loadBalance: true), (length, loopState, index) =>
574581
{
575-
Logger.VerboseNewline($"Trying metadata length 0x{metadataLength:X4}");
582+
if (index > loopState.LowestBreakIteration || index > Interlocked.Read(ref winningIndex))
583+
return;
584+
585+
Logger.VerboseNewlineIfDebug($"Trying metadata length 0x{length:X4}");
576586

577-
var paths = FindPathsThroughMetadata(headerWords, headerLength, metadataLength, out var bestDeadEnds, maxResults: 65536, debugBestN: 0, expectedSectionCount: expectedSectionCount, alignBefore: sectionAlignments, originalHeaderSize: originalHeaderSize);
587+
var paths = FindPathsThroughMetadata(headerWords, headerLength, length, out var bestDeadEnds, maxResults: 65536, debugBestN: 0, expectedSectionCount: expectedSectionCount, alignBefore: sectionAlignments, originalHeaderSize: originalHeaderSize);
578588

579589
if (paths.Count > 0)
580590
{
581591
//We'll likely get a couple dozen paths due to the fake offsets, which vary in supposed position and delta, but they should all agree on *actual* position in file.
582592
//We check that that's the case, and take those actual positions as gospel.
583593
//NB actually we don't check if that's the case because they sometimes differ in unimportant sections, too bad!
584-
Logger.VerboseNewline($"Found {paths.Count} possible section layouts with metadata length 0x{metadataLength:X4} bytes.");
594+
Logger.VerboseNewlineIfDebug($"Found {paths.Count} possible section layouts with metadata length 0x{length:X4} bytes.");
585595

586596
var actualRanges = paths.Select(path => path.Select(section => (section.ActualOffset, section.ActualOffset + section.Length)).ToArray()).ToArray();
587597

588598
var distinct = actualRanges.Distinct(new SectionRangeComparer()).ToArray();
589599

590-
Logger.VerboseNewline($"These collapse to {distinct.Length} distinct actual section layouts.");
600+
Logger.VerboseNewlineIfDebug($"These collapse to {distinct.Length} distinct actual section layouts.");
591601

592602
foreach (var acceptedLayout in distinct)
593603
{
594604

595-
Logger.VerboseNewline($"Trying section layout: " + string.Join(", ", acceptedLayout.Select(range => $"({range.Item1:X4}-{range.Item2:X4})")));
605+
Logger.VerboseNewlineIfDebug($"Trying section layout: " + string.Join(", ", acceptedLayout.Select(range => $"({range.Item1:X4}-{range.Item2:X4})")));
596606

597607
try
598608
{
599609
var ret = RebuildMetadata(originalBytes, acceptedLayout.ToList(), stringLiteralsXorKey, stringLiteralsIsPlus, offsetDelta: originalHeaderSize - headerLength, MetadataVersion, assembliesSectionIndex);
610+
var installedWinningResult = false;
611+
lock (rebuiltMetadataLock)
612+
{
613+
if (index < winningIndex)
614+
{
615+
winningIndex = index;
616+
rebuiltMetadata = ret;
617+
installedWinningResult = true;
618+
}
619+
}
620+
621+
if (!installedWinningResult)
622+
return;
623+
600624
Logger.InfoNewline("Returning decrypted metadata now...");
601-
return ret;
625+
loopState.Break();
626+
return;
602627
}
603628
catch (Exception)
604629
{
@@ -607,9 +632,8 @@ private byte[] RebuildMetadata(byte[] encryptedMetadata, List<(int Start, int En
607632
}
608633
}
609634

610-
metadataLength -= 4;
611-
}
635+
});
612636

613-
return null;
637+
return rebuiltMetadata;
614638
}
615639
}

0 commit comments

Comments
 (0)