Skip to content

Commit 1a78124

Browse files
committed
Mfuscator plugin: fix some bugs
1 parent 1190342 commit 1a78124

1 file changed

Lines changed: 41 additions & 4 deletions

File tree

Cpp2IL.Plugin.Mfuscator/MfuscatorSupportPlugin.cs

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,17 @@ public override void OnLoad()
5151
{
5252
RegisterMetadataFixupFunc(TryFixupMfuscatorMetadata);
5353
}
54+
55+
private static void CyclicXorHeader(ReadOnlySpan<byte> data, Span<byte> output, byte xorKey, bool isPlus, int offset = 0)
56+
{
57+
for (var i = 0; i < data.Length; i++)
58+
{
59+
var keyByte = (byte) ((isPlus
60+
? (xorKey + offset + i)
61+
: (xorKey - (offset + i))) & 0xFF);
62+
output[i] = (byte) (data[i] ^ keyByte);
63+
}
64+
}
5465

5566
private static void CyclicXor(ReadOnlySpan<byte> data, Span<byte> output, byte xorKey, bool isPlus, int offset = 0)
5667
{
@@ -90,9 +101,11 @@ private static byte DeriveXorKey(Span<byte> encryptedHeader, out bool isPlus)
90101
throw new Exception("Failed to derive XOR key");
91102
}
92103

93-
private static byte[] DecryptHeader(Span<byte> encryptedHeader, out byte stringLiteralsXorKey, out bool stringLiteralsIsPlus)
104+
private byte[] DecryptHeader(Span<byte> encryptedHeader, out byte stringLiteralsXorKey, out bool stringLiteralsIsPlus)
94105
{
95106
var xorKey = DeriveXorKey(encryptedHeader, out var isPlus);
107+
108+
Logger.VerboseNewline($"Derived header XOR key: 0x{xorKey:X2}. Header fields use {(isPlus ? "plus" : "minus")} rotation.");
96109

97110
//Header size isn't actually known, we just pass the first 480 bytes in
98111
//So let's work it out
@@ -102,7 +115,7 @@ private static byte[] DecryptHeader(Span<byte> encryptedHeader, out byte stringL
102115
while (headerSize < MaxHeaderSize)
103116
{
104117
var encryptedWord = encryptedHeader[headerSize..(headerSize + 4)];
105-
CyclicXor(encryptedWord, decryptedWord, xorKey, isPlus, headerSize);
118+
CyclicXorHeader(encryptedWord, decryptedWord, xorKey, isPlus, headerSize);
106119

107120
headerSize += 4;
108121

@@ -138,9 +151,10 @@ private static byte[] DecryptHeader(Span<byte> encryptedHeader, out byte stringL
138151
headerSize -= 4; //the last 4 bytes we read were actually the start of the string literal data, so remove them from the header size
139152

140153
var decryptedHeader = new byte[headerSize];
141-
CyclicXor(encryptedHeader[..headerSize], decryptedHeader, xorKey, isPlus);
154+
CyclicXorHeader(encryptedHeader[..headerSize], decryptedHeader, xorKey, isPlus);
142155
stringLiteralsXorKey = encryptedWord[0];
143-
stringLiteralsIsPlus = isPlus;
156+
var nextEncryptedWord = encryptedHeader[(headerSize + 4)..(headerSize + 8)];
157+
stringLiteralsIsPlus = nextEncryptedWord[0] == encryptedWord[0] + 4;
144158
return decryptedHeader;
145159
}
146160
}
@@ -336,6 +350,25 @@ private Dictionary<int, byte[]> DecryptEncryptedSections(byte[] encryptedMetadat
336350
if (!stringLiteralDataIsPlus && !stringLiteralDataIsMinus)
337351
throw new Exception("Failed to determine string literal data XOR direction");
338352

353+
if (stringLiteralDataIsPlus)
354+
{
355+
//check for underflow resulting in wrong initial key
356+
var encryptedFirstWord = encryptedMetadata.AsSpan(stringLiteralDataStart, 4);
357+
var decryptedFirstWord = new byte[4];
358+
CyclicXor(
359+
encryptedFirstWord,
360+
decryptedFirstWord,
361+
sectionsXorKeyAddend,
362+
true,
363+
stringLiteralDataKeyComponent
364+
);
365+
if (decryptedFirstWord[0] != 0)
366+
{
367+
stringLiteralDataIsPlus = false;
368+
sectionsXorKeyAddend = (byte)((0 - stringLiteralsXorKey - stringLiteralsKeyComponent) & 0xFF);
369+
}
370+
}
371+
339372
//And decrypt it
340373
var decryptedLiteralData = decryptedSectionBytes[StringLiteralsDataSectionIndex] = new byte[stringLiteralDataSize];
341374
CyclicXor(
@@ -355,6 +388,7 @@ private Dictionary<int, byte[]> DecryptEncryptedSections(byte[] encryptedMetadat
355388
var foundZeroBytes = 0;
356389
foreach (var testIsPlus in new bool[] { true, false })
357390
{
391+
foundZeroBytes = 0;
358392
stringsIsPlus = testIsPlus;
359393
for (var i = 0; i < 32; i++)
360394
{
@@ -371,6 +405,9 @@ private Dictionary<int, byte[]> DecryptEncryptedSections(byte[] encryptedMetadat
371405
break; //we've found the first two null terminators, which is enough to be confident we've got the right key direction
372406
}
373407
}
408+
409+
if (foundZeroBytes == 2)
410+
break;
374411
}
375412

376413
if (foundZeroBytes != 2)

0 commit comments

Comments
 (0)