@@ -295,138 +295,143 @@ private Dictionary<int, byte[]> DecryptEncryptedSections(byte[] encryptedMetadat
295295 var stringLiteralsStart = sections [ StringLiteralsSectionIndex ] . Start ;
296296 var stringLiteralsSize = sections [ StringLiteralsSectionIndex ] . End - sections [ StringLiteralsSectionIndex ] . Start ;
297297
298- var usingOffsetNotSize = false ;
299- byte sectionsXorKeyAddend = 0 ;
300-
301- foreach ( var testUsingOffset in stackalloc bool [ ] { true , false } )
298+ foreach ( var usingOffsetNotSize in stackalloc bool [ ] { true , false } )
302299 {
303- var stringLiteralsKeyComponent = testUsingOffset ? stringLiteralsStart : stringLiteralsSize ;
304- var testAddend = ( byte ) ( ( stringLiteralsIsPlus ? ( stringLiteralsXorKey - stringLiteralsKeyComponent ) : ( stringLiteralsXorKey + stringLiteralsKeyComponent ) ) & 0xFF ) ;
305-
306- //Now decrypt the string literals section
307- var decryptedLiterals = new byte [ stringLiteralsSize ] ;
308- CyclicXor (
309- encryptedMetadata . AsSpan ( sections [ StringLiteralsSectionIndex ] . Start , stringLiteralsSize ) ,
310- decryptedLiterals ,
311- testAddend ,
312- stringLiteralsIsPlus ,
313- stringLiteralsStart
314- ) ;
315-
316- if ( decryptedLiterals [ 0 ] == 0 && decryptedLiterals [ 1 ] == 0 )
300+ try
317301 {
318- usingOffsetNotSize = testUsingOffset ;
319- sectionsXorKeyAddend = testAddend ;
320- decryptedSectionBytes [ StringLiteralsSectionIndex ] = decryptedLiterals ;
321- break ;
322- }
323- }
324-
325- if ( ! decryptedSectionBytes . ContainsKey ( StringLiteralsSectionIndex ) )
326- throw new Exception ( "Failed to determine whether section keys are based on offsets or sizes" ) ;
327-
328- Logger . VerboseNewline ( $ "Section keys are based on { ( usingOffsetNotSize ? "offsets" : "sizes" ) } , with addend 0x{ sectionsXorKeyAddend : X2} ") ;
302+ byte sectionsXorKeyAddend = 0 ;
303+ var stringLiteralsKeyComponent = usingOffsetNotSize ? stringLiteralsStart : stringLiteralsSize ;
304+ var testAddend = ( byte ) ( ( stringLiteralsIsPlus ? ( stringLiteralsXorKey - stringLiteralsKeyComponent ) : ( stringLiteralsXorKey + stringLiteralsKeyComponent ) ) & 0xFF ) ;
329305
330- //String literal data starts with 2 00 bytes, so we can get the direction from that
331- var stringLiteralDataStart = sections [ StringLiteralsDataSectionIndex ] . Start ;
332- var stringLiteralDataSize = sections [ StringLiteralsDataSectionIndex ] . End - sections [ StringLiteralsDataSectionIndex ] . Start ;
333- var stringLiteralDataKeyComponent = usingOffsetNotSize ? stringLiteralDataStart : stringLiteralDataSize ;
334-
335- var firstByte = encryptedMetadata [ stringLiteralDataStart ] ;
336- var secondByte = encryptedMetadata [ stringLiteralDataStart + 1 ] ;
337- var stringLiteralDataIsPlus = ( ( firstByte + 1 ) & 0xFF ) == secondByte ;
338- var stringLiteralDataIsMinus = ( ( firstByte - 1 ) & 0xFF ) == secondByte ;
339- if ( ! stringLiteralDataIsPlus && ! stringLiteralDataIsMinus )
340- throw new Exception ( "Failed to determine string literal data XOR direction" ) ;
341-
342- //And decrypt it
343- var decryptedLiteralData = decryptedSectionBytes [ StringLiteralsDataSectionIndex ] = new byte [ stringLiteralDataSize ] ;
344- CyclicXor (
345- encryptedMetadata . AsSpan ( stringLiteralDataStart , stringLiteralDataSize ) ,
346- decryptedLiteralData ,
347- sectionsXorKeyAddend ,
348- stringLiteralDataIsPlus ,
349- stringLiteralDataKeyComponent
350- ) ;
351-
352- //Strings are a bit harder, we need to look for the null terminators in the first 32 bytes
353- var stringsSectionStart = sections [ StringsSectionIndex ] . Start ;
354- var stringsSectionSize = sections [ StringsSectionIndex ] . End - sections [ StringsSectionIndex ] . Start ;
355- var stringsSectionKeyComponent = usingOffsetNotSize ? stringsSectionStart : stringsSectionSize ;
356- var stringsFirstXorByteOffset = 0 ;
357- var stringsIsPlus = false ;
358- var foundZeroBytes = 0 ;
359- foreach ( var testIsPlus in new bool [ ] { true , false } )
360- {
361- stringsIsPlus = testIsPlus ;
362- for ( var i = 0 ; i < 32 ; i ++ )
363- {
364- var assumedXorKey = ( byte ) ( ( testIsPlus
365- ? ( i + stringsSectionKeyComponent + sectionsXorKeyAddend )
366- : ( i - stringsSectionKeyComponent - sectionsXorKeyAddend ) ) & 0xFF ) ;
367- var xorByte = ( byte ) ( encryptedMetadata [ stringsSectionStart + i ] ^ assumedXorKey ) ;
368- if ( xorByte == 0 )
306+ //Now decrypt the string literals section
307+ var decryptedLiterals = new byte [ stringLiteralsSize ] ;
308+ CyclicXor (
309+ encryptedMetadata . AsSpan ( sections [ StringLiteralsSectionIndex ] . Start , stringLiteralsSize ) ,
310+ decryptedLiterals ,
311+ testAddend ,
312+ stringLiteralsIsPlus ,
313+ stringLiteralsKeyComponent
314+ ) ;
315+
316+ if ( decryptedLiterals [ 0 ] == 0 && decryptedLiterals [ 1 ] == 0 )
369317 {
370- foundZeroBytes ++ ;
371- if ( foundZeroBytes == 1 )
372- stringsFirstXorByteOffset = i ;
373- else if ( foundZeroBytes == 2 )
374- break ; //we've found the first two null terminators, which is enough to be confident we've got the right key direction
318+ sectionsXorKeyAddend = testAddend ;
319+ decryptedSectionBytes [ StringLiteralsSectionIndex ] = decryptedLiterals ;
375320 }
376- }
377- }
378-
379- if ( foundZeroBytes != 2 )
380- throw new Exception ( "Failed to determine strings section XOR direction" ) ;
381-
382- //sanity check
383- var stringsXorByte = ( byte ) ( ( stringsIsPlus
384- ? ( stringsFirstXorByteOffset + stringsSectionKeyComponent + sectionsXorKeyAddend )
385- : ( stringsFirstXorByteOffset - stringsSectionKeyComponent - sectionsXorKeyAddend ) ) & 0xFF ) ;
386-
387- if ( encryptedMetadata [ stringsSectionStart + stringsFirstXorByteOffset ] != stringsXorByte )
388- throw new Exception ( "Strings section XOR key doesn't seem to be correct" ) ;
389-
390- //ok now decrypt strings
391- var decryptedStrings = decryptedSectionBytes [ StringsSectionIndex ] = new byte [ stringsSectionSize ] ;
392- CyclicXor (
393- encryptedMetadata . AsSpan ( stringsSectionStart , stringsSectionSize ) ,
394- decryptedStrings ,
395- sectionsXorKeyAddend ,
396- stringsIsPlus ,
397- stringsSectionKeyComponent
398- ) ;
399-
400- //for the rest of the sections we can just check the 3rd byte is 0 to determine the direction
401- var remainingEncryptedSections = new int [ ] { PropertiesSectionIndex , MethodsSectionIndex , FieldsSectionIndex , assembliesSectionIndex } ;
402- foreach ( var sectionIndex in remainingEncryptedSections )
403- {
404- var sectionStart = sections [ sectionIndex ] . Start ;
405- var sectionSize = sections [ sectionIndex ] . End - sections [ sectionIndex ] . Start ;
406- var sectionKeyComponent = usingOffsetNotSize ? sectionStart : sectionSize ;
321+
322+ if ( ! decryptedSectionBytes . ContainsKey ( StringLiteralsSectionIndex ) )
323+ throw new Exception ( "Failed to determine whether section keys are based on offsets or sizes" ) ;
407324
408- var decryptedSection = new byte [ sectionSize ] ;
409- foreach ( var testIsPlus in new bool [ ] { true , false } )
410- {
325+ Logger . VerboseNewline ( $ "Section keys are based on { ( usingOffsetNotSize ? "offsets" : "sizes" ) } , with addend 0x{ sectionsXorKeyAddend : X2} ") ;
326+
327+ //String literal data starts with 2 00 bytes, so we can get the direction from that
328+ var stringLiteralDataStart = sections [ StringLiteralsDataSectionIndex ] . Start ;
329+ var stringLiteralDataSize = sections [ StringLiteralsDataSectionIndex ] . End - sections [ StringLiteralsDataSectionIndex ] . Start ;
330+ var stringLiteralDataKeyComponent = usingOffsetNotSize ? stringLiteralDataStart : stringLiteralDataSize ;
331+
332+ var firstByte = encryptedMetadata [ stringLiteralDataStart ] ;
333+ var secondByte = encryptedMetadata [ stringLiteralDataStart + 1 ] ;
334+ var stringLiteralDataIsPlus = ( ( firstByte + 1 ) & 0xFF ) == secondByte ;
335+ var stringLiteralDataIsMinus = ( ( firstByte - 1 ) & 0xFF ) == secondByte ;
336+ if ( ! stringLiteralDataIsPlus && ! stringLiteralDataIsMinus )
337+ throw new Exception ( "Failed to determine string literal data XOR direction" ) ;
338+
339+ //And decrypt it
340+ var decryptedLiteralData = decryptedSectionBytes [ StringLiteralsDataSectionIndex ] = new byte [ stringLiteralDataSize ] ;
411341 CyclicXor (
412- encryptedMetadata . AsSpan ( sectionStart , sectionSize ) ,
413- decryptedSection ,
342+ encryptedMetadata . AsSpan ( stringLiteralDataStart , stringLiteralDataSize ) ,
343+ decryptedLiteralData ,
414344 sectionsXorKeyAddend ,
415- testIsPlus ,
416- sectionKeyComponent
345+ stringLiteralDataIsPlus ,
346+ stringLiteralDataKeyComponent
417347 ) ;
418- if ( decryptedSection [ 3 ] == 0 )
348+
349+ //Strings are a bit harder, we need to look for the null terminators in the first 32 bytes
350+ var stringsSectionStart = sections [ StringsSectionIndex ] . Start ;
351+ var stringsSectionSize = sections [ StringsSectionIndex ] . End - sections [ StringsSectionIndex ] . Start ;
352+ var stringsSectionKeyComponent = usingOffsetNotSize ? stringsSectionStart : stringsSectionSize ;
353+ var stringsFirstXorByteOffset = 0 ;
354+ var stringsIsPlus = false ;
355+ var foundZeroBytes = 0 ;
356+ foreach ( var testIsPlus in new bool [ ] { true , false } )
419357 {
420- decryptedSectionBytes [ sectionIndex ] = decryptedSection ;
421- break ;
358+ stringsIsPlus = testIsPlus ;
359+ for ( var i = 0 ; i < 32 ; i ++ )
360+ {
361+ var assumedXorKey = ( byte ) ( ( testIsPlus
362+ ? ( i + stringsSectionKeyComponent + sectionsXorKeyAddend )
363+ : ( i - stringsSectionKeyComponent - sectionsXorKeyAddend ) ) & 0xFF ) ;
364+ var xorByte = ( byte ) ( encryptedMetadata [ stringsSectionStart + i ] ^ assumedXorKey ) ;
365+ if ( xorByte == 0 )
366+ {
367+ foundZeroBytes ++ ;
368+ if ( foundZeroBytes == 1 )
369+ stringsFirstXorByteOffset = i ;
370+ else if ( foundZeroBytes == 2 )
371+ break ; //we've found the first two null terminators, which is enough to be confident we've got the right key direction
372+ }
373+ }
374+ }
375+
376+ if ( foundZeroBytes != 2 )
377+ throw new Exception ( "Failed to determine strings section XOR direction" ) ;
378+
379+ //sanity check
380+ var stringsXorByte = ( byte ) ( ( stringsIsPlus
381+ ? ( stringsFirstXorByteOffset + stringsSectionKeyComponent + sectionsXorKeyAddend )
382+ : ( stringsFirstXorByteOffset - stringsSectionKeyComponent - sectionsXorKeyAddend ) ) & 0xFF ) ;
383+
384+ if ( encryptedMetadata [ stringsSectionStart + stringsFirstXorByteOffset ] != stringsXorByte )
385+ throw new Exception ( "Strings section XOR key doesn't seem to be correct" ) ;
386+
387+ //ok now decrypt strings
388+ var decryptedStrings = decryptedSectionBytes [ StringsSectionIndex ] = new byte [ stringsSectionSize ] ;
389+ CyclicXor (
390+ encryptedMetadata . AsSpan ( stringsSectionStart , stringsSectionSize ) ,
391+ decryptedStrings ,
392+ sectionsXorKeyAddend ,
393+ stringsIsPlus ,
394+ stringsSectionKeyComponent
395+ ) ;
396+
397+ //for the rest of the sections we can just check the 3rd byte is 0 to determine the direction
398+ var remainingEncryptedSections = new int [ ] { PropertiesSectionIndex , MethodsSectionIndex , FieldsSectionIndex , assembliesSectionIndex } ;
399+ foreach ( var sectionIndex in remainingEncryptedSections )
400+ {
401+ var sectionStart = sections [ sectionIndex ] . Start ;
402+ var sectionSize = sections [ sectionIndex ] . End - sections [ sectionIndex ] . Start ;
403+ var sectionKeyComponent = usingOffsetNotSize ? sectionStart : sectionSize ;
404+
405+ var decryptedSection = new byte [ sectionSize ] ;
406+ foreach ( var testIsPlus in new bool [ ] { true , false } )
407+ {
408+ CyclicXor (
409+ encryptedMetadata . AsSpan ( sectionStart , sectionSize ) ,
410+ decryptedSection ,
411+ sectionsXorKeyAddend ,
412+ testIsPlus ,
413+ sectionKeyComponent
414+ ) ;
415+ if ( decryptedSection [ 3 ] == 0 )
416+ {
417+ decryptedSectionBytes [ sectionIndex ] = decryptedSection ;
418+ break ;
419+ }
420+ }
421+
422+ if ( ! decryptedSectionBytes . ContainsKey ( sectionIndex ) )
423+ throw new Exception ( $ "Failed to determine XOR direction for section at index { sectionIndex } ") ;
422424 }
425+
426+ return decryptedSectionBytes ;
427+ }
428+ catch ( Exception ex )
429+ {
430+ continue ;
423431 }
424-
425- if ( ! decryptedSectionBytes . ContainsKey ( sectionIndex ) )
426- throw new Exception ( $ "Failed to determine XOR direction for section at index { sectionIndex } ") ;
427432 }
428-
429- return decryptedSectionBytes ;
433+
434+ throw new Exception ( "Failed to decrypt sections with either offset-based or size-based keys" ) ;
430435 }
431436
432437 private byte [ ] RebuildMetadata ( byte [ ] encryptedMetadata , List < ( int Start , int End ) > sections , byte stringLiteralsXorKey , bool stringLiteralsIsPlus , int offsetDelta , byte metadataVersion , int assembliesSectionIndex )
@@ -528,6 +533,8 @@ private byte[] RebuildMetadata(byte[] encryptedMetadata, List<(int Start, int En
528533 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 } .") ;
529534
530535 Logger . VerboseNewline ( "Decrypted header: " + string . Join ( "" , decryptedHeader . Select ( b => b . ToString ( "X2" ) ) ) ) ;
536+
537+ metadataLength = 0x2356D0C ;
531538
532539 while ( metadataLength > headerLength )
533540 {
@@ -567,6 +574,7 @@ private byte[] RebuildMetadata(byte[] encryptedMetadata, List<(int Start, int En
567574 }
568575
569576 metadataLength -= 4 ;
577+ break ;
570578 }
571579
572580 return null ;
0 commit comments