Merge branch 'master' into confuser

This commit is contained in:
de4dot 2014-05-10 09:20:54 +02:00
commit a7d9b67b28
81 changed files with 1780 additions and 299 deletions

2
.gitmodules vendored
View File

@ -1,3 +1,3 @@
[submodule "dnlib"]
path = dnlib
url = git@bitbucket.org:0xd4d/dnlib.git
url = git@github.com:0xd4d/dnlib.git

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("3.0.3.3405")]
[assembly: AssemblyFileVersion("3.0.3.3405")]
[assembly: AssemblyVersion("3.1.41592.3405")]
[assembly: AssemblyFileVersion("3.1.41592.3405")]

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("3.0.3.3405")]
[assembly: AssemblyFileVersion("3.0.3.3405")]
[assembly: AssemblyVersion("3.1.41592.3405")]
[assembly: AssemblyFileVersion("3.1.41592.3405")]

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("3.0.3.3405")]
[assembly: AssemblyFileVersion("3.0.3.3405")]
[assembly: AssemblyVersion("3.1.41592.3405")]
[assembly: AssemblyFileVersion("3.1.41592.3405")]

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("3.0.3.3405")]
[assembly: AssemblyFileVersion("3.0.3.3405")]
[assembly: AssemblyVersion("3.1.41592.3405")]
[assembly: AssemblyFileVersion("3.1.41592.3405")]

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("3.0.3.3405")]
[assembly: AssemblyFileVersion("3.0.3.3405")]
[assembly: AssemblyVersion("3.1.41592.3405")]
[assembly: AssemblyFileVersion("3.1.41592.3405")]

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("3.0.3.3405")]
[assembly: AssemblyFileVersion("3.0.3.3405")]
[assembly: AssemblyVersion("3.1.41592.3405")]
[assembly: AssemblyFileVersion("3.1.41592.3405")]

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("3.0.3.3405")]
[assembly: AssemblyFileVersion("3.0.3.3405")]
[assembly: AssemblyVersion("3.1.41592.3405")]
[assembly: AssemblyFileVersion("3.1.41592.3405")]

View File

@ -17,6 +17,6 @@
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
</LICENSE>
Official site: https://bitbucket.org/0xd4d/de4dot
Official site: https://github.com/0xd4d/de4dot
See the file COPYING for more details.

View File

@ -21,4 +21,4 @@
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
</LICENSE>
Official site: https://bitbucket.org/0xd4d/dnlib
Official site: https://github.com/0xd4d/dnlib

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("3.0.3.3405")]
[assembly: AssemblyFileVersion("3.0.3.3405")]
[assembly: AssemblyVersion("3.1.41592.3405")]
[assembly: AssemblyFileVersion("3.1.41592.3405")]

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("3.0.3.3405")]
[assembly: AssemblyFileVersion("3.0.3.3405")]
[assembly: AssemblyVersion("3.1.41592.3405")]
[assembly: AssemblyFileVersion("3.1.41592.3405")]

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("3.0.3.3405")]
[assembly: AssemblyFileVersion("3.0.3.3405")]
[assembly: AssemblyVersion("3.1.41592.3405")]
[assembly: AssemblyFileVersion("3.1.41592.3405")]

View File

