Skip to content

Commit 6d03925

Browse files
committed
.NET Reactor: Unify FindStartEnd and GetLocal methods in EncryptedResource
1 parent 1934112 commit 6d03925

1 file changed

Lines changed: 64 additions & 170 deletions

File tree

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)