Skip to content

Commit 88b7662

Browse files
authored
Merge pull request #26 from GDATAAdvancedAnalytics/dr-decrypt
Fix .NET Reactor method decryption
2 parents 984bf3c + 1723a40 commit 88b7662

7 files changed

Lines changed: 152 additions & 203 deletions

File tree

de4dot.blocks/cflow/InstructionEmulator.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -532,9 +532,8 @@ void Emulate_Sizeof(Instruction instr){
532532
void Emulate_Newarr(Instruction instr)
533533
{
534534
var val = valueStack.Pop();
535-
if (val.IsInt32())
535+
if (val.IsInt32() && val is Int32Value { Value: < 500000 } arrSize)
536536
{
537-
Int32Value arrSize = (Int32Value)val;
538537
List<Value> arr = new List<Value>(arrSize.Value);
539538
for (int i = 0; i < arrSize.Value; i++) {
540539
arr.Add(new UnknownValue());

de4dot.code/deobfuscators/dotNET_Reactor/v4/Deobfuscator.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,8 @@ public override IDeobfuscator ModuleReloaded(ModuleDefMD module) {
446446
newOne.peImage = new MyPEImage(fileData);
447447
newOne.methodsDecrypter = new MethodsDecrypter(module, methodsDecrypter);
448448
newOne.proxyCallFixer = new ProxyCallFixer(module, proxyCallFixer);
449-
newOne.devirtualizer = new Devirtualizer(module, devirtualizer);
449+
newOne.devirtualizer = new Devirtualizer(DeobfuscatedFile, module);
450+
newOne.devirtualizer.Find();
450451
newOne.stringDecrypter = new StringDecrypter(module, stringDecrypter);
451452
newOne.booleanDecrypter = new BooleanDecrypter(module, booleanDecrypter);
452453
newOne.assemblyResolver = new AssemblyResolver(module, assemblyResolver);
@@ -462,7 +463,7 @@ void FreePEImage() {
462463
}
463464

464465
void RemoveMethods() {
465-
if (methodsDecrypter.Method != null) {
466+
if (methodsDecrypter.Method != null && options.DecryptMethods) {
466467
AddEntryPointCallToBeRemoved(methodsDecrypter.Method);
467468
}
468469

@@ -501,7 +502,7 @@ void RemoveMethods() {
501502
if (antiDebug != null)
502503
AddCallToBeRemoved(method, antiDebug);
503504

504-
if (methodsDecrypter.Method != null)
505+
if (methodsDecrypter.Method != null && options.DecryptMethods)
505506
AddCallToBeRemoved(method, methodsDecrypter.Method);
506507

507508
// AntiILDASM

de4dot.code/deobfuscators/dotNET_Reactor/v4/EncryptedResource.cs

Lines changed: 64 additions & 170 deletions
Original file line numberDiff line numberDiff line change
@@ -237,13 +237,69 @@ public byte[] Encrypt(byte[] data) {
237237
}
238238
}
239239

240-
class DecrypterV2 : IDecrypter {
240+
private abstract class EmulatingDecrypterBase
241+
{
242+
protected MethodDef method;
243+
protected List<Instruction> instructions;
244+
protected List<Local> locals;
245+
protected readonly InstructionEmulator instrEmulator = new();
246+
protected Local emuLocal;
247+
248+
/**
249+
* Locates the instructions that are responsible for producing the key stream for decrypting the resource.
250+
*/
251+
protected bool FindStartEnd(IList<Instruction> instrs, out int startIndex, out int endIndex, out Local tmpLocal) {
252+
for (int i = 0; i + 8 < instrs.Count; i++) {
253+
if (instrs[i].OpCode.Code != Code.Conv_R_Un)
254+
continue;
255+
if (instrs[i + 1].OpCode.Code != Code.Conv_R8)
256+
continue;
257+
if (instrs[i + 2].OpCode.Code != Code.Conv_U4)
258+
continue;
259+
if (instrs[i + 3].OpCode.Code != Code.Add)
260+
continue;
261+
int newEndIndex = i + 3;
262+
int newStartIndex = -1;
263+
for (int j = newEndIndex; j >= 0; j--) {
264+
// Search upwards for array access or br.
265+
if (instrs[j].OpCode.Code != Code.Ldelem_U1 && (!instrs[j].IsBr() || instrs[j - 1].OpCode.Code == Code.Bne_Un_S))
266+
continue;
267+
268+
// Go down to next local load, where the actual decryption should begin.
269+
for (int k = j + 1; k < newEndIndex; k++) {
270+
if (instrs[k].IsLdloc()) {
271+
newStartIndex = k;
272+
break;
273+
}
274+
}
275+
break;
276+
}
277+
endIndex = newEndIndex;
278+
startIndex = newStartIndex;
279+
tmpLocal = CheckLocal(instrs[startIndex], true);
280+
return true;
281+
}
282+
endIndex = 0;
283+
startIndex = 0;
284+
tmpLocal = null;
285+
return false;
286+
}
287+
288+
/**
289+
* Gets the Local referenced by the instruction if it's either ldloc or stloc (determined by isLdloc).
290+
*/
291+
protected Local CheckLocal(Instruction instr, bool isLdloc) {
292+
if (isLdloc && !instr.IsLdloc())
293+
return null;
294+
if (!isLdloc && !instr.IsStloc())
295+
return null;
296+
297+
return instr.GetLocal(locals);
298+
}
299+
}
300+
301+
class DecrypterV2 : EmulatingDecrypterBase, IDecrypter {
241302
readonly byte[] key, iv;
242-
MethodDef method;
243-
List<Instruction> instructions;
244-
List<Local> locals;
245-
readonly InstructionEmulator instrEmulator = new InstructionEmulator();
246-
Local emuLocal;
247303
Parameter emuArg;
248304
MethodDef emuMethod;
249305
bool isNewDecrypter;
@@ -310,49 +366,6 @@ bool Find(IList<Instruction> instrs, out int startIndex, out int endIndex, out L
310366
return true;
311367
}
312368

313-
bool FindStartEnd(IList<Instruction> instrs, out int startIndex, out int endIndex, out Local tmpLocal) {
314-
for (int i = 0; i + 8 < instrs.Count; i++) {
315-
if (instrs[i].OpCode.Code != Code.Conv_R_Un)
316-
continue;
317-
if (instrs[i + 1].OpCode.Code != Code.Conv_R8)
318-
continue;
319-
if (instrs[i + 2].OpCode.Code != Code.Conv_U4)
320-
continue;
321-
if (instrs[i + 3].OpCode.Code != Code.Add)
322-
continue;
323-
int newEndIndex = i + 3;
324-
int newStartIndex = -1;
325-
for (int x = newEndIndex; x > 0; x--)
326-
if (instrs[x].OpCode.FlowControl != FlowControl.Next) {
327-
newStartIndex = x + 1;
328-
break;
329-
}
330-
if (newStartIndex < 0)
331-
continue;
332-
333-
var checkLocs = new List<Local>();
334-
int ckStartIndex = -1;
335-
for (int y = newEndIndex; y >= newStartIndex; y--) {
336-
var loc = CheckLocal(instrs[y], true);
337-
if (loc == null)
338-
continue;
339-
if (!checkLocs.Contains(loc))
340-
checkLocs.Add(loc);
341-
if (checkLocs.Count == 3)
342-
break;
343-
ckStartIndex = y;
344-
}
345-
endIndex = newEndIndex;
346-
startIndex = Math.Max(ckStartIndex, newStartIndex);
347-
tmpLocal = CheckLocal(instrs[startIndex], true);
348-
return true;
349-
}
350-
endIndex = 0;
351-
startIndex = 0;
352-
tmpLocal = null;
353-
return false;
354-
}
355-
356369
bool FindStartEnd2(ref IList<Instruction> instrs, out int startIndex, out int endIndex, out Local tmpLocal, out Parameter tmpArg, ref MethodDef methodDef, ref List<Local> locals) {
357370
foreach (var instr in instrs) {
358371
if (instr.OpCode == OpCodes.Call) {
@@ -436,15 +449,6 @@ bool FindEnd(IList<Instruction> instrs, int startIndex, out int endIndex) {
436449
return false;
437450
}
438451

439-
Local CheckLocal(Instruction instr, bool isLdloc) {
440-
if (isLdloc && !instr.IsLdloc())
441-
return null;
442-
else if (!isLdloc && !instr.IsStloc())
443-
return null;
444-
445-
return instr.GetLocal(locals);
446-
}
447-
448452
public byte[] Decrypt(EmbeddedResource resource) {
449453
var encrypted = resource.CreateReader().ToArray();
450454
var decrypted = new byte[encrypted.Length];
@@ -517,13 +521,7 @@ public byte[] Encrypt(byte[] data) {
517521
}
518522
}
519523

520-
class DecrypterV3 : IDecrypter {
521-
readonly MethodDef method;
522-
List<Instruction> instructions;
523-
readonly List<Local> locals;
524-
readonly InstructionEmulator instrEmulator = new InstructionEmulator();
525-
Local emuLocal;
526-
524+
class DecrypterV3 : EmulatingDecrypterBase, IDecrypter {
527525
public DnrDecrypterType DecrypterType => DnrDecrypterType.V3;
528526

529527
public DecrypterV3(MethodDef method) {
@@ -578,48 +576,6 @@ bool Find(IList<Instruction> instrs, out int startIndex, out int endIndex, out L
578576
return true;
579577
}
580578

581-
/**
582-
* Locates the instructions that are responsible for producing the key stream for decrypting the resource.
583-
*/
584-
bool FindStartEnd(IList<Instruction> instrs, out int startIndex, out int endIndex, out Local tmpLocal) {
585-
for (int i = 0; i + 8 < instrs.Count; i++) {
586-
if (instrs[i].OpCode.Code != Code.Conv_R_Un)
587-
continue;
588-
if (instrs[i + 1].OpCode.Code != Code.Conv_R8)
589-
continue;
590-
if (instrs[i + 2].OpCode.Code != Code.Conv_U4)
591-
continue;
592-
if (instrs[i + 3].OpCode.Code != Code.Add)
593-
continue;
594-
int newEndIndex = i + 3;
595-
596-
int newStartIndex = -1;
597-
for (int j = newEndIndex; j >= 0; j--) {
598-
// Search upwards for array access.
599-
if (instrs[j].OpCode.Code != Code.Ldelem_U1)
600-
continue;
601-
602-
// Go down to next local load, where actual decryption should begin.
603-
for (int k = j + 1; k < newEndIndex; k++) {
604-
if (instrs[k].IsLdloc()) {
605-
newStartIndex = k;
606-
break;
607-
}
608-
}
609-
break;
610-
}
611-
612-
endIndex = newEndIndex;
613-
startIndex = newStartIndex;
614-
tmpLocal = CheckLocal(instrs[startIndex], true);
615-
return true;
616-
}
617-
endIndex = 0;
618-
startIndex = 0;
619-
tmpLocal = null;
620-
return false;
621-
}
622-
623579
bool FindStart(IList<Instruction> instrs, out int startIndex, out Local tmpLocal) {
624580
for (int i = 0; i + 8 < instrs.Count; i++) {
625581
if (instrs[i].OpCode.Code != Code.Conv_U)
@@ -675,18 +631,6 @@ bool FindEnd(IList<Instruction> instrs, int startIndex, out int endIndex) {
675631
return false;
676632
}
677633

678-
/**
679-
* Gets the Local referenced by the instruction if it's either ldloc or stloc (determined by isLdloc).
680-
*/
681-
Local CheckLocal(Instruction instr, bool isLdloc) {
682-
if (isLdloc && !instr.IsLdloc())
683-
return null;
684-
if (!isLdloc && !instr.IsStloc())
685-
return null;
686-
687-
return instr.GetLocal(locals);
688-
}
689-
690634
public byte[] Decrypt(EmbeddedResource resource) {
691635
var encrypted = resource.CreateReader().ToArray();
692636
var decrypted = new byte[encrypted.Length];
@@ -766,14 +710,10 @@ public byte[] Encrypt(byte[] data) {
766710
}
767711
}
768712

769-
class DecrypterV4 : IDecrypter {
713+
class DecrypterV4 : EmulatingDecrypterBase, IDecrypter {
770714
readonly byte[] key, iv;
771715
MethodDef decryptMethod;
772716
MethodDef emuMethod;
773-
List<Instruction> instructions;
774-
List<Local> locals;
775-
readonly InstructionEmulator instrEmulator = new InstructionEmulator();
776-
Local emuLocal;
777717

778718
public DnrDecrypterType DecrypterType => DnrDecrypterType.V4;
779719

@@ -908,43 +848,6 @@ bool Find(IList<Instruction> instrs, out int startIndex, out int endIndex, out L
908848
return true;
909849
}
910850

911-
bool FindStartEnd(IList<Instruction> instrs, out int startIndex, out int endIndex, out Local tmpLocal) {
912-
for (int i = 0; i + 8 < instrs.Count; i++) {
913-
if (instrs[i].OpCode.Code != Code.Conv_R_Un)
914-
continue;
915-
if (instrs[i + 1].OpCode.Code != Code.Conv_R8)
916-
continue;
917-
if (instrs[i + 2].OpCode.Code != Code.Conv_U4)
918-
continue;
919-
if (instrs[i + 3].OpCode.Code != Code.Add)
920-
continue;
921-
int newEndIndex = i + 3;
922-
int newStartIndex = -1;
923-
for (int j = newEndIndex; j >= 0; j--) {
924-
// Search upwards for array access.
925-
if (instrs[j].OpCode.Code != Code.Ldelem_U1)
926-
continue;
927-
928-
// Go down to next local load, where actual decryption should begin.
929-
for (int k = j + 1; k < newEndIndex; k++) {
930-
if (instrs[k].IsLdloc()) {
931-
newStartIndex = k;
932-
break;
933-
}
934-
}
935-
break;
936-
}
937-
endIndex = newEndIndex;
938-
startIndex = newStartIndex;
939-
tmpLocal = CheckLocal(instrs[startIndex], true);
940-
return true;
941-
}
942-
endIndex = 0;
943-
startIndex = 0;
944-
tmpLocal = null;
945-
return false;
946-
}
947-
948851
bool FindStart(IList<Instruction> instrs, out int startIndex, out Local tmpLocal) {
949852
for (int i = 0; i + 8 < instrs.Count; i++) {
950853
if (instrs[i].OpCode.Code != Code.Conv_U)
@@ -1000,15 +903,6 @@ bool FindEnd(IList<Instruction> instrs, int startIndex, out int endIndex) {
1000903
return false;
1001904
}
1002905

1003-
Local CheckLocal(Instruction instr, bool isLdloc) {
1004-
if (isLdloc && !instr.IsLdloc())
1005-
return null;
1006-
else if (!isLdloc && !instr.IsStloc())
1007-
return null;
1008-
1009-
return instr.GetLocal(locals);
1010-
}
1011-
1012906
public byte[] Decrypt(EmbeddedResource resource) {
1013907
var encrypted = resource.CreateReader().ToArray();
1014908
var decrypted = new byte[encrypted.Length];

0 commit comments

Comments
 (0)