@@ -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