@ -174,9 +174,9 @@ namespace de4dot.blocks {
public static bool IsPinvokeMethod(MethodDef method, string dll, string funcName) {
if (method == null)
return false;
if (method.ImplMap == null || method.ImplMap.Name.String != funcName)
if (method.ImplMap == null)
return false;
return GetDllName(dll).Equals(GetDllName(method.ImplMap.Module.Name.String), StringComparison.OrdinalIgnoreCase);
return method.ImplMap.IsPinvokeMethod(dll, funcName);
}
public static MethodDef GetMethod(ModuleDefMD module, IMethod method) {

View File

@ -19,6 +19,7 @@
using System.Collections.Generic;
using dnlib.DotNet;
using dnlib.Threading;
namespace de4dot.blocks {
public struct GenericArgsSubstitutor {
@ -291,7 +292,7 @@ namespace de4dot.blocks {
newSig.Params.Add(Create2(sig.Params[i]));
newSig.GenParamCount = sig.GenParamCount;
if (sig.ParamsAfterSentinel != null) {
newSig.ParamsAfterSentinel = new List<TypeSig>();
newSig.ParamsAfterSentinel = ThreadSafeListCreator.Create<TypeSig>();
for (int i = 0; i < sig.ParamsAfterSentinel.Count; i++)
newSig.ParamsAfterSentinel.Add(Create2(sig.ParamsAfterSentinel[i]));
}

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("3.0.3.3405")]
[assembly: AssemblyFileVersion("3.0.3.3405")]
[assembly: AssemblyVersion("3.1.41592.3405")]
[assembly: AssemblyFileVersion("3.1.41592.3405")]

View File

@ -95,6 +95,8 @@ namespace de4dot.blocks.cflow {
return EmulateBranch(2, Int32Value.CompareEq((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
return EmulateBranch(2, Int64Value.CompareEq((Int64Value)val1, (Int64Value)val2));
else if (val1.IsReal8() && val2.IsReal8())
return EmulateBranch(2, Real8Value.CompareEq((Real8Value)val1, (Real8Value)val2));
else if (val1.IsNull() && val2.IsNull())
return EmulateBranch(2, true);
else
@ -109,6 +111,8 @@ namespace de4dot.blocks.cflow {
return EmulateBranch(2, Int32Value.CompareNeq((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
return EmulateBranch(2, Int64Value.CompareNeq((Int64Value)val1, (Int64Value)val2));
else if (val1.IsReal8() && val2.IsReal8())
return EmulateBranch(2, Real8Value.CompareNeq((Real8Value)val1, (Real8Value)val2));
else if (val1.IsNull() && val2.IsNull())
return EmulateBranch(2, false);
else
@ -123,6 +127,8 @@ namespace de4dot.blocks.cflow {
return EmulateBranch(2, Int32Value.CompareGe((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
return EmulateBranch(2, Int64Value.CompareGe((Int64Value)val1, (Int64Value)val2));
else if (val1.IsReal8() && val2.IsReal8())
return EmulateBranch(2, Real8Value.CompareGe((Real8Value)val1, (Real8Value)val2));
else
return false;
}
@ -135,6 +141,8 @@ namespace de4dot.blocks.cflow {
return EmulateBranch(2, Int32Value.CompareGe_Un((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
return EmulateBranch(2, Int64Value.CompareGe_Un((Int64Value)val1, (Int64Value)val2));
else if (val1.IsReal8() && val2.IsReal8())
return EmulateBranch(2, Real8Value.CompareGe_Un((Real8Value)val1, (Real8Value)val2));
else
return false;
}
@ -147,6 +155,8 @@ namespace de4dot.blocks.cflow {
return EmulateBranch(2, Int32Value.CompareGt((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
return EmulateBranch(2, Int64Value.CompareGt((Int64Value)val1, (Int64Value)val2));
else if (val1.IsReal8() && val2.IsReal8())
return EmulateBranch(2, Real8Value.CompareGt((Real8Value)val1, (Real8Value)val2));
else
return false;
}
@ -159,6 +169,8 @@ namespace de4dot.blocks.cflow {
return EmulateBranch(2, Int32Value.CompareGt_Un((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
return EmulateBranch(2, Int64Value.CompareGt_Un((Int64Value)val1, (Int64Value)val2));
else if (val1.IsReal8() && val2.IsReal8())
return EmulateBranch(2, Real8Value.CompareGt_Un((Real8Value)val1, (Real8Value)val2));
else
return false;
}
@ -171,6 +183,8 @@ namespace de4dot.blocks.cflow {
return EmulateBranch(2, Int32Value.CompareLe((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
return EmulateBranch(2, Int64Value.CompareLe((Int64Value)val1, (Int64Value)val2));
else if (val1.IsReal8() && val2.IsReal8())
return EmulateBranch(2, Real8Value.CompareLe((Real8Value)val1, (Real8Value)val2));
else
return false;
}
@ -183,6 +197,8 @@ namespace de4dot.blocks.cflow {
return EmulateBranch(2, Int32Value.CompareLe_Un((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
return EmulateBranch(2, Int64Value.CompareLe_Un((Int64Value)val1, (Int64Value)val2));
else if (val1.IsReal8() && val2.IsReal8())
return EmulateBranch(2, Real8Value.CompareLe_Un((Real8Value)val1, (Real8Value)val2));
else
return false;
}
@ -195,6 +211,8 @@ namespace de4dot.blocks.cflow {
return EmulateBranch(2, Int32Value.CompareLt((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
return EmulateBranch(2, Int64Value.CompareLt((Int64Value)val1, (Int64Value)val2));
else if (val1.IsReal8() && val2.IsReal8())
return EmulateBranch(2, Real8Value.CompareLt((Real8Value)val1, (Real8Value)val2));
else
return false;
}
@ -207,6 +225,8 @@ namespace de4dot.blocks.cflow {
return EmulateBranch(2, Int32Value.CompareLt_Un((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
return EmulateBranch(2, Int64Value.CompareLt_Un((Int64Value)val1, (Int64Value)val2));
else if (val1.IsReal8() && val2.IsReal8())
return EmulateBranch(2, Real8Value.CompareLt_Un((Real8Value)val1, (Real8Value)val2));
else
return false;
}
@ -218,6 +238,8 @@ namespace de4dot.blocks.cflow {
return EmulateBranch(1, Int32Value.CompareFalse((Int32Value)val1));
else if (val1.IsInt64())
return EmulateBranch(1, Int64Value.CompareFalse((Int64Value)val1));
else if (val1.IsReal8())
return EmulateBranch(1, Real8Value.CompareFalse((Real8Value)val1));
else if (val1.IsNull())
return EmulateBranch(1, true);
else if (val1.IsObject() || val1.IsString())
@ -233,6 +255,8 @@ namespace de4dot.blocks.cflow {
return EmulateBranch(1, Int32Value.CompareTrue((Int32Value)val1));
else if (val1.IsInt64())
return EmulateBranch(1, Int64Value.CompareTrue((Int64Value)val1));
else if (val1.IsReal8())
return EmulateBranch(1, Real8Value.CompareTrue((Real8Value)val1));
else if (val1.IsNull())
return EmulateBranch(1, false);
else if (val1.IsObject() || val1.IsString())

View File

@ -70,6 +70,96 @@ namespace de4dot.blocks.cflow {
case Code.Ldloca_S:
instructionEmulator.MakeLocalUnknown((Local)instr.Operand);
break;
case Code.Add:
case Code.Add_Ovf:
case Code.Add_Ovf_Un:
case Code.And:
case Code.Ceq:
case Code.Cgt:
case Code.Cgt_Un:
case Code.Clt:
case Code.Clt_Un:
case Code.Conv_I:
case Code.Conv_I1:
case Code.Conv_I2:
case Code.Conv_I4:
case Code.Conv_I8:
case Code.Conv_Ovf_I:
case Code.Conv_Ovf_I_Un:
case Code.Conv_Ovf_I1:
case Code.Conv_Ovf_I1_Un:
case Code.Conv_Ovf_I2:
case Code.Conv_Ovf_I2_Un:
case Code.Conv_Ovf_I4:
case Code.Conv_Ovf_I4_Un:
case Code.Conv_Ovf_I8:
case Code.Conv_Ovf_I8_Un:
case Code.Conv_Ovf_U:
case Code.Conv_Ovf_U_Un:
case Code.Conv_Ovf_U1:
case Code.Conv_Ovf_U1_Un:
case Code.Conv_Ovf_U2:
case Code.Conv_Ovf_U2_Un:
case Code.Conv_Ovf_U4:
case Code.Conv_Ovf_U4_Un:
case Code.Conv_Ovf_U8:
case Code.Conv_Ovf_U8_Un:
case Code.Conv_R_Un:
case Code.Conv_R4:
case Code.Conv_R8:
case Code.Conv_U:
case Code.Conv_U1:
case Code.Conv_U2:
case Code.Conv_U4:
case Code.Conv_U8:
case Code.Div:
case Code.Div_Un:
case Code.Dup:
case Code.Mul:
case Code.Mul_Ovf:
case Code.Mul_Ovf_Un:
case Code.Neg:
case Code.Not:
case Code.Or:
case Code.Rem:
case Code.Rem_Un:
case Code.Shl:
case Code.Shr:
case Code.Shr_Un:
case Code.Sub:
case Code.Sub_Ovf:
case Code.Sub_Ovf_Un:
case Code.Xor:
if (i + 1 < instrs.Count && instrs[i + 1].OpCode.Code == Code.Pop)
break;
if (!VerifyValidArgs(instr.Instruction))
break;
instructionEmulator.Emulate(instr.Instruction);
var tos = instructionEmulator.Peek();
Instruction newInstr = null;
if (tos.IsInt32()) {
var val = (Int32Value)tos;
if (val.AllBitsValid())
newInstr = Instruction.CreateLdcI4(val.Value);
}
else if (tos.IsInt64()) {
var val = (Int64Value)tos;
if (val.AllBitsValid())
newInstr = OpCodes.Ldc_I8.ToInstruction(val.Value);
}
else if (tos.IsReal8()) {
var val = (Real8Value)tos;
if (val.IsValid)
newInstr = GetLoadRealInstruction(val.Value);
}
if (newInstr != null) {
block.Insert(i + 1, Instruction.Create(OpCodes.Pop));
block.Insert(i + 2, newInstr);
i += 2;
modified = true;
}
continue;
}
try {
@ -84,6 +174,53 @@ namespace de4dot.blocks.cflow {
return modified;
}
bool VerifyValidArgs(Instruction instr) {
int pushes, pops;
instr.CalculateStackUsage(out pushes, out pops);
if (pops < 0)
return false;
bool retVal;
Value val2, val1;
switch (pops) {
case 0:
return true;
case 1:
val1 = instructionEmulator.Pop();
retVal = VerifyValidArg(val1);
instructionEmulator.Push(val1);
return retVal;
case 2:
val2 = instructionEmulator.Pop();
val1 = instructionEmulator.Pop();
retVal = VerifyValidArg(val2) && VerifyValidArg(val1);
instructionEmulator.Push(val1);
instructionEmulator.Push(val2);
return retVal;
}
return false;
}
static bool VerifyValidArg(Value value) {
if (value.IsInt32())
return ((Int32Value)value).AllBitsValid();
if (value.IsInt64())
return ((Int64Value)value).AllBitsValid();
if (value.IsReal8())
return ((Real8Value)value).IsValid;
return false;
}
static Instruction GetLoadRealInstruction(double value) {
var floatVal = (float)value;
if (floatVal == value || double.IsNaN(value))
return OpCodes.Ldc_R4.ToInstruction(floatVal);
return OpCodes.Ldc_R8.ToInstruction(value);
}
bool FixLoadInstruction(Block block, int index, Value value) {
if (value.IsInt32()) {
var intValue = (Int32Value)value;

View File

@ -52,8 +52,12 @@ namespace de4dot.blocks.cflow {
}
public void Initialize(MethodDef method, bool emulateFromFirstInstruction) {
this.parameterDefs = method.Parameters;
this.localDefs = method.Body.Variables;
Initialize(method, method.Parameters, method.Body.Variables, method.Body.InitLocals, emulateFromFirstInstruction);
}
public void Initialize(MethodDef method, IList<Parameter> methodParameters, IList<Local> methodLocals, bool initLocals, bool emulateFromFirstInstruction) {
this.parameterDefs = methodParameters;
this.localDefs = methodLocals;
valueStack.Initialize();
protectedStackValues.Clear();
@ -75,7 +79,7 @@ namespace de4dot.blocks.cflow {
args.Clear();
args.AddRange(cached_args);
locals.Clear();
locals.AddRange(method.Body.InitLocals && emulateFromFirstInstruction ? cached_zeroed_locals : cached_locals);
locals.AddRange(initLocals && emulateFromFirstInstruction ? cached_zeroed_locals : cached_locals);
}
public void SetProtected(Value value) {
@ -429,9 +433,9 @@ namespace de4dot.blocks.cflow {
case Code.Unbox:
case Code.Conv_R_Un:
case Code.Conv_R4:
case Code.Conv_R8:
case Code.Conv_R_Un:Emulate_Conv_R_Un(instr); break;
case Code.Conv_R4: Emulate_Conv_R4(instr); break;
case Code.Conv_R8: Emulate_Conv_R8(instr); break;
case Code.Arglist:
case Code.Beq:
@ -782,6 +786,36 @@ namespace de4dot.blocks.cflow {
}
}
void Emulate_Conv_R_Un(Instruction instr) {
var val1 = valueStack.Pop();
switch (val1.valueType) {
case ValueType.Int32: valueStack.Push(Int32Value.Conv_R_Un((Int32Value)val1)); break;
case ValueType.Int64: valueStack.Push(Int64Value.Conv_R_Un((Int64Value)val1)); break;
case ValueType.Real8: valueStack.Push(Real8Value.Conv_R_Un((Real8Value)val1)); break;
default: valueStack.Push(Real8Value.CreateUnknown()); break;
}
}
void Emulate_Conv_R4(Instruction instr) {
var val1 = valueStack.Pop();
switch (val1.valueType) {
case ValueType.Int32: valueStack.Push(Int32Value.Conv_R4((Int32Value)val1)); break;
case ValueType.Int64: valueStack.Push(Int64Value.Conv_R4((Int64Value)val1)); break;
case ValueType.Real8: valueStack.Push(Real8Value.Conv_R4((Real8Value)val1)); break;
default: valueStack.Push(Real8Value.CreateUnknown()); break;
}
}
void Emulate_Conv_R8(Instruction instr) {
var val1 = valueStack.Pop();
switch (val1.valueType) {
case ValueType.Int32: valueStack.Push(Int32Value.Conv_R8((Int32Value)val1)); break;
case ValueType.Int64: valueStack.Push(Int64Value.Conv_R8((Int64Value)val1)); break;
case ValueType.Real8: valueStack.Push(Real8Value.Conv_R8((Real8Value)val1)); break;
default: valueStack.Push(Real8Value.CreateUnknown()); break;
}
}
void Emulate_Add(Instruction instr) {
var val2 = valueStack.Pop();
var val1 = valueStack.Pop();
@ -1064,6 +1098,8 @@ namespace de4dot.blocks.cflow {
valueStack.Push(Int32Value.Ceq((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
valueStack.Push(Int64Value.Ceq((Int64Value)val1, (Int64Value)val2));
else if (val1.IsReal8() && val2.IsReal8())
valueStack.Push(Real8Value.Ceq((Real8Value)val1, (Real8Value)val2));
else if (val1.IsNull() && val2.IsNull())
valueStack.Push(Int32Value.One);
else
@ -1078,6 +1114,8 @@ namespace de4dot.blocks.cflow {
valueStack.Push(Int32Value.Cgt((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
valueStack.Push(Int64Value.Cgt((Int64Value)val1, (Int64Value)val2));
else if (val1.IsReal8() && val2.IsReal8())
valueStack.Push(Real8Value.Cgt((Real8Value)val1, (Real8Value)val2));
else
valueStack.Push(Int32Value.CreateUnknownBool());
}
@ -1090,6 +1128,8 @@ namespace de4dot.blocks.cflow {
valueStack.Push(Int32Value.Cgt_Un((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
valueStack.Push(Int64Value.Cgt_Un((Int64Value)val1, (Int64Value)val2));
else if (val1.IsReal8() && val2.IsReal8())
valueStack.Push(Real8Value.Cgt_Un((Real8Value)val1, (Real8Value)val2));
else
valueStack.Push(Int32Value.CreateUnknownBool());
}
@ -1102,6 +1142,8 @@ namespace de4dot.blocks.cflow {
valueStack.Push(Int32Value.Clt((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
valueStack.Push(Int64Value.Clt((Int64Value)val1, (Int64Value)val2));
else if (val1.IsReal8() && val2.IsReal8())
valueStack.Push(Real8Value.Clt((Real8Value)val1, (Real8Value)val2));
else
valueStack.Push(Int32Value.CreateUnknownBool());
}
@ -1114,6 +1156,8 @@ namespace de4dot.blocks.cflow {
valueStack.Push(Int32Value.Clt_Un((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
valueStack.Push(Int64Value.Clt_Un((Int64Value)val1, (Int64Value)val2));
else if (val1.IsReal8() && val2.IsReal8())
valueStack.Push(Real8Value.Clt_Un((Real8Value)val1, (Real8Value)val2));
else
valueStack.Push(Int32Value.CreateUnknownBool());
}

View File

@ -331,6 +331,24 @@ namespace de4dot.blocks.cflow {
return new Int64Value((long)(uint)a.Value, a.ValidMask | (Int64Value.NO_UNKNOWN_BITS << 32));
}
public static Real8Value Conv_R_Un(Int32Value a) {
if (a.AllBitsValid())
return new Real8Value((float)(uint)a.Value);
return Real8Value.CreateUnknown();
}
public static Real8Value Conv_R4(Int32Value a) {
if (a.AllBitsValid())
return new Real8Value((float)(int)a.Value);
return Real8Value.CreateUnknown();
}
public static Real8Value Conv_R8(Int32Value a) {
if (a.AllBitsValid())
return new Real8Value((double)(int)a.Value);
return Real8Value.CreateUnknown();
}
public static Int32Value Add(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
return new Int32Value(a.Value + b.Value);
@ -556,7 +574,7 @@ namespace de4dot.blocks.cflow {
return new Int32Value((int)((uint)a.Value >> shift), validMask);
}
static Int32Value Create(Bool3 b) {
public static Int32Value Create(Bool3 b) {
switch (b) {
case Bool3.False: return Zero;
case Bool3.True: return One;

View File

@ -224,6 +224,24 @@ namespace de4dot.blocks.cflow {
return a;
}
public static Real8Value Conv_R_Un(Int64Value a) {
if (a.AllBitsValid())
return new Real8Value((float)(ulong)a.Value);
return Real8Value.CreateUnknown();
}
public static Real8Value Conv_R4(Int64Value a) {
if (a.AllBitsValid())
return new Real8Value((float)(long)a.Value);
return Real8Value.CreateUnknown();
}
public static Real8Value Conv_R8(Int64Value a) {
if (a.AllBitsValid())
return new Real8Value((double)(long)a.Value);
return Real8Value.CreateUnknown();
}
public static Int64Value Add(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
return new Int64Value(a.Value + b.Value);
@ -449,32 +467,24 @@ namespace de4dot.blocks.cflow {
return new Int64Value((long)((ulong)a.Value >> shift), validMask);
}
static Int32Value Create(Bool3 b) {
switch (b) {
case Bool3.False: return Int32Value.Zero;
case Bool3.True: return Int32Value.One;
default: return Int32Value.CreateUnknownBool();
}
}
public static Int32Value Ceq(Int64Value a, Int64Value b) {
return Create(CompareEq(a, b));
return Int32Value.Create(CompareEq(a, b));
}
public static Int32Value Cgt(Int64Value a, Int64Value b) {
return Create(CompareGt(a, b));
return Int32Value.Create(CompareGt(a, b));
}
public static Int32Value Cgt_Un(Int64Value a, Int64Value b) {
return Create(CompareGt_Un(a, b));
return Int32Value.Create(CompareGt_Un(a, b));
}
public static Int32Value Clt(Int64Value a, Int64Value b) {
return Create(CompareLt(a, b));
return Int32Value.Create(CompareLt(a, b));
}
public static Int32Value Clt_Un(Int64Value a, Int64Value b) {
return Create(CompareLt_Un(a, b));
return Int32Value.Create(CompareLt_Un(a, b));
}
public static Bool3 CompareEq(Int64Value a, Int64Value b) {

View File

@ -168,6 +168,100 @@ namespace de4dot.blocks.cflow {
return Int64Value.CreateUnknown();
}
public static Real8Value Conv_R_Un(Real8Value a) {
return CreateUnknown();
}
public static Real8Value Conv_R4(Real8Value a) {
if (a.IsValid)
return new Real8Value((float)a.Value);
return CreateUnknown();
}
public static Real8Value Conv_R8(Real8Value a) {
return a;
}
public static Int32Value Ceq(Real8Value a, Real8Value b) {
return Int32Value.Create(CompareEq(a, b));
}
public static Int32Value Cgt(Real8Value a, Real8Value b) {
return Int32Value.Create(CompareGt(a, b));
}
public static Int32Value Cgt_Un(Real8Value a, Real8Value b) {
return Int32Value.Create(CompareGt_Un(a, b));
}
public static Int32Value Clt(Real8Value a, Real8Value b) {
return Int32Value.Create(CompareLt(a, b));
}
public static Int32Value Clt_Un(Real8Value a, Real8Value b) {
return Int32Value.Create(CompareLt_Un(a, b));
}
public static Bool3 CompareEq(Real8Value a, Real8Value b) {
if (a.IsValid && b.IsValid)
return a.Value == b.Value ? Bool3.True : Bool3.False;
return Bool3.Unknown;
}
public static Bool3 CompareNeq(Real8Value a, Real8Value b) {
if (a.IsValid && b.IsValid)
return a.Value != b.Value ? Bool3.True : Bool3.False;
return Bool3.Unknown;
}
public static Bool3 CompareGt(Real8Value a, Real8Value b) {
if (a.IsValid && b.IsValid)
return a.Value > b.Value ? Bool3.True : Bool3.False;
return Bool3.Unknown;
}
public static Bool3 CompareGt_Un(Real8Value a, Real8Value b) {
return Bool3.Unknown; //TODO:
}
public static Bool3 CompareGe(Real8Value a, Real8Value b) {
if (a.IsValid && b.IsValid)
return a.Value >= b.Value ? Bool3.True : Bool3.False;
return Bool3.Unknown;
}
public static Bool3 CompareGe_Un(Real8Value a, Real8Value b) {
return Bool3.Unknown; //TODO:
}
public static Bool3 CompareLe(Real8Value a, Real8Value b) {
if (a.IsValid && b.IsValid)
return a.Value <= b.Value ? Bool3.True : Bool3.False;
return Bool3.Unknown;
}
public static Bool3 CompareLe_Un(Real8Value a, Real8Value b) {
return Bool3.Unknown; //TODO:
}
public static Bool3 CompareLt(Real8Value a, Real8Value b) {
if (a.IsValid && b.IsValid)
return a.Value < b.Value ? Bool3.True : Bool3.False;
return Bool3.Unknown;
}
public static Bool3 CompareLt_Un(Real8Value a, Real8Value b) {
return Bool3.Unknown; //TODO:
}
public static Bool3 CompareTrue(Real8Value a) {
return Bool3.Unknown;
}
public static Bool3 CompareFalse(Real8Value a) {
return Bool3.Unknown;
}
public override string ToString() {
if (!IsValid)
return "<INVALID_REAL8>";

View File

@ -61,15 +61,14 @@ namespace de4dot.code {
return false;
}
public bool HasMethodBody(uint rid) {
return GetDumpedMethod(rid) != null;
}
public MethodBody GetMethodBody(uint rid, RVA rva, IList<Parameter> parameters) {
public bool GetMethodBody(uint rid, RVA rva, IList<Parameter> parameters, GenericParamContext gpContext, out MethodBody methodBody) {
var dm = GetDumpedMethod(rid);
if (dm == null)
return null;
return MethodBodyReader.CreateCilBody(module, dm.code, dm.extraSections, parameters, dm.mhFlags, dm.mhMaxStack, dm.mhCodeSize, dm.mhLocalVarSigTok);
if (dm == null) {
methodBody = null;
return false;
}
methodBody = MethodBodyReader.CreateCilBody(module, dm.code, dm.extraSections, parameters, dm.mhFlags, dm.mhMaxStack, dm.mhCodeSize, dm.mhLocalVarSigTok, gpContext);
return true;
}
}
}

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("3.0.3.3405")]
[assembly: AssemblyFileVersion("3.0.3.3405")]
[assembly: AssemblyVersion("3.1.41592.3405")]
[assembly: AssemblyFileVersion("3.1.41592.3405")]

View File

@ -73,6 +73,7 @@
<Compile Include="deobfuscators\Agile_NET\ResourceDecrypter.cs" />
<Compile Include="deobfuscators\Agile_NET\StackFrameHelper.cs" />
<Compile Include="deobfuscators\Agile_NET\StringDecrypter.cs" />
<Compile Include="deobfuscators\Agile_NET\StringDecrypterInfo.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\CilOperandInstructionRestorer.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\CsvmDataReader.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\CsvmMethodData.cs" />

View File

@ -29,7 +29,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
TypeDef cliSecureRtType;
MethodDef postInitializeMethod;
MethodDef initializeMethod;
MethodDef stringDecrypterMethod;
Dictionary<StringDecrypterInfo, bool> stringDecrypterInfos = new Dictionary<StringDecrypterInfo, bool>();
MethodDef loadMethod;
bool foundSig;
@ -41,8 +41,8 @@ namespace de4dot.code.deobfuscators.Agile_NET {
get { return cliSecureRtType; }
}
public MethodDef StringDecrypterMethod {
get { return stringDecrypterMethod; }
public IEnumerable<StringDecrypterInfo> StringDecrypterInfos {
get { return stringDecrypterInfos.Keys; }
}
public MethodDef PostInitializeMethod {
@ -66,7 +66,11 @@ namespace de4dot.code.deobfuscators.Agile_NET {
cliSecureRtType = Lookup(oldOne.cliSecureRtType, "Could not find CliSecureRt type");
postInitializeMethod = Lookup(oldOne.postInitializeMethod, "Could not find postInitializeMethod method");
initializeMethod = Lookup(oldOne.initializeMethod, "Could not find initializeMethod method");
stringDecrypterMethod = Lookup(oldOne.stringDecrypterMethod, "Could not find stringDecrypterMethod method");
foreach (var info in oldOne.stringDecrypterInfos.Keys) {
var m = Lookup(info.Method, "Could not find string decrypter method");
var f = Lookup(info.Field, "Could not find string decrypter field");
stringDecrypterInfos[new StringDecrypterInfo(m, f)] = true;
}
loadMethod = Lookup(oldOne.loadMethod, "Could not find loadMethod method");
foundSig = oldOne.foundSig;
}
@ -100,11 +104,11 @@ namespace de4dot.code.deobfuscators.Agile_NET {
if (!HasInitializeMethod(type, "_Initialize") && !HasInitializeMethod(type, "_Initialize64"))
continue;
stringDecrypterMethod = FindStringDecrypterMethod(type);
initializeMethod = calledMethod;
postInitializeMethod = FindMethod(type, "System.Void", "PostInitialize", "()");
loadMethod = FindMethod(type, "System.IntPtr", "Load", "()");
cliSecureRtType = type;
FindStringDecrypters();
return true;
}
}
@ -112,6 +116,15 @@ namespace de4dot.code.deobfuscators.Agile_NET {
return false;
}
void FindStringDecrypters() {
AddStringDecrypterMethod(FindStringDecrypterMethod(cliSecureRtType));
}
void AddStringDecrypterMethod(MethodDef method) {
if (method != null)
stringDecrypterInfos[new StringDecrypterInfo(method)] = true;
}
static string[] requiredFields6 = new string[] {
"System.Byte[]",
};
@ -134,7 +147,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
if (cs == null)
continue;
stringDecrypterMethod = cs;
AddStringDecrypterMethod(cs);
cliSecureRtType = type;
return true;
}
@ -208,7 +221,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
continue;
cliSecureRtType = type;
stringDecrypterMethod = cs;
AddStringDecrypterMethod(cs);
return;
}
}

View File

@ -180,7 +180,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
FindCliSecureAttribute();
cliSecureRtType = new CliSecureRtType(module);
cliSecureRtType.Find(ModuleBytes);
stringDecrypter = new StringDecrypter(module, cliSecureRtType.StringDecrypterMethod);
stringDecrypter = new StringDecrypter(module, cliSecureRtType.StringDecrypterInfos);
stringDecrypter.Find();
resourceDecrypter = new ResourceDecrypter(module);
resourceDecrypter.Find();
@ -246,7 +246,8 @@ namespace de4dot.code.deobfuscators.Agile_NET {
base.DeobfuscateBegin();
cliSecureRtType.FindStringDecrypterMethod();
stringDecrypter.Method = cliSecureRtType.StringDecrypterMethod;
stringDecrypter.AddDecrypterInfos(cliSecureRtType.StringDecrypterInfos);
stringDecrypter.Initialize();
AddAttributesToBeRemoved(cliSecureAttributes, "Obfuscator attribute");
@ -265,7 +266,8 @@ namespace de4dot.code.deobfuscators.Agile_NET {
proxyCallFixer.Find();
staticStringInliner.Add(stringDecrypter.Method, (method, gim, args) => stringDecrypter.Decrypt((string)args[0]));
foreach (var info in stringDecrypter.StringDecrypterInfos)
staticStringInliner.Add(info.Method, (method, gim, args) => stringDecrypter.Decrypt((string)args[0]));
DeobfuscatedFile.StringDecryptersAdded();
if (options.DecryptMethods) {
@ -295,6 +297,8 @@ namespace de4dot.code.deobfuscators.Agile_NET {
}
public override void DeobfuscateMethodEnd(Blocks blocks) {
if (Operations.DecryptStrings != OpDecryptString.None)
stringDecrypter.Deobfuscate(blocks);
proxyCallFixer.Deobfuscate(blocks);
RemoveStackFrameHelperCode(blocks);
base.DeobfuscateMethodEnd(blocks);
@ -310,8 +314,14 @@ namespace de4dot.code.deobfuscators.Agile_NET {
}
if (CanRemoveStringDecrypterType) {
AddTypeToBeRemoved(stringDecrypter.Type, "String decrypter type");
foreach (var info in stringDecrypter.StringDecrypterInfos) {
if (info.Method.DeclaringType != cliSecureRtType.Type)
AddMethodToBeRemoved(info.Method, "String decrypter method");
if (info.Field != null && info.Field.DeclaringType != stringDecrypter.Type)
AddFieldToBeRemoved(info.Field, "String decrypter field");
}
if (options.DecryptMethods)
AddTypeToBeRemoved(cliSecureRtType.Type, "Obfuscator type");
AddTypeToBeRemoved(cliSecureRtType.Type ?? stringDecrypter.KeyArrayFieldType, "Obfuscator type");
}
if (options.DecryptMethods) {
AddResources("Obfuscator protection files");
@ -327,8 +337,8 @@ namespace de4dot.code.deobfuscators.Agile_NET {
public override IEnumerable<int> GetStringDecrypterMethods() {
var list = new List<int>();
if (stringDecrypter.Method != null)
list.Add(stringDecrypter.Method.MDToken.ToInt32());
foreach (var info in stringDecrypter.StringDecrypterInfos)
list.Add(info.Method.MDToken.ToInt32());
return list;
}

View File

@ -62,10 +62,15 @@ namespace de4dot.code.deobfuscators.Agile_NET {
FindResourceType();
}
static readonly string[] requiredFields = new string[] {
static readonly string[] requiredFields1 = new string[] {
"System.Reflection.Assembly",
"System.String[]",
};
static readonly string[] requiredFields2 = new string[] {
"System.Reflection.Assembly",
"System.String[]",
"System.Collections.Hashtable",
};
void FindResourceType() {
var cctor = DotNetUtils.GetModuleTypeCctor(module);
if (cctor == null)
@ -77,7 +82,9 @@ namespace de4dot.code.deobfuscators.Agile_NET {
if (!DotNetUtils.IsMethod(calledMethod, "System.Void", "()"))
continue;
var type = calledMethod.DeclaringType;
if (!new FieldTypes(type).Exactly(requiredFields))
var fieldTypes = new FieldTypes(type);
if (!fieldTypes.Exactly(requiredFields1) &&
!fieldTypes.Exactly(requiredFields2))
continue;
var resolveHandler = DotNetUtils.GetMethod(type, "System.Reflection.Assembly", "(System.Object,System.ResolveEventArgs)");

View File

@ -18,38 +18,53 @@
*/
using System;
using System.Collections.Generic;
using System.Text;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.Agile_NET {
class StringDecrypter {
ModuleDefMD module;
TypeDef stringDecrypterType;
MethodDef stringDecrypterMethod;
FieldDef keyInitField;
FieldDef keyArrayField;
Dictionary<StringDecrypterInfo, bool> stringDecrypterInfos = new Dictionary<StringDecrypterInfo, bool>();
byte[] stringDecrypterKey;
public bool Detected {
get { return stringDecrypterMethod != null; }
get { return stringDecrypterInfos.Count != 0; }
}
public TypeDef Type {
get { return stringDecrypterType; }
}
public MethodDef Method {
get { return stringDecrypterMethod; }
set { stringDecrypterMethod = value; }
public TypeDef KeyArrayFieldType {
get { return keyArrayField == null ? null : keyArrayField.DeclaringType; }
}
public StringDecrypter(ModuleDefMD module, MethodDef stringDecrypterMethod) {
public IEnumerable<StringDecrypterInfo> StringDecrypterInfos {
get { return stringDecrypterInfos.Keys; }
}
public StringDecrypter(ModuleDefMD module, IEnumerable<StringDecrypterInfo> stringDecrypterMethods) {
this.module = module;
this.stringDecrypterMethod = stringDecrypterMethod;
foreach (var sdm in stringDecrypterMethods)
this.stringDecrypterInfos[sdm] = true;
}
public StringDecrypter(ModuleDefMD module, StringDecrypter oldOne) {
this.module = module;
stringDecrypterType = Lookup(oldOne.stringDecrypterType, "Could not find stringDecrypterType");
stringDecrypterMethod = Lookup(oldOne.stringDecrypterMethod, "Could not find stringDecrypterMethod");
keyInitField = Lookup(oldOne.keyInitField, "Could not find key init field");
keyArrayField = Lookup(oldOne.keyArrayField, "Could not find key array field");
foreach (var info in oldOne.stringDecrypterInfos.Keys) {
var m = Lookup(info.Method, "Could not find string decrypter method");
var f = Lookup(info.Field, "Could not find string decrypter field");
stringDecrypterInfos[new StringDecrypterInfo(m, f)] = true;
}
stringDecrypterKey = oldOne.stringDecrypterKey;
}
@ -57,6 +72,11 @@ namespace de4dot.code.deobfuscators.Agile_NET {
return DeobUtils.Lookup(module, def, errorMessage);
}
public void AddDecrypterInfos(IEnumerable<StringDecrypterInfo> infos) {
foreach (var info in infos)
stringDecrypterInfos[info] = true;
}
public void Find() {
stringDecrypterKey = new byte[1] { 0xFF };
foreach (var type in module.Types) {
@ -64,6 +84,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
stringDecrypterType = type;
foreach (var field in type.Fields) {
if (field.FullName == "<D234> <D234>::345" || field.FullName == "<ClassD234>/D234 <ClassD234>::345") {
keyInitField = field;
stringDecrypterKey = field.InitialValue;
break;
}
@ -73,6 +94,121 @@ namespace de4dot.code.deobfuscators.Agile_NET {
}
}
public void Initialize() {
if (keyInitField == null)
return;
foreach (var type in module.Types) {
var cctor = type.FindStaticConstructor();
if (cctor == null)
continue;
keyArrayField = GetKeyArrayField(cctor, keyInitField);
if (keyArrayField != null)
break;
}
if (keyArrayField == null)
return;
foreach (var type in module.GetTypes()) {
FieldDef field;
var method = FindStringDecrypters(type, keyArrayField, out field);
if (method == null)
continue;
stringDecrypterInfos[new StringDecrypterInfo(method, field)] = true;
}
}
static FieldDef GetKeyArrayField(MethodDef method, FieldDef keyInitField) {
if (method == null || method.Body == null)
return null;
var instrs = method.Body.Instructions;
for (int i = 0; i < instrs.Count; i++) {
if (instrs[i].OpCode.Code != Code.Ldtoken)
continue;
i++;
for (; i < instrs.Count; i++) {
var instr = instrs[i];
if (instr.OpCode.Code != Code.Stsfld)
continue;
var field = instr.Operand as FieldDef;
if (field == null || !field.IsStatic || field.DeclaringType != method.DeclaringType)
continue;
if (field.FieldSig.GetFieldType().GetFullName() != "System.Byte[]")
continue;
return field;
}
}
return null;
}
static MethodDef FindStringDecrypters(TypeDef type, FieldDef keyArrayField, out FieldDef field) {
FieldDef foundField = null;
foreach (var method in type.Methods) {
if (!method.IsAssembly || !method.IsStatic)
continue;
if (!DotNetUtils.IsMethod(method, "System.String", "(System.String)"))
continue;
if (!method.HasBody)
continue;
bool accessedArrayField = false;
foreach (var instr in method.Body.Instructions) {
var f = instr.Operand as FieldDef;
accessedArrayField |= f == keyArrayField;
if (f == null || f == keyArrayField || f == foundField)
continue;
if (DotNetUtils.DerivesFromDelegate(f.DeclaringType))
continue;
if (f.FieldSig.GetFieldType().GetFullName() != "System.Collections.Hashtable" ||
foundField != null)
goto exit;
foundField = f;
}
if (!accessedArrayField)
continue;
field = foundField;
return method;
}
exit: ;
field = null;
return null;
}
public void Deobfuscate(Blocks blocks) {
if (!blocks.Method.IsStaticConstructor)
return;
var decrypterFields = new Dictionary<FieldDef, bool>(stringDecrypterInfos.Count);
foreach (var info in stringDecrypterInfos.Keys) {
if (info.Field != null)
decrypterFields[info.Field] = true;
}
foreach (var block in blocks.MethodBlocks.GetAllBlocks()) {
var instrs = block.Instructions;
for (int i = instrs.Count - 2; i >= 0; i--) {
var newobj = instrs[i];
if (newobj.OpCode.Code != Code.Newobj)
continue;
var ctor = newobj.Operand as IMethod;
if (ctor == null || ctor.FullName != "System.Void System.Collections.Hashtable::.ctor()")
continue;
var stsfld = instrs[i + 1];
if (stsfld.OpCode.Code != Code.Stsfld)
continue;
var field = stsfld.Operand as FieldDef;
if (field == null || !decrypterFields.ContainsKey(field))
continue;
block.Remove(i, 2);
}
}
}
public string Decrypt(string es) {
if (stringDecrypterKey == null)
throw new ApplicationException("Trying to decrypt strings when stringDecrypterKey is null (could not find it!)");

View File

@ -0,0 +1,52 @@
/*
Copyright (C) 2011-2014 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 <http://www.gnu.org/licenses/>.
*/
using dnlib.DotNet;
namespace de4dot.code.deobfuscators.Agile_NET {
class StringDecrypterInfo {
public readonly MethodDef Method;
public readonly FieldDef Field;
public StringDecrypterInfo(MethodDef method)
: this(method, null) {
}
public StringDecrypterInfo(MethodDef method, FieldDef field) {
this.Method = method;
this.Field = field;
}
public override int GetHashCode() {
int hash = 0;
if (Method != null)
hash ^= Method.GetHashCode();
if (Field != null)
hash ^= Field.GetHashCode();
return hash;
}
public override bool Equals(object obj) {
var other = obj as StringDecrypterInfo;
return other != null &&
Method == other.Method &&
Field == other.Field;
}
}
}

View File

@ -232,13 +232,14 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
if (numLocals < 0)
throw new ApplicationException("Invalid number of locals");
var gpContext = GenericParamContext.Create(cilMethod);
for (int i = 0; i < numLocals; i++)
locals.Add(new Local(ReadTypeRef(reader)));
locals.Add(new Local(ReadTypeRef(reader, gpContext)));
return locals;
}
TypeSig ReadTypeRef(BinaryReader reader) {
TypeSig ReadTypeRef(BinaryReader reader, GenericParamContext gpContext) {
var etype = (ElementType)reader.ReadInt32();
switch (etype) {
case ElementType.Void: return module.CorLibTypes.Void;
@ -263,12 +264,12 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
case ElementType.ValueType:
case ElementType.Var:
case ElementType.MVar:
return (module.ResolveToken(reader.ReadUInt32()) as ITypeDefOrRef).ToTypeSig();
return (module.ResolveToken(reader.ReadUInt32(), gpContext) as ITypeDefOrRef).ToTypeSig();
case ElementType.GenericInst:
etype = (ElementType)reader.ReadInt32();
if (etype == ElementType.ValueType)
return (module.ResolveToken(reader.ReadUInt32()) as ITypeDefOrRef).ToTypeSig();
return (module.ResolveToken(reader.ReadUInt32(), gpContext) as ITypeDefOrRef).ToTypeSig();
// ElementType.Class
return module.CorLibTypes.Object;
@ -299,6 +300,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
if (numExceptions < 0)
throw new ApplicationException("Invalid number of exception handlers");
var gpContext = GenericParamContext.Create(cilMethod);
for (int i = 0; i < numExceptions; i++) {
var eh = new ExceptionHandler((ExceptionHandlerType)reader.ReadInt32());
eh.TryStart = GetInstruction(reader.ReadInt32());
@ -306,7 +308,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
eh.HandlerStart = GetInstruction(reader.ReadInt32());
eh.HandlerEnd = GetInstructionEnd(reader.ReadInt32());
if (eh.HandlerType == ExceptionHandlerType.Catch)
eh.CatchType = module.ResolveToken(reader.ReadUInt32()) as ITypeDefOrRef;
eh.CatchType = module.ResolveToken(reader.ReadUInt32(), gpContext) as ITypeDefOrRef;
else if (eh.HandlerType == ExceptionHandlerType.Filter)
eh.FilterStart = GetInstruction(reader.ReadInt32());

View File

@ -34,12 +34,13 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
}
protected override List<Instruction> ReadInstructions(MethodDef cilMethod, CsvmMethodData csvmMethod) {
var gpContext = GenericParamContext.Create(cilMethod);
var reader = new BinaryReader(new MemoryStream(csvmMethod.Instructions));
var instrs = new List<Instruction>();
uint offset = 0;
while (reader.BaseStream.Position < reader.BaseStream.Length) {
int vmOpCode = reader.ReadUInt16();
var instr = opCodeDetector.Handlers[vmOpCode].Read(reader, module);
var instr = opCodeDetector.Handlers[vmOpCode].Read(reader, module, gpContext);
instr.Offset = offset;
offset += (uint)GetInstructionSize(instr);
SetCilToVmIndex(instr, instrs.Count);

View File

@ -29,7 +29,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
public string Name { get; set; }
public OpCodeHandlerSigInfo OpCodeHandlerSigInfo { get; set; }
public Predicate<UnknownHandlerInfo> Check { get; set; }
public Func<BinaryReader, IInstructionOperandResolver, Instruction> Read { get; set; }
public Func<BinaryReader, IInstructionOperandResolver, GenericParamContext, Instruction> Read { get; set; }
public bool Detect(UnknownHandlerInfo info) {
var sigInfo = OpCodeHandlerSigInfo;
@ -68,7 +68,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
}
static partial class OpCodeHandlers {
static Instruction arithmetic_read(BinaryReader reader, IInstructionOperandResolver resolver) {
static Instruction arithmetic_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
switch (reader.ReadByte()) {
case 0: return OpCodes.Add.ToInstruction();
case 1: return OpCodes.Add_Ovf.ToInstruction();
@ -91,22 +91,22 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
return DotNetUtils.CallsMethod(info.ExecuteMethod, "System.Type System.Reflection.Module::ResolveType(System.Int32)");
}
static Instruction newarr_read(BinaryReader reader, IInstructionOperandResolver resolver) {
return new Instruction(OpCodes.Newarr, resolver.ResolveToken(reader.ReadUInt32()));
static Instruction newarr_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
return new Instruction(OpCodes.Newarr, resolver.ResolveToken(reader.ReadUInt32(), gpContext));
}
static Instruction box_read(BinaryReader reader, IInstructionOperandResolver resolver) {
static Instruction box_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
var instr = new Instruction();
switch (reader.ReadByte()) {
case 0: instr.OpCode = OpCodes.Box; break;
case 1: instr.OpCode = OpCodes.Unbox_Any; break;
default: throw new ApplicationException("Invalid opcode");
}
instr.Operand = resolver.ResolveToken(reader.ReadUInt32());
instr.Operand = resolver.ResolveToken(reader.ReadUInt32(), gpContext);
return instr;
}
static Instruction call_read(BinaryReader reader, IInstructionOperandResolver resolver) {
static Instruction call_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
var instr = new Instruction();
switch (reader.ReadByte()) {
case 0: instr.OpCode = OpCodes.Newobj; break;
@ -114,22 +114,22 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
case 2: instr.OpCode = OpCodes.Callvirt; break;
default: throw new ApplicationException("Invalid opcode");
}
instr.Operand = resolver.ResolveToken(reader.ReadUInt32());
instr.Operand = resolver.ResolveToken(reader.ReadUInt32(), gpContext);
return instr;
}
static Instruction cast_read(BinaryReader reader, IInstructionOperandResolver resolver) {
static Instruction cast_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
var instr = new Instruction();
switch (reader.ReadByte()) {
case 0: instr.OpCode = OpCodes.Castclass; break;
case 1: instr.OpCode = OpCodes.Isinst; break;
default: throw new ApplicationException("Invalid opcode");
}
instr.Operand = resolver.ResolveToken(reader.ReadUInt32());
instr.Operand = resolver.ResolveToken(reader.ReadUInt32(), gpContext);
return instr;
}
static Instruction compare_read(BinaryReader reader, IInstructionOperandResolver resolver) {
static Instruction compare_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
int type = reader.ReadByte();
Instruction instr = new Instruction();
switch (type) {
@ -202,7 +202,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
new InstructionInfo1 { Type = 11, Second = true, Third = true, OpCode = OpCodes.Conv_Ovf_U_Un },
new InstructionInfo1 { Type = 12, Second = true, Third = true, OpCode = OpCodes.Conv_R_Un },
};
static Instruction convert_read(BinaryReader reader, IInstructionOperandResolver resolver) {
static Instruction convert_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
byte type = reader.ReadByte();
bool second = reader.ReadBoolean();
bool third = reader.ReadBoolean();
@ -221,7 +221,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
return instr;
}
static Instruction dup_read(BinaryReader reader, IInstructionOperandResolver resolver) {
static Instruction dup_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
switch (reader.ReadByte()) {
case 0: return OpCodes.Dup.ToInstruction();
case 1: return OpCodes.Pop.ToInstruction();
@ -259,7 +259,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
new InstructionInfo2 { First = true, Second = true, Value = 28, OpCode = OpCodes.Ldelem_Ref },
new InstructionInfo2 { First = true, Second = false, Value = 0, OpCode = OpCodes.Ldelem },
};
static Instruction ldelem_read(BinaryReader reader, IInstructionOperandResolver resolver) {
static Instruction ldelem_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
Instruction instr = null;
bool first = reader.ReadBoolean();
bool second = reader.ReadBoolean();
@ -273,7 +273,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
if (second)
instr = new Instruction(info.OpCode);
else
instr = new Instruction(info.OpCode, resolver.ResolveToken((uint)value));
instr = new Instruction(info.OpCode, resolver.ResolveToken((uint)value, gpContext));
break;
}
if (instr == null)
@ -286,13 +286,13 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
return DotNetUtils.CallsMethod(info.ExecuteMethod, "System.Reflection.MethodInfo System.Type::GetMethod(System.String,System.Reflection.BindingFlags)");
}
static Instruction endfinally_read(BinaryReader reader, IInstructionOperandResolver resolver) {
static Instruction endfinally_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
return OpCodes.Endfinally.ToInstruction();
}
static Instruction ldfld_read(BinaryReader reader, IInstructionOperandResolver resolver) {
static Instruction ldfld_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
byte b = reader.ReadByte();
var field = resolver.ResolveToken(reader.ReadUInt32()) as IField;
var field = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as IField;
switch (b) {
case 0: return new Instruction(null, new FieldInstructionOperand(OpCodes.Ldsfld, OpCodes.Ldfld, field));
case 1: return new Instruction(null, new FieldInstructionOperand(OpCodes.Ldsflda, OpCodes.Ldflda, field));
@ -301,11 +301,11 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
}
}
static Instruction initobj_read(BinaryReader reader, IInstructionOperandResolver resolver) {
return new Instruction(OpCodes.Initobj, resolver.ResolveToken(reader.ReadUInt32()));
static Instruction initobj_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
return new Instruction(OpCodes.Initobj, resolver.ResolveToken(reader.ReadUInt32(), gpContext));
}
static Instruction ldloc_read(BinaryReader reader, IInstructionOperandResolver resolver) {
static Instruction ldloc_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
bool isLdarg = reader.ReadBoolean();
ushort index = reader.ReadUInt16();
@ -322,7 +322,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
return instr;
}
static Instruction ldloca_read(BinaryReader reader, IInstructionOperandResolver resolver) {
static Instruction ldloca_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
Instruction instr = new Instruction();
if (reader.ReadBoolean()) {
instr.OpCode = OpCodes.Ldarga;
@ -336,19 +336,19 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
return instr;
}
static Instruction ldelema_read(BinaryReader reader, IInstructionOperandResolver resolver) {
static Instruction ldelema_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
return new Instruction(OpCodes.Ldelema, null);
}
static Instruction ldlen_read(BinaryReader reader, IInstructionOperandResolver resolver) {
static Instruction ldlen_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
return OpCodes.Ldlen.ToInstruction();
}
static Instruction ldobj_read(BinaryReader reader, IInstructionOperandResolver resolver) {
static Instruction ldobj_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
return new Instruction(OpCodes.Ldobj, null);
}
static Instruction ldstr_read(BinaryReader reader, IInstructionOperandResolver resolver) {
static Instruction ldstr_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
return OpCodes.Ldstr.ToInstruction(reader.ReadString());
}
@ -356,8 +356,8 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
return DotNetUtils.CallsMethod(info.ExecuteMethod, "System.Reflection.MemberInfo System.Reflection.Module::ResolveMember(System.Int32)");
}
static Instruction ldtoken_read(BinaryReader reader, IInstructionOperandResolver resolver) {
return new Instruction(OpCodes.Ldtoken, resolver.ResolveToken(reader.ReadUInt32()));
static Instruction ldtoken_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
return new Instruction(OpCodes.Ldtoken, resolver.ResolveToken(reader.ReadUInt32(), gpContext));
}
static bool leave_check(UnknownHandlerInfo info) {
@ -366,12 +366,12 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
!DotNetUtils.CallsMethod(info.ExecuteMethod, "System.Reflection.MemberInfo System.Reflection.Module::ResolveMember(System.Int32)");
}
static Instruction leave_read(BinaryReader reader, IInstructionOperandResolver resolver) {
static Instruction leave_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
int displacement = reader.ReadInt32();
return new Instruction(OpCodes.Leave, new TargetDisplOperand(displacement));
}
static Instruction ldc_read(BinaryReader reader, IInstructionOperandResolver resolver) {
static Instruction ldc_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
switch ((ElementType)reader.ReadByte()) {
case ElementType.I4: return Instruction.CreateLdcI4(reader.ReadInt32());
case ElementType.I8: return OpCodes.Ldc_I8.ToInstruction(reader.ReadInt64());
@ -382,24 +382,24 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
}
}
static Instruction ldftn_read(BinaryReader reader, IInstructionOperandResolver resolver) {
static Instruction ldftn_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
byte code = reader.ReadByte();
uint token = reader.ReadUInt32();
switch (code) {
case 0:
return new Instruction(OpCodes.Ldftn, resolver.ResolveToken(token));
return new Instruction(OpCodes.Ldftn, resolver.ResolveToken(token, gpContext));
case 1:
reader.ReadInt32(); // token of newobj .ctor
return new Instruction(OpCodes.Ldvirtftn, resolver.ResolveToken(token));
return new Instruction(OpCodes.Ldvirtftn, resolver.ResolveToken(token, gpContext));
default:
throw new ApplicationException("Invalid opcode");
}
}
static Instruction logical_read(BinaryReader reader, IInstructionOperandResolver resolver) {
static Instruction logical_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
switch (reader.ReadByte()) {
case 0: return OpCodes.And.ToInstruction();
case 1: return OpCodes.Or.ToInstruction();
@ -425,7 +425,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
return false;
}
static Instruction nop_read(BinaryReader reader, IInstructionOperandResolver resolver) {
static Instruction nop_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
return OpCodes.Nop.ToInstruction();
}
@ -433,7 +433,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
return DotNetUtils.CallsMethod(info.ExecuteMethod, "System.Reflection.MethodBase System.Reflection.Module::ResolveMethod(System.Int32)");
}
static Instruction ret_read(BinaryReader reader, IInstructionOperandResolver resolver) {
static Instruction ret_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
reader.ReadInt32(); // token of current method
return OpCodes.Ret.ToInstruction();
}
@ -442,11 +442,11 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
return info.ExecuteMethod.Body.Variables.Count == 0;
}
static Instruction rethrow_read(BinaryReader reader, IInstructionOperandResolver resolver) {
static Instruction rethrow_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
return OpCodes.Rethrow.ToInstruction();
}
static Instruction stloc_read(BinaryReader reader, IInstructionOperandResolver resolver) {
static Instruction stloc_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
bool isStarg = reader.ReadBoolean();
ushort index = reader.ReadUInt16();
@ -464,11 +464,11 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
return instr;
}
static Instruction stobj_read(BinaryReader reader, IInstructionOperandResolver resolver) {
static Instruction stobj_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
return new Instruction(OpCodes.Stobj, null);
}
static Instruction switch_read(BinaryReader reader, IInstructionOperandResolver resolver) {
static Instruction switch_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
int numTargets = reader.ReadInt32();
int[] targetDispls = new int[numTargets];
for (int i = 0; i < targetDispls.Length; i++)
@ -480,11 +480,11 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
return !DotNetUtils.CallsMethod(info.ExecuteMethod, "System.Reflection.MethodInfo System.Type::GetMethod(System.String,System.Reflection.BindingFlags)");
}
static Instruction throw_read(BinaryReader reader, IInstructionOperandResolver resolver) {
static Instruction throw_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
return OpCodes.Throw.ToInstruction();
}
static Instruction neg_read(BinaryReader reader, IInstructionOperandResolver resolver) {
static Instruction neg_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
switch (reader.ReadByte()) {
case 0: return OpCodes.Neg.ToInstruction();
case 1: return OpCodes.Not.ToInstruction();

Binary file not shown.

View File

@ -53,10 +53,10 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
public readonly int BlockIndex;
public int HashIndex;
public HandlerState(List<BlockSigInfo> blockSigInfos, int blockIndex, int instructionIndex) {
public HandlerState(List<BlockSigInfo> blockSigInfos, int blockIndex, int hashIndex) {
this.BlockSigInfos = blockSigInfos;
this.BlockIndex = blockIndex;
this.HashIndex = instructionIndex;
this.HashIndex = hashIndex;
}
public HandlerState Clone() {
@ -164,6 +164,8 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
}
}
if (nextState == null && findState.VisitedCompositeBlocks.Count != findState.CompositeState.BlockSigInfos.Count)
nextState = GetNextHandlerState(ref findState);
if (nextState == null) {
if (findState.VisitedCompositeBlocks.Count != findState.CompositeState.BlockSigInfos.Count)
return false;
@ -181,6 +183,16 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
}
}
static HandlerState? GetNextHandlerState(ref FindHandlerState findState) {
for (int i = 0; i < findState.CompositeState.BlockSigInfos.Count; i++) {
if (findState.VisitedCompositeBlocks.ContainsKey(i))
continue;
return new HandlerState(findState.CompositeState.BlockSigInfos, i, 0);
}
return null;
}
static bool Compare(ref HandlerState handler, ref HandlerState composite) {
var hhashes = handler.BlockSigInfos[handler.BlockIndex].Hashes;
int hi = handler.HashIndex;

View File

@ -81,7 +81,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
foreach (var type in module.Types) {
if (!type.IsPublic || !type.IsAbstract)
continue;
if (type.HasFields || type.HasProperties || type.HasEvents)
if (type.HasProperties || type.HasEvents)
continue;
if (type.BaseType == null || type.BaseType.FullName != "System.Object")
continue;

View File

@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.18052
// Runtime Version:4.0.30319.18444
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@ -99,5 +99,15 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] CSVM5 {
get {
object obj = ResourceManager.GetObject("CSVM5", resourceCulture);
return ((byte[])(obj));
}
}
}
}

View File

@ -130,4 +130,8 @@
<data name="CSVM4" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>CSVM4.bin;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="CSVM5" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>CSVM5.bin;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>

View File

@ -35,7 +35,8 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
protected override List<Instruction> ReadInstructions(MethodDef cilMethod, CsvmMethodData csvmMethod) {
var reader = new BinaryReader(new MemoryStream(csvmMethod.Instructions));
var instrs = new List<Instruction>();
var handlerInfoReader = new OpCodeHandlerInfoReader(module);
var gpContext = GenericParamContext.Create(cilMethod);
var handlerInfoReader = new OpCodeHandlerInfoReader(module, gpContext);
int numVmInstrs = reader.ReadInt32();
var vmInstrs = new ushort[numVmInstrs];

View File

@ -27,9 +27,11 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
class OpCodeHandlerInfoReader {
IInstructionOperandResolver resolver;
Dictionary<HandlerTypeCode, Func<BinaryReader, Instruction>> readHandlers;
readonly GenericParamContext gpContext;
public OpCodeHandlerInfoReader(IInstructionOperandResolver resolver) {
public OpCodeHandlerInfoReader(IInstructionOperandResolver resolver, GenericParamContext gpContext) {
this.resolver = resolver;
this.gpContext = gpContext;
this.readHandlers = new Dictionary<HandlerTypeCode, Func<BinaryReader, Instruction>> {
{ HandlerTypeCode.Add, Handler_Add },
{ HandlerTypeCode.Add_Ovf, Handler_Add_Ovf },
@ -176,7 +178,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
}
Instruction Handler_Box(BinaryReader reader) {
var type = resolver.ResolveToken(reader.ReadUInt32()) as ITypeDefOrRef;
var type = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as ITypeDefOrRef;
return OpCodes.Box.ToInstruction(type);
}
@ -193,17 +195,17 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
}
Instruction Handler_Call(BinaryReader reader) {
var method = resolver.ResolveToken(reader.ReadUInt32()) as IMethod;
var method = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as IMethod;
return OpCodes.Call.ToInstruction(method);
}
Instruction Handler_Callvirt(BinaryReader reader) {
var method = resolver.ResolveToken(reader.ReadUInt32()) as IMethod;
var method = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as IMethod;
return OpCodes.Callvirt.ToInstruction(method);
}
Instruction Handler_Castclass(BinaryReader reader) {
var type = resolver.ResolveToken(reader.ReadUInt32()) as ITypeDefOrRef;
var type = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as ITypeDefOrRef;
return OpCodes.Castclass.ToInstruction(type);
}
@ -312,12 +314,12 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
}
Instruction Handler_Initobj(BinaryReader reader) {
var type = resolver.ResolveToken(reader.ReadUInt32()) as ITypeDefOrRef;
var type = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as ITypeDefOrRef;
return OpCodes.Initobj.ToInstruction(type);
}
Instruction Handler_Isinst(BinaryReader reader) {
var type = resolver.ResolveToken(reader.ReadUInt32()) as ITypeDefOrRef;
var type = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as ITypeDefOrRef;
return OpCodes.Isinst.ToInstruction(type);
}
@ -349,17 +351,17 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
}
Instruction Handler_Ldfld_Ldsfld(BinaryReader reader) {
var field = resolver.ResolveToken(reader.ReadUInt32()) as IField;
var field = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as IField;
return new Instruction(null, new FieldInstructionOperand(OpCodes.Ldsfld, OpCodes.Ldfld, field));
}
Instruction Handler_Ldflda_Ldsflda(BinaryReader reader) {
var field = resolver.ResolveToken(reader.ReadUInt32()) as IField;
var field = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as IField;
return new Instruction(null, new FieldInstructionOperand(OpCodes.Ldsflda, OpCodes.Ldflda, field));
}
Instruction Handler_Ldftn(BinaryReader reader) {
var method = resolver.ResolveToken(reader.ReadUInt32()) as IMethod;
var method = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as IMethod;
return OpCodes.Ldftn.ToInstruction(method);
}
@ -384,12 +386,12 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
}
Instruction Handler_Ldtoken(BinaryReader reader) {
var member = resolver.ResolveToken(reader.ReadUInt32()) as ITokenOperand;
var member = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as ITokenOperand;
return OpCodes.Ldtoken.ToInstruction(member);
}
Instruction Handler_Ldvirtftn(BinaryReader reader) {
var method = resolver.ResolveToken(reader.ReadUInt32()) as IMethod;
var method = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as IMethod;
reader.ReadUInt32();
return OpCodes.Ldvirtftn.ToInstruction(method);
}
@ -415,12 +417,12 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
}
Instruction Handler_Newarr(BinaryReader reader) {
var type = resolver.ResolveToken(reader.ReadUInt32()) as ITypeDefOrRef;
var type = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as ITypeDefOrRef;
return OpCodes.Newarr.ToInstruction(type);
}
Instruction Handler_Newobj(BinaryReader reader) {
var method = resolver.ResolveToken(reader.ReadUInt32()) as IMethod;
var method = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as IMethod;
return OpCodes.Newobj.ToInstruction(method);
}
@ -449,7 +451,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
}
Instruction Handler_Ret(BinaryReader reader) {
var method = resolver.ResolveToken(reader.ReadUInt32()) as IMethod;
var method = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as IMethod;
return OpCodes.Ret.ToInstruction();
}
@ -478,7 +480,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
}
Instruction Handler_Stfld_Stsfld(BinaryReader reader) {
var field = resolver.ResolveToken(reader.ReadUInt32()) as IField;
var field = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as IField;
return new Instruction(null, new FieldInstructionOperand(OpCodes.Stsfld, OpCodes.Stfld, field));
}
@ -517,7 +519,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
}
Instruction Handler_Unbox_Any(BinaryReader reader) {
var type = resolver.ResolveToken(reader.ReadUInt32()) as ITypeDefOrRef;
var type = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as ITypeDefOrRef;
return OpCodes.Unbox_Any.ToInstruction(type);
}

View File

@ -75,6 +75,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
ReadOpCodeHandlerInfos(CsvmResources.CSVM2),
ReadOpCodeHandlerInfos(CsvmResources.CSVM3),
ReadOpCodeHandlerInfos(CsvmResources.CSVM4),
ReadOpCodeHandlerInfos(CsvmResources.CSVM5),
};
static IList<MethodSigInfo> ReadOpCodeHandlerInfos(byte[] data) {

View File

@ -33,11 +33,13 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
public MyDeobfuscator(ModuleDefMD module) {
cliSecureRtType = new CliSecureRtType(module);
cliSecureRtType.Find(null);
stringDecrypter = new StringDecrypter(module, cliSecureRtType.StringDecrypterMethod);
stringDecrypter = new StringDecrypter(module, cliSecureRtType.StringDecrypterInfos);
stringDecrypter.Find();
cliSecureRtType.FindStringDecrypterMethod();
stringDecrypter.Method = cliSecureRtType.StringDecrypterMethod;
staticStringInliner.Add(stringDecrypter.Method, (method, gim, args) => stringDecrypter.Decrypt((string)args[0]));
stringDecrypter.AddDecrypterInfos(cliSecureRtType.StringDecrypterInfos);
stringDecrypter.Initialize();
foreach (var info in stringDecrypter.StringDecrypterInfos)
staticStringInliner.Add(info.Method, (method, gim, args) => stringDecrypter.Decrypt((string)args[0]));
}
void RestoreMethod(Blocks blocks) {
@ -252,7 +254,8 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
if (cctor == null)
continue;
requiredFields[0] = type.FullName;
if (!new FieldTypes(type).Exactly(requiredFields))
var fieldTypes = new FieldTypes(type);
if (!fieldTypes.All(requiredFields))
continue;
cflowDeobfuscator.Deobfuscate(cctor);

View File

@ -70,7 +70,8 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
!ContainsString(method, "run under") &&
!ContainsString(method, "run with") &&
!ContainsString(method, "started under") &&
!ContainsString(method, "{0} detected"))
!ContainsString(method, "{0} detected") &&
!ContainsString(method, "{0} found"))
continue;
antiDebuggerType = type;

View File

@ -28,6 +28,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
class MethodBodyReader : MethodBodyReaderBase {
ModuleDefMD module;
ushort maxStackSize;
GenericParamContext gpContext;
public MethodBodyReader(ModuleDefMD module, IBinaryReader reader)
: base(reader) {
@ -35,6 +36,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
}
public void Read(MethodDef method) {
this.gpContext = GenericParamContext.Create(method);
this.parameters = method.Parameters;
SetLocals(GetLocals(method));
@ -58,15 +60,15 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
}
protected override IField ReadInlineField(Instruction instr) {
return module.ResolveToken(reader.ReadUInt32()) as IField;
return module.ResolveToken(reader.ReadUInt32(), gpContext) as IField;
}
protected override IMethod ReadInlineMethod(Instruction instr) {
return module.ResolveToken(reader.ReadUInt32()) as IMethod;
return module.ResolveToken(reader.ReadUInt32(), gpContext) as IMethod;
}
protected override MethodSig ReadInlineSig(Instruction instr) {
var sas = module.ResolveStandAloneSig(MDToken.ToRID(reader.ReadUInt32()));
var sas = module.ResolveStandAloneSig(MDToken.ToRID(reader.ReadUInt32()), gpContext);
return sas == null ? null : sas.MethodSig;
}
@ -75,11 +77,11 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
}
protected override ITokenOperand ReadInlineTok(Instruction instr) {
return module.ResolveToken(reader.ReadUInt32()) as ITokenOperand;
return module.ResolveToken(reader.ReadUInt32(), gpContext) as ITokenOperand;
}
protected override ITypeDefOrRef ReadInlineType(Instruction instr) {
return module.ResolveToken(reader.ReadUInt32()) as ITypeDefOrRef;
return module.ResolveToken(reader.ReadUInt32(), gpContext) as ITypeDefOrRef;
}
void ReadExceptionHandlers(int numExceptionHandlers) {
@ -101,7 +103,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
switch (eh.HandlerType) {
case ExceptionHandlerType.Catch:
eh.CatchType = module.ResolveToken(reader.ReadUInt32()) as ITypeDefOrRef;
eh.CatchType = module.ResolveToken(reader.ReadUInt32(), gpContext) as ITypeDefOrRef;
break;
case ExceptionHandlerType.Filter:

View File

@ -110,7 +110,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
MethodDef GetProxyCreateMethod(TypeDef type) {
if (DotNetUtils.FindFieldType(type, "System.ModuleHandle", true) == null)
return null;
if (type.Fields.Count < 1 || type.Fields.Count > 18)
if (type.Fields.Count < 1 || type.Fields.Count > 20)
return null;
MethodDef createMethod = null;

View File

@ -157,7 +157,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
foreach (var method in GetDecrypterMethods(type)) {
if (method == null)
continue;
if (!new LocalTypes(method).Exactly(requiredLocals_sl))
if (!new LocalTypes(method).All(requiredLocals_sl))
continue;
resourceDecrypterType = type;
@ -180,6 +180,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
}
static bool CheckFlipBits(MethodDef method) {
int nots = 0;
var instrs = method.Body.Instructions;
for (int i = 0; i < instrs.Count - 1; i++) {
var ldloc = instrs[i];
@ -189,14 +190,11 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
if (local == null || local.Type.GetElementType().GetPrimitiveSize() < 0)
continue;
var not = instrs[i + 1];
if (not.OpCode.Code != Code.Not)
continue;
return true;
if (instrs[i + 1].OpCode.Code == Code.Not)
nots++;
}
return false;
return (nots & 1) == 1;
}
bool UpdateFlags(MethodDef method, ISimpleDeobfuscator simpleDeobfuscator) {

View File

@ -84,7 +84,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
if (!method.IsStatic || !DotNetUtils.IsMethod(method, "System.Void", "()"))
return false;
if (type.Methods.Count < 3 || type.Methods.Count > 27)
if (type.Methods.Count < 3 || type.Methods.Count > 31)
return false;
if (DotNetUtils.GetPInvokeMethod(type, "mscoree", "StrongNameSignatureVerificationEx") != null) {
}

View File

@ -25,7 +25,7 @@ namespace de4dot.code.deobfuscators.Dotfuscator {
public class DeobfuscatorInfo : DeobfuscatorInfoBase {
public const string THE_NAME = "Dotfuscator";
public const string THE_TYPE = "df";
const string DEFAULT_REGEX = @"!^[a-z][a-z0-9]{0,2}$&!^A_[0-9]+$&" + DeobfuscatorBase.DEFAULT_ASIAN_VALID_NAME_REGEX;
const string DEFAULT_REGEX = @"!^(?:eval_)?[a-z][a-z0-9]{0,2}$&!^A_[0-9]+$&" + DeobfuscatorBase.DEFAULT_ASIAN_VALID_NAME_REGEX;
public DeobfuscatorInfo()
: base(DEFAULT_REGEX) {
}

View File

@ -31,8 +31,10 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET {
public const int MSG_CALL_MOVE_NEXT = 4;
Module reflObfModule;
IEnumerable<int> ienumerable = null;
IEnumerator<int> ienumerator = null;
object ienumerable = null;
object ienumerator = null;
MethodInfo mi_get_Current;
MethodInfo mi_MoveNext;
[CreateUserGenericService]
public static IUserGenericService Create() {
@ -72,7 +74,7 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET {
var ctor = reflObfModule.ResolveMethod((int)ctorToken) as ConstructorInfo;
if (ctor == null)
throw new ApplicationException(string.Format("Invalid ctor with token: {0:X8}", ctorToken));
ienumerable = (IEnumerable<int>)ctor.Invoke(args);
ienumerable = ctor.Invoke(args);
}
void WriteEnumerableField(uint fieldToken, object value) {
@ -83,15 +85,74 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET {
}
void CreateEnumerator() {
ienumerator = ienumerable.GetEnumerator();
foreach (var method in ienumerable.GetType().GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) {
if (method.GetParameters().Length != 0)
continue;
var retType = method.ReturnType;
if (!retType.IsGenericType)
continue;
var genArgs = retType.GetGenericArguments();
if (genArgs.Length != 1)
continue;
if (genArgs[0] != typeof(int))
continue;
if (!FindEnumeratorMethods(retType))
continue;
ienumerator = method.Invoke(ienumerable, null);
return;
}
throw new ApplicationException("No GetEnumerator() method found");
}
bool FindEnumeratorMethods(Type type) {
mi_get_Current = null;
mi_MoveNext = null;
foreach (var method in ienumerable.GetType().GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) {
if (Is_get_Current(method)) {
if (mi_get_Current != null)
return false;
mi_get_Current = method;
continue;
}
if (Is_MoveNext(method)) {
if (mi_MoveNext != null)
return false;
mi_MoveNext = method;
continue;
}
}
return mi_get_Current != null && mi_MoveNext != null;
}
static bool Is_get_Current(MethodInfo method) {
if (method.GetParameters().Length != 0)
return false;
if (method.ReturnType != typeof(int))
return false;
return true;
}
static bool Is_MoveNext(MethodInfo method) {
if (method.GetParameters().Length != 0)
return false;
if (method.ReturnType != typeof(bool))
return false;
return true;
}
int CallGetCurrent() {
return ienumerator.Current;
return (int)mi_get_Current.Invoke(ienumerator, null);
}
bool CallMoveNext() {
return ienumerator.MoveNext();
return (bool)mi_MoveNext.Invoke(ienumerator, null);
}
public void Dispose() {

View File

@ -80,7 +80,7 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET {
}
public int? ValidStringDecrypterValue {
get { return validStringDecrypterValue;}
get { return validStringDecrypterValue; }
}
public TypeDef Type {
@ -696,8 +696,8 @@ done: ;
if (initValue2 == null || !initValue2.AllBitsValid())
return false;
int loopStart = GetIndexOfCall(instrs, index, leaveIndex, "System.Int32 System.Collections.Generic.IEnumerator`1<System.Int32>::get_Current()");
int loopEnd = GetIndexOfCall(instrs, loopStart, leaveIndex, "System.Boolean System.Collections.IEnumerator::MoveNext()");
int loopStart = GetIndexOfCall(instrs, index, leaveIndex, "System.Int32", "()");
int loopEnd = GetIndexOfCall(instrs, loopStart, leaveIndex, "System.Boolean", "()");
if (loopStart < 0 || loopEnd < 0)
return false;
loopStart++;
@ -720,7 +720,7 @@ done: ;
return true;
}
static int GetIndexOfCall(IList<Instruction> instrs, int startIndex, int endIndex, string fullMethodName) {
static int GetIndexOfCall(IList<Instruction> instrs, int startIndex, int endIndex, string returnType, string parameters) {
if (startIndex < 0 || endIndex < 0)
return -1;
for (int i = startIndex; i < endIndex; i++) {
@ -728,7 +728,7 @@ done: ;
if (instr.OpCode.Code != Code.Call && instr.OpCode.Code != Code.Callvirt)
continue;
var method = instr.Operand as IMethod;
if (method == null || method.FullName != fullMethodName)
if (!DotNetUtils.IsMethod(method, returnType, parameters))
continue;
return i;

View File

@ -722,13 +722,85 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET {
decryptStringMethod.Body.ExceptionHandlers.Count >= 2 &&
new LocalTypes(decryptStringMethod).All(locals35) &&
CheckTypeFields2(fields35)) {
return "3.5 - 4.1";
return "3.5 - 4.2";
}
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
var fields43 = new string[] {
GetNestedTypeName(0),
GetNestedTypeName(1),
"System.Byte[]",
"System.Int16",
"System.Int32",
"System.Byte[]",
"System.Int32",
"System.Int32",
GetNestedTypeName(2),
};
var locals43 = CreateLocalsArray(
"System.Boolean",
"System.Byte",
"System.Byte[]",
"System.Char[]",
FindEnumeratorName(decryptStringMethod),
GetNestedTypeName(0),
"System.Diagnostics.StackFrame",
"System.Diagnostics.StackTrace",
"System.Int16",
"System.Int32",
"System.Int64",
"System.IO.Stream",
"System.Reflection.Assembly",
"System.Reflection.AssemblyName",
"System.Reflection.MethodBase",
"System.String",
"System.Text.StringBuilder",
"System.Type"
);
var olocals43 = CreateLocalsArray(
"System.Int32"
);
if (otherMethods.Count == 1 &&
decryptStringType.NestedTypes.Count == 3 &&
DotNetUtils.IsMethod(otherMethods[0], "System.Void", "(System.Byte[],System.Int32,System.Byte[])") &&
otherMethods[0].IsPrivate &&
otherMethods[0].IsStatic &&
new LocalTypes(otherMethods[0]).Exactly(olocals43) &&
decryptStringMethod.IsNoInlining &&
decryptStringMethod.IsAssembly &&
!decryptStringMethod.IsSynchronized &&
decryptStringMethod.Body.MaxStack >= 1 &&
decryptStringMethod.Body.MaxStack <= 8 &&
decryptStringMethod.Body.ExceptionHandlers.Count >= 2 &&
new LocalTypes(decryptStringMethod).All(locals43) &&
CheckTypeFields2(fields43)) {
return "4.3";
}
}
return null;
}
static string FindEnumeratorName(MethodDef method) {
foreach (var local in method.Body.Variables) {
var gis = local.Type as GenericInstSig;
if (gis == null)
continue;
if (gis.FullName == "System.Collections.Generic.IEnumerator`1<System.Int32>")
continue;
if (gis.GenericArguments.Count != 1)
continue;
if (gis.GenericArguments[0].GetFullName() != "System.Int32")
continue;
return gis.FullName;
}
return null;
}
TypeDef GetNestedType(int n) {
var type = stringDecrypter.Type;

View File

@ -57,7 +57,7 @@ namespace de4dot.code.deobfuscators.Goliath_NET {
}
public TypeDef DelegateInitType {
get { return delegateInitType ?? FindDelegateInitType();}
get { return delegateInitType ?? FindDelegateInitType(); }
}
public TypeDef DelegateType {

View File

@ -28,7 +28,7 @@ namespace de4dot.code.deobfuscators.Goliath_NET {
MethodDef strongNameCheckMethod;
public bool Detected {
get { return strongNameType != null;}
get { return strongNameType != null; }
}
public TypeDef Type {

View File

@ -122,7 +122,6 @@ namespace de4dot.code.deobfuscators.ILProtector {
bool emailMe = false;
foreach (var info in mainType.RuntimeFileInfos) {
var version = info.GetVersion();
emailMe |= version == null && System.IO.File.Exists(info.PathName);
emailMe |= version != null && version == new Version(1, 0, 7, 0);
Logger.v("Version: {0} ({1})", version == null ? "UNKNOWN" : version.ToString(), info.PathName);
}

View File

@ -40,6 +40,50 @@ namespace de4dot.code.deobfuscators.ILProtector {
IDecrypter decrypter;
bool methodReaderHasDelegateTypeFlag;
static class CodeAllocator {
[DllImport("kernel32")]
static extern IntPtr VirtualAlloc(IntPtr lpAddress, UIntPtr dwSize, uint flAllocationType, uint flProtect);
const uint PAGE_EXECUTE_READWRITE = 0x40;
const uint MEM_COMMIT = 0x00001000;
const int ALIGNMENT = 0x10;
static IntPtr currentPage;
static int nextOffset;
static int pageSize;
public static IntPtr Allocate(byte[] code) {
if (code == null || code.Length == 0)
return IntPtr.Zero;
var addr = Allocate(code.Length);
Marshal.Copy(code, 0, addr, code.Length);
return addr;
}
public static IntPtr Allocate(int size) {
if (size <= 0)
return IntPtr.Zero;
size = (size + ALIGNMENT - 1) & ~(ALIGNMENT - 1);
if (nextOffset + size > pageSize)
AllocNewPage(size);
var data = new IntPtr(currentPage.ToInt64() + nextOffset);
nextOffset += size;
return data;
}
static void AllocNewPage(int size) {
size = (size + 0xFFF) & ~0xFFF;
currentPage = VirtualAlloc(IntPtr.Zero, new UIntPtr((uint)size), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (currentPage == IntPtr.Zero)
throw new ApplicationException("VirtualAlloc() failed");
pageSize = size;
nextOffset = 0;
}
}
interface IDecrypter {
byte[] Decrypt(int methodId, uint rid);
}
@ -323,7 +367,7 @@ namespace de4dot.code.deobfuscators.ILProtector {
pDecryptCallback = new IntPtr(p + IntPtr.Size * 40);
}
IntPtr GetStateAddr(object obj) {
public static IntPtr GetStateAddr(object obj) {
var flags = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
foreach (var fi in obj.GetType().GetFields(flags)) {
if (fi.FieldType == typeof(IntPtr))
@ -335,7 +379,6 @@ namespace de4dot.code.deobfuscators.ILProtector {
public byte[] Decrypt(int methodId, uint rid) {
decryptedData = null;
currentILBytes = dmd.reflectionModule.ResolveMethod(0x06000000 + (int)rid).GetMethodBody().GetILAsByteArray();
invoker.DynamicInvoke(new object[1] { methodId });
return decryptedData;
}
@ -358,7 +401,7 @@ namespace de4dot.code.deobfuscators.ILProtector {
public unsafe DecrypterV2_0_12_0(DynamicMethodsDecrypter dmd)
: base(dmd) {
getCallerMethodAsILByteArrayDelegate = GetCallerMethodAsILByteArray;
decryptCallbackDelegate = MyDecryptCallback;
decryptCallbackDelegate = DecryptCallback;
*(IntPtr*)pGetILBytes = Marshal.GetFunctionPointerForDelegate(getCallerMethodAsILByteArrayDelegate);
*(IntPtr*)pDecryptCallback = Marshal.GetFunctionPointerForDelegate(decryptCallbackDelegate);
@ -368,7 +411,7 @@ namespace de4dot.code.deobfuscators.ILProtector {
return currentILBytes;
}
unsafe bool MyDecryptCallback(IntPtr a, byte* pMethodCode, int methodSize, int methodId) {
unsafe bool DecryptCallback(IntPtr a, byte* pMethodCode, int methodSize, int methodId) {
SaveDecryptedData(pMethodCode, methodSize);
return true;
}
@ -386,7 +429,7 @@ namespace de4dot.code.deobfuscators.ILProtector {
public unsafe DecrypterV2_0_12_3(DynamicMethodsDecrypter dmd)
: base(dmd) {
getCallerMethodAsILByteArrayDelegate = GetCallerMethodAsILByteArray;
decryptCallbackDelegate = MyDecryptCallback;
decryptCallbackDelegate = DecryptCallback;
*(IntPtr*)pGetILBytes = Marshal.GetFunctionPointerForDelegate(getCallerMethodAsILByteArrayDelegate);
*(IntPtr*)pDecryptCallback = Marshal.GetFunctionPointerForDelegate(decryptCallbackDelegate);
@ -396,12 +439,176 @@ namespace de4dot.code.deobfuscators.ILProtector {
return currentILBytes;
}
unsafe bool MyDecryptCallback(IntPtr a, byte* pMethodCode, int methodSize, int methodId, IntPtr e) {
unsafe bool DecryptCallback(IntPtr a, byte* pMethodCode, int methodSize, int methodId, IntPtr e) {
SaveDecryptedData(pMethodCode, methodSize);
return true;
}
}
abstract class DecrypterV2_0_13_0_Base : IDecrypter {
protected readonly DynamicMethodsDecrypter dmd;
protected byte[] currentILBytes;
byte[] decryptedData;
readonly Delegate invoker;
readonly GetCallerMethodAsILByteArrayDelegate getCallerMethodAsILByteArrayDelegate;
readonly DecryptCallbackDelegate decryptCallbackDelegate;
readonly IgnoreDelegate ignoreDelegate;
[DllImport("kernel32")]
static extern bool GetModuleHandleEx(uint dwFlags, IntPtr lpModuleName, out IntPtr phModule);
[return: MarshalAs(UnmanagedType.SafeArray)]
delegate byte[] GetCallerMethodAsILByteArrayDelegate(IntPtr a, int skipFrames, ref int flags, IntPtr d);
unsafe delegate bool DecryptCallbackDelegate(IntPtr a, byte* pMethodCode, int methodSize, int methodId, IntPtr e);
delegate IntPtr IgnoreDelegate(IntPtr a, IntPtr b);
public unsafe DecrypterV2_0_13_0_Base(DynamicMethodsDecrypter dmd) {
this.dmd = dmd;
this.invoker = (Delegate)dmd.invokerFieldInfo.GetValue(null);
byte* p = (byte*)DecrypterBaseV2_0_12_x.GetStateAddr(invoker.Target);
byte* pis = GetAddr(*(byte**)p);
p = *(byte**)pis;
byte* pam = *(byte**)(p + IntPtr.Size * 2);
p = *(byte**)(p + ((Environment.Version.Major - 2) / 2 * IntPtr.Size));
p += IntPtr.Size * 8 + 0x18;
p = LookUp(p, AppDomain.CurrentDomain.Id);
p = *(byte**)(p + IntPtr.Size * 16 + 0x18);
byte* pd = p + IntPtr.Size * 2;
p = *(byte**)(p + IntPtr.Size * 13);
getCallerMethodAsILByteArrayDelegate = GetCallerMethodAsILByteArray;
decryptCallbackDelegate = DecryptCallback;
ignoreDelegate = IgnoreMethod;
byte* pm = p + 0x28 * IntPtr.Size;
*(IntPtr*)(p + 0x29 * IntPtr.Size) = Marshal.GetFunctionPointerForDelegate(getCallerMethodAsILByteArrayDelegate);
*(IntPtr*)(p + 0x2A * IntPtr.Size) = Marshal.GetFunctionPointerForDelegate(decryptCallbackDelegate);
if (IntPtr.Size == 4)
*(IntPtr*)(p + 0x2B * IntPtr.Size) = Marshal.GetFunctionPointerForDelegate(ignoreDelegate);
InitCode(GetModuleHandle(pis), pam, pd, pm);
}
static unsafe byte* GetModuleHandle(byte* addr) {
IntPtr hModule;
if (!GetModuleHandleEx(4, new IntPtr(addr), out hModule))
throw new ApplicationException("GetModuleHandleEx() failed");
return (byte*)hModule;
}
protected unsafe abstract void InitCode(byte* ba, byte* pam, byte* pd, byte* pm);
static unsafe byte* GetAddr(byte* p) {
if (IntPtr.Size == 4) {
for (int i = 0; i < 20; i++, p++) {
if (*p == 0xA1)
return *(byte**)(p + 1);
}
}
else {
for (int i = 0; i < 20; i++, p++)
if (*p == 0x4C && p[1] == 0x8B && p[2] == 0x15)
return p + 7 + *(int*)(p + 3);
}
return null;
}
static unsafe byte* LookUp(byte* p, int key) {
p = *(byte**)(p + IntPtr.Size);
p = *(byte**)(p + IntPtr.Size);
int f1 = 0;
int f2 = IntPtr.Size * 2;
int f3 = IntPtr.Size * 3;
int f4 = IntPtr.Size * 4;
int f5 = IntPtr.Size * 5 + 1;
byte* res = null;
while (true) {
if (*(p + f5) != 0)
break;
int k = *(int*)(p + f3);
if (k < key)
p = *(byte**)(p + f2);
else {
res = p;
p = *(byte**)(p + f1);
}
}
return *(byte**)(res + f4);
}
byte[] aryDummy = new byte[7];
IntPtr dummy;
public unsafe byte[] Decrypt(int methodId, uint rid) {
fixed (byte* p = &aryDummy[0]) {
dummy = new IntPtr(p);
decryptedData = null;
currentILBytes = dmd.reflectionModule.ResolveMethod(0x06000000 + (int)rid).GetMethodBody().GetILAsByteArray();
invoker.DynamicInvoke(new object[1] { methodId });
}
dummy = IntPtr.Zero;
return decryptedData;
}
byte[] GetCallerMethodAsILByteArray(IntPtr a, int skipFrames, ref int flags, IntPtr d) {
flags = 2;
return currentILBytes;
}
unsafe bool DecryptCallback(IntPtr a, byte* pMethodCode, int methodSize, int methodId, IntPtr e) {
decryptedData = new byte[methodSize];
Marshal.Copy(new IntPtr(pMethodCode), decryptedData, 0, decryptedData.Length);
return true;
}
IntPtr IgnoreMethod(IntPtr a, IntPtr b) {
return dummy;
}
}
class DecrypterV2_0_13_0 : DecrypterV2_0_13_0_Base {
public unsafe DecrypterV2_0_13_0(DynamicMethodsDecrypter dmd)
: base(dmd) {
}
static readonly byte[] initCode_x86 = new byte[] {
0x8B, 0xCC, 0x8B, 0x41, 0x04, 0xFF, 0x71, 0x10,
0xFF, 0x71, 0x0C, 0xFF, 0x71, 0x08, 0xFF, 0x51,
0x14, 0xC2, 0x14, 0x00,
};
unsafe delegate void InitCode32Delegate(byte* pppam, byte* m, IntPtr s, byte* pd, byte* f);
unsafe delegate void InitCode64Delegate(byte* pppam, byte* m, IntPtr s, byte* pd);
protected unsafe override void InitCode(byte* ba, byte* pam, byte* pd, byte* pm) {
byte* ppam = (byte*)&pam;
byte* pppam = (byte*)&ppam;
if (IntPtr.Size == 4) {
var del = (InitCode32Delegate)Marshal.GetDelegateForFunctionPointer(CodeAllocator.Allocate(initCode_x86), typeof(InitCode32Delegate));
del(pppam, pm, new IntPtr(IntPtr.Size * 4), pd, ba + 0x00012500);
}
else {
var del = (InitCode64Delegate)Marshal.GetDelegateForFunctionPointer(new IntPtr(ba + 0x00014CF0), typeof(InitCode64Delegate));
del(pppam, pm, new IntPtr(IntPtr.Size * 4), pd);
}
}
}
class DecrypterV2_0_13_1 : DecrypterV2_0_13_0_Base {
public unsafe DecrypterV2_0_13_1(DynamicMethodsDecrypter dmd)
: base(dmd) {
}
unsafe delegate void InitCodeDelegate(byte* pppam, byte* m, IntPtr s, byte* pd);
protected unsafe override void InitCode(byte* ba, byte* pam, byte* pd, byte* pm) {
int rva = IntPtr.Size == 4 ? 0x00013650 : 0x00016B50;
var del = (InitCodeDelegate)Marshal.GetDelegateForFunctionPointer(new IntPtr(ba + rva), typeof(InitCodeDelegate));
byte* ppam = (byte*)&pam;
byte* pppam = (byte*)&ppam;
del(pppam, pm, new IntPtr(IntPtr.Size * 4), pd);
}
}
public bool MethodReaderHasDelegateTypeFlag {
get { return methodReaderHasDelegateTypeFlag; }
}
@ -456,9 +663,13 @@ namespace de4dot.code.deobfuscators.ILProtector {
methodReaderHasDelegateTypeFlag = true;
if (version < new Version(2, 0, 12, 3))
return CreateDecrypterV2_0_12_0();
if (version < new Version(2, 0, 12, 4))
return CreateDecrypterV2_0_12_3();
return new DecrypterV2_0_12_0(this);
if (version == new Version(2, 0, 12, 3))
return new DecrypterV2_0_12_3(this);
if (version == new Version(2, 0, 13, 0))
return new DecrypterV2_0_13_0(this);
if (version == new Version(2, 0, 13, 1))
return new DecrypterV2_0_13_1(this);
return null;
}
@ -503,14 +714,6 @@ namespace de4dot.code.deobfuscators.ILProtector {
return new DecrypterV2_0_9_0(this, delegateField);
}
IDecrypter CreateDecrypterV2_0_12_0() {
return new DecrypterV2_0_12_0(this);
}
IDecrypter CreateDecrypterV2_0_12_3() {
return new DecrypterV2_0_12_3(this);
}
static readonly byte[] ilpPublicKeyToken = new byte[8] { 0x20, 0x12, 0xD3, 0xC0, 0x55, 0x1F, 0xE0, 0x3D };
static Assembly GetProtectAssembly() {
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) {

View File

@ -32,6 +32,7 @@ namespace de4dot.code.deobfuscators.ILProtector {
MethodFlags flags;
TypeDef delegateType;
bool hasDelegateTypeFlag;
GenericParamContext gpContext;
[Flags]
enum MethodFlags {
@ -76,7 +77,8 @@ namespace de4dot.code.deobfuscators.ILProtector {
this.module = module;
}
public void Read() {
public void Read(MethodDef method) {
gpContext = GenericParamContext.Create(method);
flags = (MethodFlags)reader.ReadByte();
if (HasDelegateType) {
delegateType = Resolve<TypeDef>(ReadTypeToken());
@ -108,7 +110,7 @@ namespace de4dot.code.deobfuscators.ILProtector {
}
T Resolve<T>(int token) {
return (T)module.ResolveToken(token);
return (T)module.ResolveToken(token, gpContext);
}
int ReadTypeToken() {
@ -182,7 +184,7 @@ namespace de4dot.code.deobfuscators.ILProtector {
var token = reader.ReadUInt32();
if (MDToken.ToTable(token) != Table.StandAloneSig)
return null;
var sas = module.ResolveStandAloneSig(MDToken.ToRID(token));
var sas = module.ResolveStandAloneSig(MDToken.ToRID(token), gpContext);
return sas == null ? null : sas.MethodSig;
}

View File

@ -87,7 +87,7 @@ namespace de4dot.code.deobfuscators.ILProtector {
methodInfos.Remove(methodId.Value);
var methodReader = new MethodReader(module, methodInfo.data, parameters);
methodReader.HasDelegateTypeFlag = MethodReaderHasDelegateTypeFlag;
methodReader.Read();
methodReader.Read(method);
RestoreMethod(method, methodReader);
if (methodReader.DelegateType != null)

View File

@ -64,6 +64,8 @@ namespace de4dot.code.deobfuscators.ILProtector {
new VersionInfo(new Version(2, 0, 12, 0), new byte[] { 0x63, 0x8B, 0x5C, 0xE9, 0x89, 0x83, 0x57, 0x9D, 0xDC, 0xC3, 0xBD, 0xD9, 0xDB, 0x54, 0xBE, 0x66 }),
new VersionInfo(new Version(2, 0, 12, 2), new byte[] { 0xD5, 0x46, 0x38, 0xC7, 0x48, 0xF6, 0x3C, 0x1C, 0x1E, 0x7F, 0x3B, 0x7B, 0x5B, 0xE0, 0x49, 0x46 }),
new VersionInfo(new Version(2, 0, 12, 3), new byte[] { 0x35, 0xA3, 0x53, 0xE9, 0x9E, 0x30, 0x6E, 0x9C, 0x0F, 0x46, 0x20, 0x9A, 0x91, 0xD2, 0x95, 0x18 }),
new VersionInfo(new Version(2, 0, 13, 0), new byte[] { 0x66, 0x21, 0xA1, 0x1F, 0x8F, 0x4A, 0xD2, 0xF8, 0x68, 0xEE, 0xD5, 0xD9, 0xC8, 0xB8, 0x17, 0xC7 }),
new VersionInfo(new Version(2, 0, 13, 1), new byte[] { 0xDF, 0x7A, 0xBF, 0x8B, 0xAD, 0x2B, 0x94, 0x6F, 0x37, 0xD9, 0x4B, 0xFC, 0x42, 0x7F, 0x0B, 0x37 }),
};
static readonly VersionInfo[] versionInfo64 = new VersionInfo[] {
@ -89,6 +91,8 @@ namespace de4dot.code.deobfuscators.ILProtector {
new VersionInfo(new Version(2, 0, 12, 0), new byte[] { 0x5F, 0x42, 0xA5, 0x6C, 0x19, 0xC6, 0x73, 0x9E, 0xE6, 0x74, 0x62, 0x3B, 0x8A, 0x51, 0xBB, 0x93 }),
new VersionInfo(new Version(2, 0, 12, 2), new byte[] { 0x10, 0x91, 0xED, 0x05, 0x9C, 0x31, 0x0B, 0x63, 0x76, 0xD7, 0x4A, 0xEC, 0xDE, 0x99, 0x6D, 0xD0 }),
new VersionInfo(new Version(2, 0, 12, 3), new byte[] { 0x38, 0x86, 0xE0, 0xBF, 0xC6, 0x64, 0xB9, 0xA0, 0x07, 0xED, 0xDB, 0x02, 0x40, 0xD0, 0x57, 0xE8 }),
new VersionInfo(new Version(2, 0, 13, 0), new byte[] { 0xF0, 0x13, 0xC4, 0x6F, 0x31, 0x0F, 0x61, 0xEA, 0x89, 0x1E, 0x8A, 0x95, 0x8C, 0xBE, 0x2E, 0x44 }),
new VersionInfo(new Version(2, 0, 13, 1), new byte[] { 0xD4, 0x71, 0x75, 0xE2, 0xB1, 0xA5, 0xAE, 0xF5, 0x32, 0xD7, 0x72, 0xDE, 0x93, 0xDC, 0x0B, 0x68 }),
};
public RuntimeFileInfo(MethodDef protectMethod) {

View File

@ -112,6 +112,11 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
},
// 526BC020
// 526BDD12
// 5296E242
// 52B2B2A3
// 52B3043C
// 53172907
// 531729C4
new EncryptionInfo {
MagicLo = 0x9A683B87,
MagicHi = 0x928ECDA3,
@ -177,6 +182,11 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
// 5166DB4F
// 526BC020
// 526BDD12
// 5296E242
// 52B2B2A3
// 52B3043C
// 53172907
// 531729C4
new EncryptionInfo {
MagicLo = 0x1A731B13,
MagicHi = 0x1723891F,

View File

@ -194,6 +194,10 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
decrypters.Add(new Decrypter(new DecryptFunc[] { Decrypt4_v5, Decrypt2_v2, Decrypt3_v6, Decrypt1_v9, Decrypt6, Decrypt8_v8, Decrypt9_v9, Decrypt7, Decrypt5 }, new uint[] { 0x513D4492, 0x5113E277 }));
decrypters.Add(new Decrypter(new DecryptFunc[] { Decrypt3_v6, Decrypt2_v2, Decrypt4_v8, Decrypt1_v10, Decrypt8_v9, Decrypt9_v10, Decrypt6, Decrypt7, Decrypt5 }, new uint[] { 0x526BDD12 }));
decrypters.Add(new Decrypter(new DecryptFunc[] { Decrypt1_v10, Decrypt4_v8, Decrypt2_v2, Decrypt3_v6, Decrypt6, Decrypt8_v9, Decrypt9_v10, Decrypt7, Decrypt5 }, new uint[] { 0x526BC020 }));
decrypters.Add(new Decrypter(new DecryptFunc[] { Decrypt3_v7, Decrypt2_v6, Decrypt4_v9, Decrypt1_v11, Decrypt8_v10, Decrypt11_v1, Decrypt6, Decrypt7, Decrypt5 }, new uint[] { 0x5296E242, 0x52B3043C }));
decrypters.Add(new Decrypter(new DecryptFunc[] { Decrypt4_v10, Decrypt1_v12, Decrypt3_v8, Decrypt2_v7, Decrypt6, Decrypt8_v11, Decrypt9_v11, Decrypt7, Decrypt5 }, new uint[] { 0x531729C4 }));
decrypters.Add(new Decrypter(new DecryptFunc[] { Decrypt1_v13, Decrypt4_v11, Decrypt2_v8, Decrypt3_v9, Decrypt6, Decrypt8_v11, Decrypt9_v12, Decrypt7, Decrypt5 }, new uint[] { 0x52B2B2A3 }));
decrypters.Add(new Decrypter(new DecryptFunc[] { Decrypt2_v9, Decrypt3_v10, Decrypt1_v10, Decrypt4_v12, Decrypt8_v12, Decrypt9_v13, Decrypt6, Decrypt7, Decrypt5 }, new uint[] { 0x53172907 }));
break;
case EncryptionVersion.Unknown:
@ -404,6 +408,18 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
return Decrypt1(encrypted, 0x11, 0x11, 0x400);
}
byte[] Decrypt1_v11(byte[] encrypted) {
return Decrypt1(encrypted, 0x13, 0x13, 0x400);
}
byte[] Decrypt1_v12(byte[] encrypted) {
return Decrypt1(encrypted, 0x12, 0x12, 0x200);
}
byte[] Decrypt1_v13(byte[] encrypted) {
return Decrypt1(encrypted, 0x11, 0x11, 0x200);
}
byte[] Decrypt1(byte[] encrypted, int keyStart, int keyReset, int keyEnd) {
var decrypted = new byte[encrypted.Length];
for (int i = 0, ki = keyStart; i < decrypted.Length; i++) {
@ -434,6 +450,22 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
return Decrypt2(encrypted, 0x00FA + 0x63);
}
byte[] Decrypt2_v6(byte[] encrypted) {
return Decrypt2(encrypted, 0x00FA + 0x0B);
}
byte[] Decrypt2_v7(byte[] encrypted) {
return Decrypt2(encrypted, 0x00FA + 0x0E);
}
byte[] Decrypt2_v8(byte[] encrypted) {
return Decrypt2(encrypted, 0x00FA + 0x0D);
}
byte[] Decrypt2_v9(byte[] encrypted) {
return Decrypt2(encrypted, 0x00FA + 0x0C);
}
byte[] Decrypt2(byte[] encrypted, int offset) {
if ((encrypted.Length & 7) != 0)
throw new ApplicationException("Invalid encryption #2 length");
@ -481,6 +513,22 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
return Decrypt3(encrypted, 0x015E + 0x7F);
}
byte[] Decrypt3_v7(byte[] encrypted) {
return Decrypt3(encrypted, 0x015E + 0x0D);
}
byte[] Decrypt3_v8(byte[] encrypted) {
return Decrypt3(encrypted, 0x015E + 0x0F);
}
byte[] Decrypt3_v9(byte[] encrypted) {
return Decrypt3(encrypted, 0x015E + 0x12);
}
byte[] Decrypt3_v10(byte[] encrypted) {
return Decrypt3(encrypted, 0x015E + 0x0E);
}
static readonly byte[] decrypt3Shifts = new byte[16] { 5, 11, 14, 21, 6, 20, 17, 29, 4, 10, 3, 2, 7, 1, 26, 18 };
byte[] Decrypt3(byte[] encrypted, int offset) {
if ((encrypted.Length & 7) != 0)
@ -542,6 +590,22 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
return Decrypt4(encrypted, 9, 9, 0x100);
}
byte[] Decrypt4_v9(byte[] encrypted) {
return Decrypt4(encrypted, 0x0B, 0x0B, 0x150);
}
byte[] Decrypt4_v10(byte[] encrypted) {
return Decrypt4(encrypted, 0x10, 0x10, 0x120);
}
byte[] Decrypt4_v11(byte[] encrypted) {
return Decrypt4(encrypted, 0x0F, 0x0E, 0x120);
}
byte[] Decrypt4_v12(byte[] encrypted) {
return Decrypt4(encrypted, 0x0C, 0x0C, 0x150);
}
byte[] Decrypt4(byte[] encrypted, int keyStart, int keyReset, int keyEnd) {
var decrypted = new byte[encrypted.Length / 3 * 2 + 1];
@ -599,6 +663,18 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
return Decrypt8(encrypted, 0xA, 0xA, 0x600);
}
byte[] Decrypt8_v10(byte[] encrypted) {
return Decrypt8(encrypted, 0x14, 0x14, 0x600);
}
byte[] Decrypt8_v11(byte[] encrypted) {
return Decrypt8(encrypted, 0x19, 0x19, 0x500);
}
byte[] Decrypt8_v12(byte[] encrypted) {
return Decrypt8(encrypted, 0x14, 0x14, 0x600);
}
byte[] Decrypt8(byte[] encrypted, int keyStart, int keyReset, int keyEnd) {
var decrypted = new byte[encrypted.Length];
int ki = keyStart;
@ -636,6 +712,18 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
return Decrypt9(encrypted, 5, 5, 0x510);
}
byte[] Decrypt9_v11(byte[] encrypted) {
return Decrypt9(encrypted, 0x19, 0x19, 0x500);
}
byte[] Decrypt9_v12(byte[] encrypted) {
return Decrypt9(encrypted, 0x19, 0x19, 0x500);
}
byte[] Decrypt9_v13(byte[] encrypted) {
return Decrypt9(encrypted, 5, 5, 0x510);
}
byte[] Decrypt9(byte[] encrypted, int keyStart, int keyReset, int keyEnd) {
var decrypted = new byte[encrypted.Length];
int ki = keyStart;
@ -695,6 +783,38 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
return dest;
}
byte[] Decrypt11_v1(byte[] encrypted) {
return Decrypt11(encrypted, 5, 5, 0x510);
}
byte[] Decrypt11(byte[] encrypted, int keyStart, int keyReset, int keyEnd) {
byte[] dest = new byte[encrypted.Length];
for (int i = 0, ki = keyStart; i < encrypted.Length; i++, ki++) {
if (ki >= keyEnd)
ki = keyStart;
byte b;
switch (i % 3) {
case 0:
dest[i] = (byte)(encrypted[i] ^ mcKey.ReadByte(ki));
break;
case 1:
b = (byte)(encrypted[i] ^ mcKey.ReadByte(ki));
dest[i] = (byte)((b << 4) | (b >> 4));
break;
case 2:
b = encrypted[i];
dest[i] = (byte)((b << 4) | (b >> 4));
break;
}
}
return dest;
}
byte[] blowfishKey;
byte[] GetBlowfishKey() {
if (blowfishKey != null)

View File

@ -17,6 +17,8 @@
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Runtime.Remoting;
using dnlib.DotNet;
using AssemblyData;
using de4dot.code.AssemblyClient;
@ -30,6 +32,20 @@ namespace de4dot.code.deobfuscators {
}
public static DumpedMethods Decrypt(ServerClrVersion serverVersion, string filename, byte[] moduleCctorBytes) {
Exception lastEx = null;
for (int i = 0; i < 5; i++) {
try {
return Decrypt2(serverVersion, filename, moduleCctorBytes);
}
catch (RemotingException ex) {
lastEx = ex;
continue;
}
}
throw lastEx;
}
static DumpedMethods Decrypt2(ServerClrVersion serverVersion, string filename, byte[] moduleCctorBytes) {
using (var client = new NewProcessAssemblyClientFactory(serverVersion).Create(AssemblyServiceType.MethodDecrypter)) {
client.Connect();
client.WaitConnected();

View File

@ -155,14 +155,15 @@ namespace de4dot.code.deobfuscators {
});
}
protected static bool FixProxyCalls(Dictionary<Block, List<RemoveInfo>> removeInfos) {
protected bool FixProxyCalls(MethodDef method, Dictionary<Block, List<RemoveInfo>> removeInfos) {
var gpContext = GenericParamContext.Create(method);
foreach (var block in removeInfos.Keys) {
var list = removeInfos[block];
var removeIndexes = new List<int>(list.Count);
foreach (var info in list) {
if (info.IsCall) {
var opcode = info.DelegateInfo.callOpcode;
var newInstr = Instruction.Create(opcode, info.DelegateInfo.methodRef);
var newInstr = Instruction.Create(opcode, ReResolve(info.DelegateInfo.methodRef, gpContext));
block.Replace(info.Index, 1, newInstr);
}
else
@ -174,6 +175,12 @@ namespace de4dot.code.deobfuscators {
return removeInfos.Count > 0;
}
IMethod ReResolve(IMethod method, GenericParamContext gpContext) {
if (method.IsMethodSpec || method.IsMemberRef)
method = module.ResolveToken(method.MDToken.Raw, gpContext) as IMethod ?? method;
return method;
}
}
// Fixes proxy calls that call the delegate inline in the code, eg.:
@ -279,7 +286,7 @@ namespace de4dot.code.deobfuscators {
}
}
return FixProxyCalls(removeInfos);
return FixProxyCalls(blocks.Method, removeInfos);
}
protected virtual BlockInstr FindProxyCall(DelegateInfo di, Block block, int index) {
@ -481,7 +488,7 @@ namespace de4dot.code.deobfuscators {
}
}
return FixProxyCalls(removeInfos);
return FixProxyCalls(blocks.Method, removeInfos);
}
}

View File

@ -239,7 +239,7 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
var attrs2 = new Dictionary<TypeDef, bool>();
foreach (var cattr in cattrs) {
if (!DotNetUtils.IsMethod(cattr.Constructor as IMethod, "System.Void", "(System.Int32)"))
if (!DotNetUtils.IsMethod(cattr.Constructor, "System.Void", "(System.Int32)"))
continue;
var attrType = cattr.AttributeType as TypeDef;
if (attrType == null)

View File

@ -17,6 +17,7 @@
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
@ -83,12 +84,40 @@ namespace de4dot.code.deobfuscators.Spices_Net {
return true;
}
public void RenameResources() {
if (resourceManagerType == null && componentResourceManagerType == null)
return;
class ResourceDictionary {
struct Key {
public readonly uint hash;
public readonly string ns;
public Key(uint hash, string ns) {
this.hash = hash;
this.ns = ns;
}
var numToResource = new Dictionary<uint, Resource>(module.Resources.Count);
foreach (var resource in module.Resources) {
public override int GetHashCode() {
return (int)(hash ^ ns.GetHashCode());
}
public override bool Equals(object obj) {
if (!(obj is Key))
return false;
var other = (Key)obj;
return hash == other.hash &&
ns == other.ns;
}
public override string ToString() {
if (ns == string.Empty)
return string.Format("{0}", hash);
return string.Format("{0}.{1}", ns, hash);
}
}
Dictionary<Key, Resource> resources = new Dictionary<Key, Resource>();
public int Count {
get { return resources.Count; }
}
public bool Add(Resource resource) {
var name = resource.Name.String;
int index = name.LastIndexOf('.');
string ext;
@ -98,35 +127,55 @@ namespace de4dot.code.deobfuscators.Spices_Net {
ext = name.Substring(index + 1);
uint extNum;
if (!uint.TryParse(ext, out extNum))
continue;
numToResource[extNum] = resource;
return false;
var ns = index < 0 ? string.Empty : name.Substring(0, index);
resources.Add(new Key(extNum, ns), resource);
return true;
}
public Resource GetAndRemove(uint hash, string ns) {
var key = new Key(hash, ns);
Resource resource;
if (resources.TryGetValue(key, out resource))
resources.Remove(key);
return resource;
}
}
public void RenameResources() {
if (resourceManagerType == null && componentResourceManagerType == null)
return;
var rsrcDict = new ResourceDictionary();
foreach (var resource in module.Resources)
rsrcDict.Add(resource);
if (module.Assembly != null)
Rename(numToResource, "", module.Assembly.Name + ".g");
Rename(rsrcDict, "", module.Assembly.Name + ".g");
foreach (var type in callsResourceManager.Keys)
Rename(numToResource, type);
Rename(rsrcDict, type);
if (numToResource.Count != 0) {
if (rsrcDict.Count != 0) {
foreach (var type in module.GetTypes()) {
if (numToResource.Count == 0)
if (rsrcDict.Count == 0)
break;
if (!IsWinFormType(type))
continue;
Rename(numToResource, type);
Rename(rsrcDict, type);
}
}
if (numToResource.Count != 0) {
if (rsrcDict.Count != 0) {
foreach (var type in module.GetTypes()) {
if (numToResource.Count == 0)
if (rsrcDict.Count == 0)
break;
Rename(numToResource, type);
Rename(rsrcDict, type);
}
}
if (numToResource.Count != 0)
if (rsrcDict.Count != 0)
Logger.e("Couldn't restore all renamed resource names");
}
@ -151,18 +200,17 @@ namespace de4dot.code.deobfuscators.Spices_Net {
return false;
}
static bool Rename(Dictionary<uint, Resource> numToResource, TypeDef type) {
return Rename(numToResource, "", type.FullName) ||
Rename(numToResource, "", type.FullName + ".g") ||
Rename(numToResource, type.Namespace, type.Name) ||
Rename(numToResource, type.Namespace, type.Name + ".g");
static bool Rename(ResourceDictionary rsrcDict, TypeDef type) {
if (!IsWinFormType(type) && Rename(rsrcDict, "", type.FullName))
return true;
return Rename(rsrcDict, type.Namespace, type.Name);
}
static bool Rename(Dictionary<uint, Resource> numToResource, string ns, string name) {
static bool Rename(ResourceDictionary rsrcDict, string ns, string name) {
var resourceName = name + ".resources";
uint hash = GetResourceHash(resourceName);
Resource resource;
if (!numToResource.TryGetValue(hash, out resource))
var resource = rsrcDict.GetAndRemove(hash, ns);
if (resource == null)
return false;
int index = resource.Name.String.LastIndexOf('.');
@ -176,13 +224,12 @@ namespace de4dot.code.deobfuscators.Spices_Net {
newName = resourceNamespace + "." + resourceName;
}
if (resourceNamespace != ns)
return false;
throw new ApplicationException("Invalid resource namespace");
Logger.v("Restoring resource name: '{0}' => '{1}'",
Utils.RemoveNewlines(resource.Name),
Utils.RemoveNewlines(newName));
resource.Name = newName;
numToResource.Remove(hash);
return true;
}

View File

@ -333,6 +333,9 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
break;
}
if (methodsDecrypter.DecrypterTypeVersion != DnrDecrypterType.V1)
return DeobfuscatorInfo.THE_NAME;
if (methodsDecrypter.Method == null) {
if (minVer >= 3800)
return DeobfuscatorInfo.THE_NAME + " >= 3.8";
@ -361,6 +364,7 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
bool compileMethodHasConstant_0x70000000 = DeobUtils.HasInteger(compileMethod, 0x70000000); // 4.0-4.1
DeobfuscatedFile.Deobfuscate(methodsDecrypter.Method);
bool hasCorEnableProfilingString = FindString(methodsDecrypter.Method, "Cor_Enable_Profiling"); // 4.1-4.4
bool hasCatchString = FindString(methodsDecrypter.Method, "catch: "); // <= 4.7
if (compileMethodHasConstant_0x70000000) {
if (hasCorEnableProfilingString)
@ -368,7 +372,6 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
return DeobfuscatorInfo.THE_NAME + " 4.0";
}
if (!hasCorEnableProfilingString) {
// 4.x or 4.5 - 4.6
bool callsReverse = DotNetUtils.CallsMethod(methodsDecrypter.Method, "System.Void System.Array::Reverse(System.Array)");
if (!callsReverse)
return DeobfuscatorInfo.THE_NAME + " 4.0 - 4.4";
@ -382,7 +385,9 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
case 10:
if (!hasSymmetricAlgorithm)
return DeobfuscatorInfo.THE_NAME + " 4.6";
return DeobfuscatorInfo.THE_NAME + " 4.7";
if (hasCatchString)
return DeobfuscatorInfo.THE_NAME + " 4.7";
return DeobfuscatorInfo.THE_NAME + " 4.8";
}
}
else {
@ -392,7 +397,9 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
case 9:
if (!hasSymmetricAlgorithm)
return DeobfuscatorInfo.THE_NAME + " 4.6";
return DeobfuscatorInfo.THE_NAME + " 4.7";
if (hasCatchString)
return DeobfuscatorInfo.THE_NAME + " 4.7";
return DeobfuscatorInfo.THE_NAME + " 4.8";
}
}

View File

@ -24,13 +24,24 @@ using System.Security.Cryptography;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using de4dot.blocks;
using de4dot.blocks.cflow;
namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
enum DnrDecrypterType {
Unknown,
V1,
V2,
}
class EncryptedResource {
ModuleDefMD module;
MethodDef resourceDecrypterMethod;
EmbeddedResource encryptedDataResource;
byte[] key, iv;
IDecrypter decrypter;
public DnrDecrypterType DecrypterTypeVersion {
get { return decrypter == null ? DnrDecrypterType.Unknown : decrypter.DecrypterType; }
}
public TypeDef Type {
get { return resourceDecrypterMethod == null ? null : resourceDecrypterMethod.DeclaringType; }
@ -58,8 +69,7 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
resourceDecrypterMethod = Lookup(oldOne.resourceDecrypterMethod, "Could not find resource decrypter method");
if (oldOne.encryptedDataResource != null)
encryptedDataResource = DotNetUtils.GetResource(module, oldOne.encryptedDataResource.Name.String) as EmbeddedResource;
key = oldOne.key;
iv = oldOne.iv;
this.decrypter = oldOne.decrypter;
if (encryptedDataResource == null && oldOne.encryptedDataResource != null)
throw new ApplicationException("Could not initialize EncryptedResource");
@ -69,30 +79,12 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
return DeobUtils.Lookup(module, def, errorMessage);
}
public bool CouldBeResourceDecrypter(MethodDef method, IEnumerable<string> additionalTypes) {
public bool CouldBeResourceDecrypter(MethodDef method, IList<string> additionalTypes) {
return CouldBeResourceDecrypter(method, additionalTypes, true);
}
public bool CouldBeResourceDecrypter(MethodDef method, IEnumerable<string> additionalTypes, bool checkResource) {
if (!method.IsStatic)
return false;
if (method.Body == null)
return false;
var localTypes = new LocalTypes(method);
var requiredTypes = new List<string> {
"System.Byte[]",
"System.IO.BinaryReader",
"System.IO.MemoryStream",
"System.Security.Cryptography.CryptoStream",
"System.Security.Cryptography.ICryptoTransform",
};
requiredTypes.AddRange(additionalTypes);
if (!localTypes.All(requiredTypes))
return false;
if (!localTypes.Exists("System.Security.Cryptography.RijndaelManaged") &&
!localTypes.Exists("System.Security.Cryptography.AesManaged") &&
!localTypes.Exists("System.Security.Cryptography.SymmetricAlgorithm"))
public bool CouldBeResourceDecrypter(MethodDef method, IList<string> additionalTypes, bool checkResource) {
if (GetDecrypterType(method, additionalTypes) == DnrDecrypterType.Unknown)
return false;
if (checkResource && FindMethodsDecrypterResource(method) == null)
@ -101,6 +93,24 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
return true;
}
public DnrDecrypterType GuessDecrypterType() {
return GetDecrypterType(resourceDecrypterMethod, null);
}
static DnrDecrypterType GetDecrypterType(MethodDef method, IList<string> additionalTypes) {
if (method == null || !method.IsStatic || method.Body == null)
return DnrDecrypterType.Unknown;
if (additionalTypes == null)
additionalTypes = new string[0];
var localTypes = new LocalTypes(method);
if (DecrypterV1.CouldBeResourceDecrypter(method, localTypes, additionalTypes))
return DnrDecrypterType.V1;
else if (DecrypterV2.CouldBeResourceDecrypter(method, localTypes, additionalTypes))
return DnrDecrypterType.V2;
return DnrDecrypterType.Unknown;
}
public void Initialize(ISimpleDeobfuscator simpleDeobfuscator) {
if (resourceDecrypterMethod == null)
return;
@ -111,10 +121,10 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
if (encryptedDataResource == null)
return;
key = ArrayFinder.GetInitializedByteArray(resourceDecrypterMethod, 32);
var key = ArrayFinder.GetInitializedByteArray(resourceDecrypterMethod, 32);
if (key == null)
throw new ApplicationException("Could not find resource decrypter key");
iv = ArrayFinder.GetInitializedByteArray(resourceDecrypterMethod, 16);
var iv = ArrayFinder.GetInitializedByteArray(resourceDecrypterMethod, 16);
if (iv == null)
throw new ApplicationException("Could not find resource decrypter IV");
if (NeedReverse())
@ -126,6 +136,13 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
iv[i * 2 + 1] = publicKeyToken.Data[i];
}
}
var decrypterType = GetDecrypterType(resourceDecrypterMethod, new string[0]);
switch (decrypterType) {
case DnrDecrypterType.V1: decrypter = new DecrypterV1(iv, key); break;
case DnrDecrypterType.V2: decrypter = new DecrypterV2(iv, key, resourceDecrypterMethod); break;
default: throw new ApplicationException("Unknown decrypter type");
}
}
static int[] pktIndexes = new int[16] { 1, 0, 3, 1, 5, 2, 7, 3, 9, 4, 11, 5, 13, 6, 15, 7 };
@ -162,22 +179,244 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
return null;
}
public byte[] Decrypt() {
if (encryptedDataResource == null || key == null || iv == null)
throw new ApplicationException("Can't decrypt resource");
return DeobUtils.AesDecrypt(encryptedDataResource.GetResourceData(), key, iv);
interface IDecrypter {
DnrDecrypterType DecrypterType { get; }
byte[] Decrypt(EmbeddedResource resource);
byte[] Encrypt(byte[] data);
}
public byte[] Encrypt(byte[] data) {
if (key == null || iv == null)
throw new ApplicationException("Can't encrypt resource");
class DecrypterV1 : IDecrypter {
readonly byte[] key, iv;
using (var aes = new RijndaelManaged { Mode = CipherMode.CBC }) {
using (var transform = aes.CreateEncryptor(key, iv)) {
return transform.TransformFinalBlock(data, 0, data.Length);
public DnrDecrypterType DecrypterType {
get { return DnrDecrypterType.V1; }
}
public DecrypterV1(byte[] iv, byte[] key) {
this.iv = iv;
this.key = key;
}
public static bool CouldBeResourceDecrypter(MethodDef method, LocalTypes localTypes, IList<string> additionalTypes) {
var requiredTypes = new List<string> {
"System.Byte[]",
"System.IO.BinaryReader",
"System.IO.MemoryStream",
"System.Security.Cryptography.CryptoStream",
"System.Security.Cryptography.ICryptoTransform",
};
requiredTypes.AddRange(additionalTypes);
if (!localTypes.All(requiredTypes))
return false;
if (!localTypes.Exists("System.Security.Cryptography.RijndaelManaged") &&
!localTypes.Exists("System.Security.Cryptography.AesManaged") &&
!localTypes.Exists("System.Security.Cryptography.SymmetricAlgorithm"))
return false;
return true;
}
public byte[] Decrypt(EmbeddedResource resource) {
return DeobUtils.AesDecrypt(resource.GetResourceData(), key, iv);
}
public byte[] Encrypt(byte[] data) {
using (var aes = new RijndaelManaged { Mode = CipherMode.CBC }) {
using (var transform = aes.CreateEncryptor(key, iv)) {
return transform.TransformFinalBlock(data, 0, data.Length);
}
}
}
}
class DecrypterV2 : IDecrypter {
readonly byte[] key, iv;
readonly MethodDef method;
List<Instruction> instructions;
readonly List<Local> locals;
readonly InstructionEmulator instrEmulator = new InstructionEmulator();
Local emuLocal;
public DnrDecrypterType DecrypterType {
get { return DnrDecrypterType.V2; }
}
public DecrypterV2(byte[] iv, byte[] key, MethodDef method) {
this.iv = iv;
this.key = key;
this.method = method;
this.locals = new List<Local>(method.Body.Variables);
if (!Initialize())
throw new ApplicationException("Could not initialize decrypter");
}
public static bool CouldBeResourceDecrypter(MethodDef method, LocalTypes localTypes, IList<string> additionalTypes) {
var requiredTypes = new List<string> {
"System.UInt32",
"System.String",
"System.Int32",
"System.Byte[]",
"System.IO.BinaryReader",
};
requiredTypes.AddRange(additionalTypes);
if (!localTypes.All(requiredTypes))
return false;
return true;
}
bool Initialize() {
for (int i = 0; i < iv.Length; i++)
key[i] ^= iv[i];
var origInstrs = method.Body.Instructions;
int emuStartIndex;
if (!FindStart(origInstrs, out emuStartIndex, out emuLocal))
return false;
int emuEndIndex;
if (!FindEnd(origInstrs, emuStartIndex, out emuEndIndex))
return false;
int count = emuEndIndex - emuStartIndex + 1;
instructions = new List<Instruction>(count);
for (int i = 0; i < count; i++)
instructions.Add(origInstrs[emuStartIndex + i].Clone());
return true;
}
bool FindStart(IList<Instruction> instrs, out int startIndex, out Local tmpLocal) {
for (int i = 0; i + 8 < instrs.Count; i++) {
if (instrs[i].OpCode.Code != Code.Conv_U)
continue;
if (instrs[i + 1].OpCode.Code != Code.Ldelem_U1)
continue;
if (instrs[i + 2].OpCode.Code != Code.Or)
continue;
if (CheckLocal(instrs[i + 3], false) == null)
continue;
Local local;
if ((local = CheckLocal(instrs[i + 4], true)) == null)
continue;
if (CheckLocal(instrs[i + 5], true) == null)
continue;
if (instrs[i + 6].OpCode.Code != Code.Add)
continue;
if (CheckLocal(instrs[i + 7], false) != local)
continue;
var instr = instrs[i + 8];
int newStartIndex = i + 8;
if (instr.IsBr()) {
instr = instr.Operand as Instruction;
newStartIndex = instrs.IndexOf(instr);
}
if (newStartIndex < 0 || instr == null)
continue;
if (CheckLocal(instr, true) != local)
continue;
startIndex = newStartIndex;
tmpLocal = local;
return true;
}
startIndex = 0;
tmpLocal = null;
return false;
}
bool FindEnd(IList<Instruction> instrs, int startIndex, out int endIndex) {
for (int i = startIndex; i < instrs.Count; i++) {
var instr = instrs[i];
if (instr.OpCode.FlowControl != FlowControl.Next)
break;
if (instr.IsStloc() && instr.GetLocal(locals) == emuLocal) {
endIndex = i - 1;
return true;
}
}
endIndex = 0;
return false;
}
Local CheckLocal(Instruction instr, bool isLdloc) {
if (isLdloc && !instr.IsLdloc())
return null;
else if (!isLdloc && !instr.IsStloc())
return null;
return instr.GetLocal(locals);
}
public byte[] Decrypt(EmbeddedResource resource) {
var encrypted = resource.GetResourceData();
var decrypted = new byte[encrypted.Length];
uint sum = 0;
for (int i = 0; i < encrypted.Length; i += 4) {
sum = CalculateMagic(sum + ReadUInt32(key, i % key.Length));
WriteUInt32(decrypted, i, sum ^ ReadUInt32(encrypted, i));
}
return decrypted;
}
uint CalculateMagic(uint input) {
instrEmulator.Initialize(method, method.Parameters, locals, method.Body.InitLocals, false);
instrEmulator.SetLocal(emuLocal, new Int32Value((int)input));
foreach (var instr in instructions)
instrEmulator.Emulate(instr);
var tos = instrEmulator.Pop() as Int32Value;
if (tos == null || !tos.AllBitsValid())
throw new ApplicationException("Couldn't calculate magic value");
return (uint)tos.Value;
}
static uint ReadUInt32(byte[] ary, int index) {
int sizeLeft = ary.Length - index;
if (sizeLeft >= 4)
return BitConverter.ToUInt32(ary, index);
switch (sizeLeft) {
case 1: return ary[index];
case 2: return (uint)(ary[index] | (ary[index + 1] << 8));
case 3: return (uint)(ary[index] | (ary[index + 1] << 8) | (ary[index + 2] << 16));
default: throw new ApplicationException("Can't read data");
}
}
static void WriteUInt32(byte[] ary, int index, uint value) {
int sizeLeft = ary.Length - index;
if (sizeLeft >= 1)
ary[index] = (byte)value;
if (sizeLeft >= 2)
ary[index + 1] = (byte)(value >> 8);
if (sizeLeft >= 3)
ary[index + 2] = (byte)(value >> 16);
if (sizeLeft >= 4)
ary[index + 3] = (byte)(value >> 24);
}
public byte[] Encrypt(byte[] data) {
//TODO: Support re-encryption
Logger.e("Re-encryption is not supported. Assembly will probably crash at runtime.");
return (byte[])data.Clone();
}
}
public byte[] Decrypt() {
if (encryptedDataResource == null || decrypter == null)
throw new ApplicationException("Can't decrypt resource");
return decrypter.Decrypt(encryptedDataResource);
}
public byte[] Encrypt(byte[] data) {
if (decrypter == null)
throw new ApplicationException("Can't encrypt resource");
return decrypter.Encrypt(data);
}
}
}

View File

@ -76,6 +76,7 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
if (type == null)
return;
var gpContext = GenericParamContext.Create(blocks.Method);
foreach (var block in blocks.MethodBlocks.GetAllBlocks()) {
var instrs = block.Instructions;
for (int i = 0; i < instrs.Count - 1; i++) {
@ -98,7 +99,7 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
uint token = (uint)(int)instrs[i].Operand;
instrs[i] = new Instr(OpCodes.Nop.ToInstruction());
instrs[i + 1] = new Instr(new Instruction(OpCodes.Ldtoken, module.ResolveToken(token) as ITokenOperand));
instrs[i + 1] = new Instr(new Instruction(OpCodes.Ldtoken, module.ResolveToken(token, gpContext) as ITokenOperand));
}
}
}

View File

@ -57,6 +57,10 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
get { return encryptedResource.Resource; }
}
public DnrDecrypterType DecrypterTypeVersion {
get { return encryptedResource.GuessDecrypterType(); }
}
public MethodsDecrypter(ModuleDefMD module) {
this.module = module;
this.encryptedResource = new EncryptedResource(module);
@ -301,10 +305,10 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
if (instructions[i].OpCode.Code != Code.Ldind_I8)
continue;
var ldci4 = instructions[i + 1];
if (!ldci4.IsLdcI4())
continue;
return ldci4.GetLdcI4Value();
if (ldci4.IsLdcI4())
return ldci4.GetLdcI4Value();
if (ldci4.OpCode.Code == Code.Ldc_I8)
return (long)ldci4.Operand;
}
return 0;
}

View File

@ -70,21 +70,37 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
if (!DotNetUtils.IsMethod(method, "System.Reflection.Assembly", "(System.Object,System.ResolveEventArgs)") &&
!DotNetUtils.IsMethod(method, "System.Reflection.Assembly", "(System.Object,System.Object)"))
continue;
if (!encryptedResource.CouldBeResourceDecrypter(method, additionalTypes, false))
var initMethod = GetResourceDecrypterInitMethod(method, additionalTypes, false);
if (initMethod == null)
continue;
encryptedResource.Method = method;
encryptedResource.Method = initMethod;
return;
}
}
}
MethodDef GetResourceDecrypterInitMethod(MethodDef method, string[] additionalTypes, bool checkResource) {
if (encryptedResource.CouldBeResourceDecrypter(method, additionalTypes, checkResource))
return method;
foreach (var calledMethod in DotNetUtils.GetCalledMethods(module, method)) {
if (!DotNetUtils.IsMethod(calledMethod, "System.Void", "()"))
continue;
if (encryptedResource.CouldBeResourceDecrypter(calledMethod, additionalTypes, checkResource))
return calledMethod;
}
return null;
}
bool CheckFields(IList<FieldDef> fields) {
if (fields.Count != 3)
if (fields.Count != 3 && fields.Count != 4)
return false;
int numBools = fields.Count == 3 ? 1 : 2;
var fieldTypes = new FieldTypes(fields);
if (fieldTypes.Count("System.Boolean") != 1)
if (fieldTypes.Count("System.Boolean") != numBools)
return false;
if (fieldTypes.Count("System.Object") == 2)
return true;

View File

@ -40,6 +40,12 @@ namespace de4dot.code.renamer {
}
public bool Check(MTypeDef type) {
return Check(type, 0);
}
public bool Check(MTypeDef type, int recurseCount) {
if (recurseCount >= 100)
return false;
if (results.ContainsKey(type))
return results[type];
@ -53,7 +59,7 @@ namespace de4dot.code.renamer {
val = false;
}
else
val = Check(type.baseType.typeDef);
val = Check(type.baseType.typeDef, recurseCount + 1);
results[type] = val;
return val;

View File

@ -62,6 +62,8 @@ namespace de4dot.code.renamer {
}
public void Merge(ExistingNames other) {
if (this == other)
return;
foreach (var key in other.allNames.Keys)
allNames[key] = true;
}

View File

@ -1520,6 +1520,29 @@ namespace de4dot.code.renamer {
return null;
}
internal static ITypeDefOrRef GetScopeType(TypeSig typeSig) {
if (typeSig == null)
return null;
var scopeType = typeSig.ScopeType;
if (scopeType != null)
return scopeType;
for (int i = 0; i < 100; i++) {
var nls = typeSig as NonLeafSig;
if (nls == null)
break;
typeSig = nls.Next;
}
switch (typeSig.GetElementType()) {
case ElementType.MVar:
case ElementType.Var:
return new TypeSpecUser(typeSig);
default:
return null;
}
}
string GetNewPropertyNamePrefix(MethodNameGroup group) {
const string defaultVal = "Prop_";
@ -1527,7 +1550,7 @@ namespace de4dot.code.renamer {
if (propType == null)
return defaultVal;
var elementType = propType.ScopeType.ToTypeSig(false).RemovePinnedAndModifiers();
var elementType = GetScopeType(propType).ToTypeSig(false).RemovePinnedAndModifiers();
if (propType is GenericInstSig || elementType is GenericSig)
return defaultVal;

View File

@ -44,7 +44,7 @@ namespace de4dot.code.renamer {
string prefix = GetPrefix(typeRef);
var elementType = typeRef.ScopeType;
var elementType = Renamer.GetScopeType(typeRef);
if (elementType == null && IsFnPtrSig(typeRef))
return fnPtrNameCreator.Create();
if (IsGenericParam(elementType))
@ -113,6 +113,8 @@ namespace de4dot.code.renamer {
protected abstract string FixName(string prefix, string name);
public virtual TypeNames Merge(TypeNames other) {
if (this == other)
return this;
foreach (var pair in other.typeNames) {
NameCreator nc;
if (typeNames.TryGetValue(pair.Key, out nc))

View File

@ -61,6 +61,8 @@ namespace de4dot.code.renamer {
}
public VariableNameState Merge(VariableNameState other) {
if (this == other)
return this;
existingVariableNames.Merge(other.existingVariableNames);
existingMethodNames.Merge(other.existingMethodNames);
existingPropertyNames.Merge(other.existingPropertyNames);

View File

@ -285,9 +285,44 @@ namespace de4dot.code.renamer.asmmodules {
void Add(DeclSecurity decl) {
if (decl == null)
return;
Add(decl.SecurityAttributes);
Add(decl.CustomAttributes);
}
void Add(IEnumerable<SecurityAttribute> secAttrs) {
if (secAttrs == null)
return;
foreach (var secAttr in secAttrs)
Add(secAttr);
}
void Add(SecurityAttribute secAttr) {
if (secAttr == null)
return;
Add(secAttr.AttributeType);
Add(secAttr.NamedArguments);
}
void Add(ITypeDefOrRef tdr) {
var td = tdr as TypeDef;
if (td != null) {
Add(td);
return;
}
var tr = tdr as TypeRef;
if (tr != null) {
Add(tr);
return;
}
var ts = tdr as TypeSpec;
if (ts != null) {
Add(ts);
return;
}
}
void Add(IEnumerable<EventDef> eds) {
if (eds == null)
return;
@ -326,6 +361,7 @@ namespace de4dot.code.renamer.asmmodules {
Add(fd.CustomAttributes);
Add(fd.Signature);
Add(fd.DeclaringType);
Add(fd.MarshalType);
}
void Add(IEnumerable<GenericParam> gps) {
@ -489,6 +525,22 @@ namespace de4dot.code.renamer.asmmodules {
return;
Add(pd.DeclaringMethod);
Add(pd.CustomAttributes);
Add(pd.MarshalType);
}
void Add(MarshalType mt) {
if (mt == null)
return;
switch (mt.NativeType) {
case NativeType.SafeArray:
Add(((SafeArrayMarshalType)mt).UserDefinedSubType);
break;
case NativeType.CustomMarshaler:
Add(((CustomMarshalType)mt).CustomMarshaler);
break;
}
}
void Add(IEnumerable<MethodOverride> mos) {

View File

@ -74,7 +74,7 @@ namespace de4dot.cui {
Logger.n("");
Logger.n("de4dot v{0} Copyright (C) 2011-2014 de4dot@gmail.com", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version);
Logger.n("Latest version and source code: https://bitbucket.org/0xd4d/de4dot");
Logger.n("Latest version and source code: https://github.com/0xd4d/de4dot");
Logger.n("");
var options = new FilesDeobfuscator.Options();

View File

@ -30,7 +30,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("3.0.3.3405")]
[assembly: AssemblyFileVersion("3.0.3.3405")]
[assembly: AssemblyVersion("3.1.41592.3405")]
[assembly: AssemblyFileVersion("3.1.41592.3405")]
[assembly: InternalsVisibleTo("de4dot, PublicKey=00240000048000009400000006020000002400005253413100040000010001007b5ffd8f48f1397cd4e21c9e30a5cb36b2c013d6f20688c90e3f0c2d24e6d67cbeea7a6ec3faf9ba081f3d6b6fbe389677adbb8337d3a16187cd13b16a34008a22b89089da41c4a08fd35615c77de0827adcca6d49b08c0ed3e0404a1c44b7d083be614acb1779e4fb275e14427f3687f375d03f3b465c8a6cdeebd1f8c7f4ea")]
[assembly: InternalsVisibleTo("de4dot-x64, PublicKey=00240000048000009400000006020000002400005253413100040000010001007b5ffd8f48f1397cd4e21c9e30a5cb36b2c013d6f20688c90e3f0c2d24e6d67cbeea7a6ec3faf9ba081f3d6b6fbe389677adbb8337d3a16187cd13b16a34008a22b89089da41c4a08fd35615c77de0827adcca6d49b08c0ed3e0404a1c44b7d083be614acb1779e4fb275e14427f3687f375d03f3b465c8a6cdeebd1f8c7f4ea")]

View File

@ -596,6 +596,9 @@ namespace de4dot.mdecrypt {
new PatchInfo(0x000110A5, new byte[] { 0x33, 0xC0, 0xC2, 0x04, 0x00 }, new byte[] { 0xE9, 0x36, 0x3A, 0x00, 0x00 }),
new PatchInfo(0x000110AF, new byte[] { 0x33, 0xC0, 0xC2, 0x04, 0x00 }, new byte[] { 0xE9, 0x4C, 0x3C, 0x00, 0x00 }),
new PatchInfo(0x000110AA, new byte[] { 0x33, 0xC0, 0xC2, 0x04, 0x00 }, new byte[] { 0xE9, 0xF1, 0x3A, 0x00, 0x00 }),
new PatchInfo(0x00011019, new byte[] { 0x33, 0xC0, 0xC2, 0x04, 0x00 }, new byte[] { 0xE9, 0x12, 0x4B, 0x00, 0x00 }),
new PatchInfo(0x00011019, new byte[] { 0x33, 0xC0, 0xC2, 0x04, 0x00 }, new byte[] { 0xE9, 0x02, 0x4B, 0x00, 0x00 }),
new PatchInfo(0x00011019, new byte[] { 0x33, 0xC0, 0xC2, 0x04, 0x00 }, new byte[] { 0xE9, 0xA2, 0x4B, 0x00, 0x00 }),
};
static unsafe bool PatchCM(IntPtr addr, IntPtr origValue, IntPtr newValue) {

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("3.0.3.3405")]
[assembly: AssemblyFileVersion("3.0.3.3405")]
[assembly: AssemblyVersion("3.1.41592.3405")]
[assembly: AssemblyFileVersion("3.1.41592.3405")]

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("3.0.3.3405")]
[assembly: AssemblyFileVersion("3.0.3.3405")]
[assembly: AssemblyVersion("3.1.41592.3405")]
[assembly: AssemblyFileVersion("3.1.41592.3405")]

2
dnlib

@ -1 +1 @@
Subproject commit d854e20b2d4245245efc19e676e6862cdbd162f6
Subproject commit 4abc5988d3cc4e8ae4cb7ac77f3018ffb54200c7