diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj index 7d714538..3fdfe8bb 100644 --- a/de4dot.code/de4dot.code.csproj +++ b/de4dot.code/de4dot.code.csproj @@ -69,6 +69,7 @@ + diff --git a/de4dot.code/deobfuscators/dotNET_Reactor/ArrayFinder.cs b/de4dot.code/deobfuscators/dotNET_Reactor/ArrayFinder.cs new file mode 100644 index 00000000..68e6ae49 --- /dev/null +++ b/de4dot.code/deobfuscators/dotNET_Reactor/ArrayFinder.cs @@ -0,0 +1,146 @@ +/* + Copyright (C) 2011 de4dot@gmail.com + + This file is part of de4dot. + + de4dot is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + de4dot is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with de4dot. If not, see . +*/ + +using System.Collections.Generic; +using Mono.Cecil; +using Mono.Cecil.Cil; +using de4dot.blocks; +using de4dot.blocks.cflow; + +namespace de4dot.deobfuscators.dotNET_Reactor { + class ArrayFinder { + List arrays = new List(); + + public ArrayFinder(MethodDefinition method) { + init(method); + } + + void init(MethodDefinition method) { + if (method.Body == null) + return; + + foreach (var instr in method.Body.Instructions) { + if (instr.OpCode.Code != Code.Ldtoken) + continue; + var field = instr.Operand as FieldDefinition; + if (field == null) + continue; + arrays.Add(field.InitialValue); + } + + var instructions = method.Body.Instructions; + for (int i = 1; i < instructions.Count; i++) { + var instr = instructions[i]; + if (instr.OpCode.Code != Code.Newarr) + continue; + var ldci4 = instructions[i - 1]; + if (!DotNetUtils.isLdcI4(ldci4)) + continue; + int arraySize = DotNetUtils.getLdcI4Value(ldci4); + var ary = getInitializedArray(arraySize, method, ref i); + if (ary != null) + arrays.Add(ary); + } + } + + public bool exists(byte[] array) { + foreach (var ary in arrays) { + if (isEqual(ary, array)) + return true; + } + return false; + } + + static bool isEqual(byte[] ary1, byte[] ary2) { + if (ary1.Length != ary2.Length) + return false; + for (int i = 0; i < ary1.Length; i++) { + if (ary1[i] != ary2[i]) + return false; + } + return true; + } + + public static byte[] getInitializedArray(MethodDefinition method, int arraySize) { + int newarrIndex = findNewarr(method, arraySize); + if (newarrIndex < 0) + return null; + return getInitializedArray(arraySize, method, ref newarrIndex); + } + + public static byte[] getInitializedArray(int arraySize, MethodDefinition method, ref int newarrIndex) { + var resultValueArray = new Value[arraySize]; + + var emulator = new InstructionEmulator(method.HasThis, false, method.Parameters, method.Body.Variables); + var theArray = new UnknownValue(); + emulator.push(theArray); + + var instructions = method.Body.Instructions; + int i; + for (i = newarrIndex + 1; i < instructions.Count; i++) { + var instr = instructions[i]; + if (instr.OpCode.FlowControl != FlowControl.Next) + break; + if (instr.OpCode.Code == Code.Newarr) + break; + + if (instr.OpCode.Code == Code.Stelem_I1) { + var value = emulator.pop(); + var index = emulator.pop() as Int32Value; + var array = emulator.pop(); + if (ReferenceEquals(array, theArray) && index != null && index.allBitsValid()) { + if (0 <= index.value && index.value < resultValueArray.Length) + resultValueArray[index.value] = value; + } + } + else + emulator.emulate(instr); + } + newarrIndex = i; + + byte[] resultArray = new byte[resultValueArray.Length]; + for (i = 0; i < resultArray.Length; i++) { + var intValue = resultValueArray[i] as Int32Value; + if (intValue == null || !intValue.allBitsValid()) + return null; + resultArray[i] = (byte)intValue.value; + } + + return resultArray; + } + + static int findNewarr(MethodDefinition method, int arraySize) { + var instructions = method.Body.Instructions; + for (int i = 0; i < instructions.Count; i++) { + var instr = instructions[i]; + if (instr.OpCode.Code != Code.Newarr || i < 1) + continue; + var ldci4 = instructions[i - 1]; + if (!DotNetUtils.isLdcI4(ldci4)) + continue; + if (DotNetUtils.getLdcI4Value(ldci4) != arraySize) + continue; + + return i; + } + + return -1; + } + } +} diff --git a/de4dot.code/deobfuscators/dotNET_Reactor/EncryptedResource.cs b/de4dot.code/deobfuscators/dotNET_Reactor/EncryptedResource.cs index 3a67222e..6a2bdb50 100644 --- a/de4dot.code/deobfuscators/dotNET_Reactor/EncryptedResource.cs +++ b/de4dot.code/deobfuscators/dotNET_Reactor/EncryptedResource.cs @@ -22,9 +22,7 @@ using System.IO; using System.Collections.Generic; using System.Security.Cryptography; using Mono.Cecil; -using Mono.Cecil.Cil; using de4dot.blocks; -using de4dot.blocks.cflow; namespace de4dot.deobfuscators.dotNET_Reactor { class EncryptedResource { @@ -98,10 +96,10 @@ namespace de4dot.deobfuscators.dotNET_Reactor { if (encryptedDataResource == null) throw new ApplicationException("Could not find encrypted resource"); - key = initArray(resourceDecrypterMethod, 32); + key = ArrayFinder.getInitializedArray(resourceDecrypterMethod, 32); if (key == null) throw new ApplicationException("Could not find resource decrypter key"); - iv = initArray(resourceDecrypterMethod, 16); + iv = ArrayFinder.getInitializedArray(resourceDecrypterMethod, 16); if (iv == null) throw new ApplicationException("Could not find resource decrypter IV"); var publicKeyToken = module.Assembly.Name.PublicKeyToken; @@ -120,67 +118,6 @@ namespace de4dot.deobfuscators.dotNET_Reactor { return null; } - static byte[] initArray(MethodDefinition method, int arraySize) { - int newarrIndex = findNewarr(method, arraySize); - if (newarrIndex < 0) - return null; - - var resultValueArray = new Value[arraySize]; - - var emulator = new InstructionEmulator(method.HasThis, false, method.Parameters, method.Body.Variables); - var theArray = new UnknownValue(); - emulator.push(theArray); - - var instructions = method.Body.Instructions; - for (int i = newarrIndex + 1; i < instructions.Count; i++) { - var instr = instructions[i]; - if (instr.OpCode.FlowControl != FlowControl.Next) - break; - if (instr.OpCode.Code == Code.Newarr) - break; - - if (instr.OpCode.Code == Code.Stelem_I1) { - var value = emulator.pop(); - var index = emulator.pop() as Int32Value; - var array = emulator.pop(); - if (ReferenceEquals(array, theArray) && index != null && index.allBitsValid()) { - if (0 <= index.value && index.value < resultValueArray.Length) - resultValueArray[index.value] = value; - } - } - else - emulator.emulate(instr); - } - - byte[] resultArray = new byte[resultValueArray.Length]; - for (int i = 0; i < resultArray.Length; i++) { - var intValue = resultValueArray[i] as Int32Value; - if (intValue == null || !intValue.allBitsValid()) - return null; - resultArray[i] = (byte)intValue.value; - } - - return resultArray; - } - - static int findNewarr(MethodDefinition method, int arraySize) { - var instructions = method.Body.Instructions; - for (int i = 0; i < instructions.Count; i++) { - var instr = instructions[i]; - if (instr.OpCode.Code != Code.Newarr || i < 1) - continue; - var ldci4 = instructions[i - 1]; - if (!DotNetUtils.isLdcI4(ldci4)) - continue; - if (DotNetUtils.getLdcI4Value(ldci4) != arraySize) - continue; - - return i; - } - - return -1; - } - public byte[] decrypt() { if (encryptedDataResource == null || key == null || iv == null) throw new ApplicationException("Can't decrypt resource");