diff --git a/AssemblyData/AssemblyData.csproj b/AssemblyData/AssemblyData.csproj
index 847bed52..f34df5c0 100644
--- a/AssemblyData/AssemblyData.csproj
+++ b/AssemblyData/AssemblyData.csproj
@@ -41,8 +41,14 @@
+
+
+
+
+
+
@@ -58,6 +64,7 @@
+
@@ -66,9 +73,9 @@
-
+
{045B96F2-AF80-4C4C-8D27-E38635AC705E}
- blocks
+ de4dot.blocks
{5C93C5E2-196F-4877-BF65-96FEBFCEFCA1}
diff --git a/AssemblyData/AssemblyServer.cs b/AssemblyData/AssemblyServer.cs
index 44c9ce0b..a9110bd1 100644
--- a/AssemblyData/AssemblyServer.cs
+++ b/AssemblyData/AssemblyServer.cs
@@ -27,12 +27,13 @@ using AssemblyData;
namespace AssemblyServer {
public static class Start {
public static int Main2(string[] args) {
- if (args.Length != 2)
+ if (args.Length != 3)
Environment.Exit(1);
- var channelName = args[0];
- var uri = args[1];
+ var serviceType = (AssemblyServiceType)int.Parse(args[0]);
+ var channelName = args[1];
+ var uri = args[2];
- var service = new AssemblyService();
+ var service = (AssemblyService)AssemblyService.Create(serviceType);
StartServer(service, channelName, uri);
service.WaitExit();
return 0;
diff --git a/AssemblyData/AssemblyService.cs b/AssemblyData/AssemblyService.cs
index 7b691efc..74798b51 100644
--- a/AssemblyData/AssemblyService.cs
+++ b/AssemblyData/AssemblyService.cs
@@ -18,25 +18,51 @@
*/
using System;
-using System.Collections.Generic;
using System.Reflection;
using System.Threading;
-using dnlib.DotNet;
-using de4dot.blocks;
-using de4dot.mdecrypt;
namespace AssemblyData {
- public class AssemblyService : MarshalByRefObject, IAssemblyService {
- IStringDecrypter stringDecrypter = null;
+ public abstract class AssemblyService : MarshalByRefObject, IAssemblyService {
ManualResetEvent exitEvent = new ManualResetEvent(false);
- Assembly assembly = null;
+ protected Assembly assembly = null;
AssemblyResolver assemblyResolver = new AssemblyResolver();
- bool installCompileMethodCalled = false;
+
+ public static AssemblyService Create(AssemblyServiceType serviceType) {
+ switch (serviceType) {
+ case AssemblyServiceType.StringDecrypter:
+ return new StringDecrypterService();
+
+ case AssemblyServiceType.MethodDecrypter:
+ return new MethodDecrypterService();
+
+ case AssemblyServiceType.Generic:
+ return new GenericService();
+
+ default:
+ throw new ArgumentException("Invalid assembly service type");
+ }
+ }
+
+ public static Type GetType(AssemblyServiceType serviceType) {
+ switch (serviceType) {
+ case AssemblyServiceType.StringDecrypter:
+ return typeof(StringDecrypterService);
+
+ case AssemblyServiceType.MethodDecrypter:
+ return typeof(MethodDecrypterService);
+
+ case AssemblyServiceType.Generic:
+ return typeof(GenericService);
+
+ default:
+ throw new ArgumentException("Invalid assembly service type");
+ }
+ }
public void DoNothing() {
}
- public void Exit() {
+ public virtual void Exit() {
exitEvent.Set();
}
@@ -48,17 +74,12 @@ namespace AssemblyData {
return null;
}
- void CheckStringDecrypter() {
- if (stringDecrypter == null)
- throw new ApplicationException("setStringDecrypterType() hasn't been called yet.");
- }
-
- void CheckAssembly() {
+ protected void CheckAssembly() {
if (assembly == null)
- throw new ApplicationException("loadAssembly() hasn't been called yet.");
+ throw new ApplicationException("LoadAssembly() hasn't been called yet.");
}
- public void LoadAssembly(string filename) {
+ protected void LoadAssemblyInternal(string filename) {
if (assembly != null)
throw new ApplicationException("Only one assembly can be explicitly loaded");
try {
@@ -68,86 +89,5 @@ namespace AssemblyData {
throw new ApplicationException(string.Format("Could not load assembly {0}. Maybe it's 32-bit or 64-bit only?", filename));
}
}
-
- public void SetStringDecrypterType(StringDecrypterType type) {
- if (stringDecrypter != null)
- throw new ApplicationException("StringDecrypterType already set");
-
- switch (type) {
- case StringDecrypterType.Delegate:
- stringDecrypter = new DelegateStringDecrypter();
- break;
-
- case StringDecrypterType.Emulate:
- stringDecrypter = new EmuStringDecrypter();
- break;
-
- default:
- throw new ApplicationException(string.Format("Unknown StringDecrypterType {0}", type));
- }
- }
-
- public int DefineStringDecrypter(int methodToken) {
- CheckStringDecrypter();
- var methodInfo = FindMethod(methodToken);
- if (methodInfo == null)
- throw new ApplicationException(string.Format("Could not find method {0:X8}", methodToken));
- if (methodInfo.ReturnType != typeof(string) && methodInfo.ReturnType != typeof(object))
- throw new ApplicationException(string.Format("Method return type must be string or object: {0}", methodInfo));
- return stringDecrypter.DefineStringDecrypter(methodInfo);
- }
-
- public object[] DecryptStrings(int stringDecrypterMethod, object[] args, int callerToken) {
- CheckStringDecrypter();
- var caller = GetCaller(callerToken);
- foreach (var arg in args)
- SimpleData.Unpack((object[])arg);
- return SimpleData.Pack(stringDecrypter.DecryptStrings(stringDecrypterMethod, args, caller));
- }
-
- MethodBase GetCaller(int callerToken) {
- try {
- return assembly.GetModules()[0].ResolveMethod(callerToken);
- }
- catch {
- return null;
- }
- }
-
- MethodInfo FindMethod(int methodToken) {
- CheckAssembly();
-
- foreach (var module in assembly.GetModules()) {
- var method = module.ResolveMethod(methodToken) as MethodInfo;
- if (method != null)
- return method;
- }
-
- return null;
- }
-
- public void InstallCompileMethod(DecryptMethodsInfo decryptMethodsInfo) {
- if (installCompileMethodCalled)
- throw new ApplicationException("installCompileMethod() has already been called");
- installCompileMethodCalled = true;
- DynamicMethodsDecrypter.Instance.DecryptMethodsInfo = decryptMethodsInfo;
- DynamicMethodsDecrypter.Instance.InstallCompileMethod();
- }
-
- public void LoadObfuscator(string filename) {
- LoadAssembly(filename);
- DynamicMethodsDecrypter.Instance.Module = assembly.ManifestModule;
- DynamicMethodsDecrypter.Instance.LoadObfuscator();
- }
-
- public bool CanDecryptMethods() {
- CheckAssembly();
- return DynamicMethodsDecrypter.Instance.CanDecryptMethods();
- }
-
- public DumpedMethods DecryptMethods() {
- CheckAssembly();
- return DynamicMethodsDecrypter.Instance.DecryptMethods();
- }
}
}
diff --git a/AssemblyData/GenericService.cs b/AssemblyData/GenericService.cs
new file mode 100644
index 00000000..a214f024
--- /dev/null
+++ b/AssemblyData/GenericService.cs
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2011-2013 de4dot@gmail.com
+
+ This file is part of de4dot.
+
+ de4dot is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ de4dot is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with de4dot. If not, see .
+*/
+
+using System;
+using System.Reflection;
+
+namespace AssemblyData {
+ class GenericService : AssemblyService, IGenericService {
+ IUserGenericService userGenericService;
+
+ public override void Exit() {
+ if (userGenericService != null)
+ userGenericService.Dispose();
+ userGenericService = null;
+ base.Exit();
+ }
+
+ public void LoadUserService(Type createServiceType, object createMethodArgs) {
+ var createServiceMethod = GetCreateUserServiceMethod(createServiceType);
+ userGenericService = createServiceMethod.Invoke(null, null) as IUserGenericService;
+ if (userGenericService == null)
+ throw new ApplicationException("create-service-method failed to create user service");
+ }
+
+ MethodInfo GetCreateUserServiceMethod(Type createServiceType) {
+ if (createServiceType == null)
+ throw new ApplicationException(string.Format("Create-service-type is null"));
+ foreach (var method in createServiceType.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)) {
+ if (method.GetCustomAttributes(typeof(CreateUserGenericServiceAttribute), false).Length > 0)
+ return method;
+ }
+ throw new ApplicationException(string.Format("Failed to find create-service-method. Type token: Type: {0}", createServiceType));
+ }
+
+ void CheckUserService() {
+ if (userGenericService == null)
+ throw new ApplicationException("LoadUserService() hasn't been called yet.");
+ }
+
+ public void LoadAssembly(string filename) {
+ CheckUserService();
+ LoadAssemblyInternal(filename);
+ userGenericService.AssemblyLoaded(assembly);
+ }
+
+ public object SendMessage(int msg, object[] args) {
+ CheckUserService();
+ return userGenericService.HandleMessage(msg, args);
+ }
+ }
+}
diff --git a/AssemblyData/IAssemblyService.cs b/AssemblyData/IAssemblyService.cs
index 2867531b..b0e1da67 100644
--- a/AssemblyData/IAssemblyService.cs
+++ b/AssemblyData/IAssemblyService.cs
@@ -17,29 +17,15 @@
along with de4dot. If not, see .
*/
-using dnlib.DotNet;
-using de4dot.blocks;
-using de4dot.mdecrypt;
-
namespace AssemblyData {
- public enum StringDecrypterType {
- Delegate,
- Emulate,
+ public enum AssemblyServiceType {
+ StringDecrypter,
+ MethodDecrypter,
+ Generic,
}
public interface IAssemblyService {
void DoNothing();
void Exit();
-
- void LoadAssembly(string filename);
-
- void SetStringDecrypterType(StringDecrypterType type);
- int DefineStringDecrypter(int methodToken);
- object[] DecryptStrings(int stringDecrypterMethod, object[] args, int callerToken);
-
- void InstallCompileMethod(DecryptMethodsInfo decryptMethodsInfo);
- void LoadObfuscator(string filename);
- bool CanDecryptMethods();
- DumpedMethods DecryptMethods();
}
}
diff --git a/AssemblyData/IGenericService.cs b/AssemblyData/IGenericService.cs
new file mode 100644
index 00000000..db4d7a91
--- /dev/null
+++ b/AssemblyData/IGenericService.cs
@@ -0,0 +1,31 @@
+/*
+ Copyright (C) 2011-2013 de4dot@gmail.com
+
+ This file is part of de4dot.
+
+ de4dot is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ de4dot is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with de4dot. If not, see .
+*/
+
+using System;
+
+namespace AssemblyData {
+ public class CreateUserGenericServiceAttribute : Attribute {
+ }
+
+ public interface IGenericService : IAssemblyService {
+ void LoadUserService(Type createServiceType, object createMethodArgs);
+ void LoadAssembly(string filename);
+ object SendMessage(int msg, object[] args);
+ }
+}
diff --git a/AssemblyData/IMethodDecrypterService.cs b/AssemblyData/IMethodDecrypterService.cs
new file mode 100644
index 00000000..5ec2b224
--- /dev/null
+++ b/AssemblyData/IMethodDecrypterService.cs
@@ -0,0 +1,30 @@
+/*
+ Copyright (C) 2011-2013 de4dot@gmail.com
+
+ This file is part of de4dot.
+
+ de4dot is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ de4dot is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with de4dot. If not, see .
+*/
+
+using de4dot.blocks;
+using de4dot.mdecrypt;
+
+namespace AssemblyData {
+ public interface IMethodDecrypterService : IAssemblyService {
+ void InstallCompileMethod(DecryptMethodsInfo decryptMethodsInfo);
+ void LoadObfuscator(string filename);
+ bool CanDecryptMethods();
+ DumpedMethods DecryptMethods();
+ }
+}
diff --git a/AssemblyData/IStringDecrypterService.cs b/AssemblyData/IStringDecrypterService.cs
new file mode 100644
index 00000000..83ad0c6a
--- /dev/null
+++ b/AssemblyData/IStringDecrypterService.cs
@@ -0,0 +1,32 @@
+/*
+ Copyright (C) 2011-2013 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 .
+*/
+
+namespace AssemblyData {
+ public enum StringDecrypterType {
+ Delegate,
+ Emulate,
+ }
+
+ public interface IStringDecrypterService : IAssemblyService {
+ void LoadAssembly(string filename);
+ void SetStringDecrypterType(StringDecrypterType type);
+ int DefineStringDecrypter(int methodToken);
+ object[] DecryptStrings(int stringDecrypterMethod, object[] args, int callerToken);
+ }
+}
diff --git a/AssemblyData/IUserGenericService.cs b/AssemblyData/IUserGenericService.cs
new file mode 100644
index 00000000..635ae7f6
--- /dev/null
+++ b/AssemblyData/IUserGenericService.cs
@@ -0,0 +1,28 @@
+/*
+ Copyright (C) 2011-2013 de4dot@gmail.com
+
+ This file is part of de4dot.
+
+ de4dot is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ de4dot is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with de4dot. If not, see .
+*/
+
+using System;
+using System.Reflection;
+
+namespace AssemblyData {
+ public interface IUserGenericService : IDisposable {
+ void AssemblyLoaded(Assembly assembly);
+ object HandleMessage(int msg, object[] args);
+ }
+}
diff --git a/AssemblyData/MethodDecrypterService.cs b/AssemblyData/MethodDecrypterService.cs
new file mode 100644
index 00000000..47c75234
--- /dev/null
+++ b/AssemblyData/MethodDecrypterService.cs
@@ -0,0 +1,52 @@
+/*
+ Copyright (C) 2011-2013 de4dot@gmail.com
+
+ This file is part of de4dot.
+
+ de4dot is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ de4dot is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with de4dot. If not, see .
+*/
+
+using System;
+using de4dot.blocks;
+using de4dot.mdecrypt;
+
+namespace AssemblyData {
+ class MethodDecrypterService : AssemblyService, IMethodDecrypterService {
+ bool installCompileMethodCalled = false;
+
+ public void InstallCompileMethod(DecryptMethodsInfo decryptMethodsInfo) {
+ if (installCompileMethodCalled)
+ throw new ApplicationException("installCompileMethod() has already been called");
+ installCompileMethodCalled = true;
+ DynamicMethodsDecrypter.Instance.DecryptMethodsInfo = decryptMethodsInfo;
+ DynamicMethodsDecrypter.Instance.InstallCompileMethod();
+ }
+
+ public void LoadObfuscator(string filename) {
+ LoadAssemblyInternal(filename);
+ DynamicMethodsDecrypter.Instance.Module = assembly.ManifestModule;
+ DynamicMethodsDecrypter.Instance.LoadObfuscator();
+ }
+
+ public bool CanDecryptMethods() {
+ CheckAssembly();
+ return DynamicMethodsDecrypter.Instance.CanDecryptMethods();
+ }
+
+ public DumpedMethods DecryptMethods() {
+ CheckAssembly();
+ return DynamicMethodsDecrypter.Instance.DecryptMethods();
+ }
+ }
+}
diff --git a/AssemblyData/StringDecrypterService.cs b/AssemblyData/StringDecrypterService.cs
new file mode 100644
index 00000000..08c0be43
--- /dev/null
+++ b/AssemblyData/StringDecrypterService.cs
@@ -0,0 +1,93 @@
+/*
+ Copyright (C) 2011-2013 de4dot@gmail.com
+
+ This file is part of de4dot.
+
+ de4dot is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ de4dot is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with de4dot. If not, see .
+*/
+
+using System;
+using System.Reflection;
+
+namespace AssemblyData {
+ class StringDecrypterService : AssemblyService, IStringDecrypterService {
+ IStringDecrypter stringDecrypter = null;
+
+ void CheckStringDecrypter() {
+ if (stringDecrypter == null)
+ throw new ApplicationException("SetStringDecrypterType() hasn't been called yet.");
+ }
+
+ public void LoadAssembly(string filename) {
+ LoadAssemblyInternal(filename);
+ }
+
+ public void SetStringDecrypterType(StringDecrypterType type) {
+ if (stringDecrypter != null)
+ throw new ApplicationException("StringDecrypterType already set");
+
+ switch (type) {
+ case StringDecrypterType.Delegate:
+ stringDecrypter = new DelegateStringDecrypter();
+ break;
+
+ case StringDecrypterType.Emulate:
+ stringDecrypter = new EmuStringDecrypter();
+ break;
+
+ default:
+ throw new ApplicationException(string.Format("Unknown StringDecrypterType {0}", type));
+ }
+ }
+
+ public int DefineStringDecrypter(int methodToken) {
+ CheckStringDecrypter();
+ var methodInfo = FindMethod(methodToken);
+ if (methodInfo == null)
+ throw new ApplicationException(string.Format("Could not find method {0:X8}", methodToken));
+ if (methodInfo.ReturnType != typeof(string) && methodInfo.ReturnType != typeof(object))
+ throw new ApplicationException(string.Format("Method return type must be string or object: {0}", methodInfo));
+ return stringDecrypter.DefineStringDecrypter(methodInfo);
+ }
+
+ public object[] DecryptStrings(int stringDecrypterMethod, object[] args, int callerToken) {
+ CheckStringDecrypter();
+ var caller = GetCaller(callerToken);
+ foreach (var arg in args)
+ SimpleData.Unpack((object[])arg);
+ return SimpleData.Pack(stringDecrypter.DecryptStrings(stringDecrypterMethod, args, caller));
+ }
+
+ MethodBase GetCaller(int callerToken) {
+ try {
+ return assembly.GetModules()[0].ResolveMethod(callerToken);
+ }
+ catch {
+ return null;
+ }
+ }
+
+ MethodInfo FindMethod(int methodToken) {
+ CheckAssembly();
+
+ foreach (var module in assembly.GetModules()) {
+ var method = module.ResolveMethod(methodToken) as MethodInfo;
+ if (method != null)
+ return method;
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/AssemblyData/methodsrewriter/MethodsRewriter.cs b/AssemblyData/methodsrewriter/MethodsRewriter.cs
index 117128ff..c37a9ae7 100644
--- a/AssemblyData/methodsrewriter/MethodsRewriter.cs
+++ b/AssemblyData/methodsrewriter/MethodsRewriter.cs
@@ -338,7 +338,7 @@ namespace AssemblyData.methodsrewriter {
return list;
}
- static FieldInfo GgetStackTraceStackFramesField() {
+ static FieldInfo GetStackTraceStackFramesField() {
var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
return ResolverUtils.GetFieldThrow(typeof(StackTrace), typeof(StackFrame[]), flags, "Could not find StackTrace's frames (StackFrame[]) field");
}
@@ -367,7 +367,7 @@ namespace AssemblyData.methodsrewriter {
}
StackTrace RtFixStackTrace(StackTrace stackTrace) {
- var framesField = GgetStackTraceStackFramesField();
+ var framesField = GetStackTraceStackFramesField();
var frames = (StackFrame[])framesField.GetValue(stackTrace);
var newFrames = new List(frames.Length);
diff --git a/blocks/cflow/Real8Value.cs b/blocks/cflow/Real8Value.cs
deleted file mode 100644
index 868f2339..00000000
--- a/blocks/cflow/Real8Value.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- Copyright (C) 2011-2013 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 .
-*/
-
-namespace de4dot.blocks.cflow {
- public class Real8Value : Value {
- public readonly double value;
-
- public Real8Value(double value)
- : base(ValueType.Real8) {
- this.value = value;
- }
-
- public static Real8Value Add(Real8Value a, Real8Value b) {
- return new Real8Value(a.value + b.value);
- }
-
- public static Real8Value Sub(Real8Value a, Real8Value b) {
- return new Real8Value(a.value - b.value);
- }
-
- public static Real8Value Mul(Real8Value a, Real8Value b) {
- return new Real8Value(a.value * b.value);
- }
-
- public static Real8Value Div(Real8Value a, Real8Value b) {
- return new Real8Value(a.value / b.value);
- }
-
- public static Real8Value Rem(Real8Value a, Real8Value b) {
- return new Real8Value(a.value % b.value);
- }
-
- public static Real8Value Neg(Real8Value a) {
- return new Real8Value(-a.value);
- }
- }
-}
diff --git a/blocks/BaseBlock.cs b/de4dot.blocks/BaseBlock.cs
similarity index 100%
rename from blocks/BaseBlock.cs
rename to de4dot.blocks/BaseBlock.cs
diff --git a/blocks/Block.cs b/de4dot.blocks/Block.cs
similarity index 100%
rename from blocks/Block.cs
rename to de4dot.blocks/Block.cs
diff --git a/blocks/Blocks.cs b/de4dot.blocks/Blocks.cs
similarity index 100%
rename from blocks/Blocks.cs
rename to de4dot.blocks/Blocks.cs
diff --git a/blocks/BlocksSorter.cs b/de4dot.blocks/BlocksSorter.cs
similarity index 81%
rename from blocks/BlocksSorter.cs
rename to de4dot.blocks/BlocksSorter.cs
index 2bf6aec2..484f8f1c 100644
--- a/blocks/BlocksSorter.cs
+++ b/de4dot.blocks/BlocksSorter.cs
@@ -170,38 +170,60 @@ namespace de4dot.blocks {
dest.Add(block);
}
+ struct VisitState {
+ public BlockInfo Info;
+ public List Targets;
+ public int TargetIndex;
+ public BlockInfo TargetInfo;
+ public VisitState(BlockInfo info) {
+ this.Info = info;
+ this.Targets = null;
+ this.TargetIndex = 0;
+ this.TargetInfo = null;
+ }
+ }
+ Stack visitStateStack = new Stack();
void Visit(BlockInfo info) {
- if (info.baseBlock == firstBlock)
+ // This method used to be recursive but to prevent stack overflows,
+ // it's not recursive anymore.
+
+ VisitState state = new VisitState(info);
+recursive_call:
+ if (state.Info.baseBlock == firstBlock)
throw new ApplicationException("Can't visit firstBlock");
- stack.Push(info);
- info.onStack = true;
- info.dfsNumber = dfsNumber;
- info.low = dfsNumber;
+ stack.Push(state.Info);
+ state.Info.onStack = true;
+ state.Info.dfsNumber = dfsNumber;
+ state.Info.low = dfsNumber;
dfsNumber++;
- foreach (var tmp in GetTargets(info.baseBlock)) {
- var targetInfo = GetInfo(tmp);
- if (targetInfo == null)
+ state.Targets = GetTargets(state.Info.baseBlock);
+ state.TargetIndex = 0;
+return_to_caller:
+ for (; state.TargetIndex < state.Targets.Count; state.TargetIndex++) {
+ state.TargetInfo = GetInfo(state.Targets[state.TargetIndex]);
+ if (state.TargetInfo == null)
continue;
- if (targetInfo.baseBlock == firstBlock)
+ if (state.TargetInfo.baseBlock == firstBlock)
continue;
- if (!targetInfo.Visited()) {
- Visit(targetInfo);
- info.low = Math.Min(info.low, targetInfo.low);
+ if (!state.TargetInfo.Visited()) {
+ visitStateStack.Push(state);
+ state = new VisitState(state.TargetInfo);
+ goto recursive_call;
}
- else if (targetInfo.onStack)
- info.low = Math.Min(info.low, targetInfo.dfsNumber);
+ else if (state.TargetInfo.onStack)
+ state.Info.low = Math.Min(state.Info.low, state.TargetInfo.dfsNumber);
}
- if (info.low != info.dfsNumber)
- return;
+ if (state.Info.low != state.Info.dfsNumber)
+ goto return_from_method;
var sccBlocks = new List();
while (true) {
var poppedInfo = stack.Pop();
poppedInfo.onStack = false;
sccBlocks.Add(poppedInfo.baseBlock);
- if (ReferenceEquals(info, poppedInfo))
+ if (ReferenceEquals(state.Info, poppedInfo))
break;
}
if (sccBlocks.Count > 1) {
@@ -213,6 +235,14 @@ namespace de4dot.blocks {
else {
sorted.Insert(0, sccBlocks[0]);
}
+
+return_from_method:
+ if (visitStateStack.Count == 0)
+ return;
+ state = visitStateStack.Pop();
+ state.Info.low = Math.Min(state.Info.low, state.TargetInfo.low);
+ state.TargetIndex++;
+ goto return_to_caller;
}
void SortLoopBlock(List list) {
diff --git a/blocks/CodeGenerator.cs b/de4dot.blocks/CodeGenerator.cs
similarity index 100%
rename from blocks/CodeGenerator.cs
rename to de4dot.blocks/CodeGenerator.cs
diff --git a/blocks/DeadBlocksRemover.cs b/de4dot.blocks/DeadBlocksRemover.cs
similarity index 100%
rename from blocks/DeadBlocksRemover.cs
rename to de4dot.blocks/DeadBlocksRemover.cs
diff --git a/blocks/DotNetUtils.cs b/de4dot.blocks/DotNetUtils.cs
similarity index 100%
rename from blocks/DotNetUtils.cs
rename to de4dot.blocks/DotNetUtils.cs
diff --git a/blocks/DumpedMethod.cs b/de4dot.blocks/DumpedMethod.cs
similarity index 100%
rename from blocks/DumpedMethod.cs
rename to de4dot.blocks/DumpedMethod.cs
diff --git a/blocks/DumpedMethods.cs b/de4dot.blocks/DumpedMethods.cs
similarity index 100%
rename from blocks/DumpedMethods.cs
rename to de4dot.blocks/DumpedMethods.cs
diff --git a/blocks/FilterHandlerBlock.cs b/de4dot.blocks/FilterHandlerBlock.cs
similarity index 100%
rename from blocks/FilterHandlerBlock.cs
rename to de4dot.blocks/FilterHandlerBlock.cs
diff --git a/blocks/ForwardScanOrder.cs b/de4dot.blocks/ForwardScanOrder.cs
similarity index 80%
rename from blocks/ForwardScanOrder.cs
rename to de4dot.blocks/ForwardScanOrder.cs
index a46355e0..a2029955 100644
--- a/blocks/ForwardScanOrder.cs
+++ b/de4dot.blocks/ForwardScanOrder.cs
@@ -100,25 +100,38 @@ namespace de4dot.blocks {
return false;
}
- void ScanBaseBlock(BaseBlock bb, int stackStart) {
- if (blockInfos.ContainsKey(bb) || !scopeBlock.IsOurBaseBlock(bb))
- return;
-
- var blockInfo = new BlockInfo(bb, stackStart);
- blockInfos[bb] = blockInfo;
-
- var block = bb as Block;
- if (block == null) { // i.e., if try, filter, or handler block
- // It's not important to know the exact values, so we set them both to 0.
- // Compilers must make sure the stack is empty when entering a try block.
- blockInfo.stackStart = blockInfo.stackEnd = 0;
- return;
+ struct ScanBaseBlockState {
+ public BaseBlock bb;
+ public int stackStart;
+ public ScanBaseBlockState(BaseBlock bb, int stackStart) {
+ this.bb = bb;
+ this.stackStart = stackStart;
}
+ }
+ Stack scanBaseBlockStack = new Stack();
+ void ScanBaseBlock(BaseBlock bb, int stackStart) {
+ scanBaseBlockStack.Push(new ScanBaseBlockState(bb, stackStart));
+ while (scanBaseBlockStack.Count > 0) {
+ var state = scanBaseBlockStack.Pop();
+ if (blockInfos.ContainsKey(state.bb) || !scopeBlock.IsOurBaseBlock(state.bb))
+ continue;
- blockInfo.CalculateStackUsage();
+ var blockInfo = new BlockInfo(state.bb, state.stackStart);
+ blockInfos[state.bb] = blockInfo;
- foreach (var target in block.GetTargets())
- ScanBaseBlock(target, blockInfo.stackEnd);
+ var block = state.bb as Block;
+ if (block == null) { // i.e., if try, filter, or handler block
+ // It's not important to know the exact values, so we set them both to 0.
+ // Compilers must make sure the stack is empty when entering a try block.
+ blockInfo.stackStart = blockInfo.stackEnd = 0;
+ continue;
+ }
+
+ blockInfo.CalculateStackUsage();
+
+ foreach (var target in block.GetTargets())
+ scanBaseBlockStack.Push(new ScanBaseBlockState(target, blockInfo.stackEnd));
+ }
}
void CreateNewList() {
diff --git a/blocks/GenericArgsSubstitutor.cs b/de4dot.blocks/GenericArgsSubstitutor.cs
similarity index 100%
rename from blocks/GenericArgsSubstitutor.cs
rename to de4dot.blocks/GenericArgsSubstitutor.cs
diff --git a/blocks/HandlerBlock.cs b/de4dot.blocks/HandlerBlock.cs
similarity index 100%
rename from blocks/HandlerBlock.cs
rename to de4dot.blocks/HandlerBlock.cs
diff --git a/blocks/Instr.cs b/de4dot.blocks/Instr.cs
similarity index 100%
rename from blocks/Instr.cs
rename to de4dot.blocks/Instr.cs
diff --git a/blocks/InstructionListParser.cs b/de4dot.blocks/InstructionListParser.cs
similarity index 100%
rename from blocks/InstructionListParser.cs
rename to de4dot.blocks/InstructionListParser.cs
diff --git a/blocks/MemberDefDict.cs b/de4dot.blocks/MemberDefDict.cs
similarity index 100%
rename from blocks/MemberDefDict.cs
rename to de4dot.blocks/MemberDefDict.cs
diff --git a/blocks/MethodBlocks.cs b/de4dot.blocks/MethodBlocks.cs
similarity index 100%
rename from blocks/MethodBlocks.cs
rename to de4dot.blocks/MethodBlocks.cs
diff --git a/blocks/Properties/AssemblyInfo.cs b/de4dot.blocks/Properties/AssemblyInfo.cs
similarity index 93%
rename from blocks/Properties/AssemblyInfo.cs
rename to de4dot.blocks/Properties/AssemblyInfo.cs
index a0dd84e7..59432fe2 100644
--- a/blocks/Properties/AssemblyInfo.cs
+++ b/de4dot.blocks/Properties/AssemblyInfo.cs
@@ -20,11 +20,11 @@
using System.Reflection;
using System.Runtime.InteropServices;
-[assembly: AssemblyTitle("blocks")]
+[assembly: AssemblyTitle("de4dot.blocks")]
[assembly: AssemblyDescription("Modifies dnlib MethodDef bodies")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("blocks")]
+[assembly: AssemblyProduct("de4dot.blocks")]
[assembly: AssemblyCopyright("Copyright (C) 2011-2013 de4dot@gmail.com")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
diff --git a/blocks/ScopeBlock.cs b/de4dot.blocks/ScopeBlock.cs
similarity index 100%
rename from blocks/ScopeBlock.cs
rename to de4dot.blocks/ScopeBlock.cs
diff --git a/de4dot.blocks/StackTracePatcher.cs b/de4dot.blocks/StackTracePatcher.cs
new file mode 100644
index 00000000..1d4334f7
--- /dev/null
+++ b/de4dot.blocks/StackTracePatcher.cs
@@ -0,0 +1,94 @@
+/*
+ Copyright (C) 2011-2013 de4dot@gmail.com
+
+ This file is part of de4dot.
+
+ de4dot is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ de4dot is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with de4dot. If not, see .
+*/
+
+using System;
+using System.Reflection;
+using System.Diagnostics;
+
+namespace de4dot.blocks {
+ public class StackTracePatcher {
+ static readonly FieldInfo methodField;
+ static readonly FieldInfo framesField;
+ static readonly FieldInfo methodsToSkipField;
+
+ static StackTracePatcher() {
+ methodField = GetStackFrameMethodField();
+ framesField = GetStackTraceStackFramesField();
+ methodsToSkipField = GetMethodsToSkipField();
+ }
+
+ static FieldInfo GetStackFrameMethodField() {
+ var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
+ return GetFieldThrow(typeof(StackFrame), typeof(MethodBase), flags, "Could not find StackFrame's method (MethodBase) field");
+ }
+
+ static FieldInfo GetStackTraceStackFramesField() {
+ var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
+ return GetFieldThrow(typeof(StackTrace), typeof(StackFrame[]), flags, "Could not find StackTrace's frames (StackFrame[]) field");
+ }
+
+ static FieldInfo GetMethodsToSkipField() {
+ var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
+ return GetFieldThrow(typeof(StackTrace), "m_iMethodsToSkip", flags, "Could not find StackTrace's iMethodsToSkip field");
+ }
+
+ static FieldInfo GetFieldThrow(Type type, Type fieldType, BindingFlags flags, string msg) {
+ var info = GetField(type, fieldType, flags);
+ if (info != null)
+ return info;
+ throw new ApplicationException(msg);
+ }
+
+ static FieldInfo GetField(Type type, Type fieldType, BindingFlags flags) {
+ foreach (var field in type.GetFields(flags)) {
+ if (field.FieldType == fieldType)
+ return field;
+ }
+ return null;
+ }
+
+ static FieldInfo GetFieldThrow(Type type, string fieldName, BindingFlags flags, string msg) {
+ var info = GetField(type, fieldName, flags);
+ if (info != null)
+ return info;
+ throw new ApplicationException(msg);
+ }
+
+ static FieldInfo GetField(Type type, string fieldName, BindingFlags flags) {
+ foreach (var field in type.GetFields(flags)) {
+ if (field.Name == fieldName)
+ return field;
+ }
+ return null;
+ }
+
+ public static StackTrace WriteStackFrame(StackTrace stackTrace, int frameNo, MethodBase newMethod) {
+ var frames = (StackFrame[])framesField.GetValue(stackTrace);
+ int numFramesToSkip = (int)methodsToSkipField.GetValue(stackTrace);
+ WriteMethodBase(frames[numFramesToSkip + frameNo], newMethod);
+ return stackTrace;
+ }
+
+ static void WriteMethodBase(StackFrame frame, MethodBase method) {
+ methodField.SetValue(frame, method);
+ if (frame.GetMethod() != method)
+ throw new ApplicationException(string.Format("Could not set new method: {0}", method));
+ }
+ }
+}
diff --git a/blocks/TryBlock.cs b/de4dot.blocks/TryBlock.cs
similarity index 100%
rename from blocks/TryBlock.cs
rename to de4dot.blocks/TryBlock.cs
diff --git a/blocks/TryHandlerBlock.cs b/de4dot.blocks/TryHandlerBlock.cs
similarity index 100%
rename from blocks/TryHandlerBlock.cs
rename to de4dot.blocks/TryHandlerBlock.cs
diff --git a/blocks/Utils.cs b/de4dot.blocks/Utils.cs
similarity index 100%
rename from blocks/Utils.cs
rename to de4dot.blocks/Utils.cs
diff --git a/blocks/cflow/BlockCflowDeobfuscator.cs b/de4dot.blocks/cflow/BlockCflowDeobfuscator.cs
similarity index 97%
rename from blocks/cflow/BlockCflowDeobfuscator.cs
rename to de4dot.blocks/cflow/BlockCflowDeobfuscator.cs
index 24975de0..3bc44f1f 100644
--- a/blocks/cflow/BlockCflowDeobfuscator.cs
+++ b/de4dot.blocks/cflow/BlockCflowDeobfuscator.cs
@@ -35,7 +35,7 @@ namespace de4dot.blocks.cflow {
this.block = block;
if (!block.LastInstr.IsConditionalBranch() && block.LastInstr.OpCode.Code != Code.Switch)
return false;
- instructionEmulator.Initialize(blocks);
+ instructionEmulator.Initialize(blocks, allBlocks[0] == block);
var instructions = block.Instructions;
if (instructions.Count == 0)
diff --git a/blocks/cflow/BlockDeobfuscator.cs b/de4dot.blocks/cflow/BlockDeobfuscator.cs
similarity index 100%
rename from blocks/cflow/BlockDeobfuscator.cs
rename to de4dot.blocks/cflow/BlockDeobfuscator.cs
diff --git a/blocks/cflow/BlocksCflowDeobfuscator.cs b/de4dot.blocks/cflow/BlocksCflowDeobfuscator.cs
similarity index 100%
rename from blocks/cflow/BlocksCflowDeobfuscator.cs
rename to de4dot.blocks/cflow/BlocksCflowDeobfuscator.cs
diff --git a/blocks/cflow/BranchEmulator.cs b/de4dot.blocks/cflow/BranchEmulator.cs
similarity index 100%
rename from blocks/cflow/BranchEmulator.cs
rename to de4dot.blocks/cflow/BranchEmulator.cs
diff --git a/blocks/cflow/CachedCflowDeobfuscator.cs b/de4dot.blocks/cflow/CachedCflowDeobfuscator.cs
similarity index 100%
rename from blocks/cflow/CachedCflowDeobfuscator.cs
rename to de4dot.blocks/cflow/CachedCflowDeobfuscator.cs
diff --git a/blocks/cflow/CflowDeobfuscator.cs b/de4dot.blocks/cflow/CflowDeobfuscator.cs
similarity index 100%
rename from blocks/cflow/CflowDeobfuscator.cs
rename to de4dot.blocks/cflow/CflowDeobfuscator.cs
diff --git a/blocks/cflow/CflowUtils.cs b/de4dot.blocks/cflow/CflowUtils.cs
similarity index 97%
rename from blocks/cflow/CflowUtils.cs
rename to de4dot.blocks/cflow/CflowUtils.cs
index 1f644bf1..401f75d1 100644
--- a/blocks/cflow/CflowUtils.cs
+++ b/de4dot.blocks/cflow/CflowUtils.cs
@@ -25,7 +25,7 @@ namespace de4dot.blocks.cflow {
if (!intValue.AllBitsValid())
return null;
- int index = intValue.value;
+ int index = intValue.Value;
if (targets == null || index < 0 || index >= targets.Count)
return fallThrough;
else
diff --git a/blocks/cflow/ConstantsFolder.cs b/de4dot.blocks/cflow/ConstantsFolder.cs
similarity index 96%
rename from blocks/cflow/ConstantsFolder.cs
rename to de4dot.blocks/cflow/ConstantsFolder.cs
index 43c291de..9a600dfa 100644
--- a/blocks/cflow/ConstantsFolder.cs
+++ b/de4dot.blocks/cflow/ConstantsFolder.cs
@@ -37,7 +37,7 @@ namespace de4dot.blocks.cflow {
protected override bool Deobfuscate(Block block) {
bool modified = false;
- instructionEmulator.Initialize(blocks);
+ instructionEmulator.Initialize(blocks, allBlocks[0] == block);
var instrs = block.Instructions;
for (int i = 0; i < instrs.Count; i++) {
var instr = instrs[i];
@@ -89,14 +89,14 @@ namespace de4dot.blocks.cflow {
var intValue = (Int32Value)value;
if (!intValue.AllBitsValid())
return false;
- block.Instructions[index] = new Instr(Instruction.CreateLdcI4(intValue.value));
+ block.Instructions[index] = new Instr(Instruction.CreateLdcI4(intValue.Value));
return true;
}
else if (value.IsInt64()) {
var intValue = (Int64Value)value;
if (!intValue.AllBitsValid())
return false;
- block.Instructions[index] = new Instr(OpCodes.Ldc_I8.ToInstruction(intValue.value));
+ block.Instructions[index] = new Instr(OpCodes.Ldc_I8.ToInstruction(intValue.Value));
return true;
}
return false;
diff --git a/blocks/cflow/DeadCodeRemover.cs b/de4dot.blocks/cflow/DeadCodeRemover.cs
similarity index 100%
rename from blocks/cflow/DeadCodeRemover.cs
rename to de4dot.blocks/cflow/DeadCodeRemover.cs
diff --git a/blocks/cflow/DeadStoreRemover.cs b/de4dot.blocks/cflow/DeadStoreRemover.cs
similarity index 100%
rename from blocks/cflow/DeadStoreRemover.cs
rename to de4dot.blocks/cflow/DeadStoreRemover.cs
diff --git a/blocks/cflow/DupBlockDeobfuscator.cs b/de4dot.blocks/cflow/DupBlockDeobfuscator.cs
similarity index 100%
rename from blocks/cflow/DupBlockDeobfuscator.cs
rename to de4dot.blocks/cflow/DupBlockDeobfuscator.cs
diff --git a/blocks/cflow/IBlocksDeobfuscator.cs b/de4dot.blocks/cflow/IBlocksDeobfuscator.cs
similarity index 100%
rename from blocks/cflow/IBlocksDeobfuscator.cs
rename to de4dot.blocks/cflow/IBlocksDeobfuscator.cs
diff --git a/blocks/cflow/ICflowDeobfuscator.cs b/de4dot.blocks/cflow/ICflowDeobfuscator.cs
similarity index 100%
rename from blocks/cflow/ICflowDeobfuscator.cs
rename to de4dot.blocks/cflow/ICflowDeobfuscator.cs
diff --git a/blocks/cflow/InstructionEmulator.cs b/de4dot.blocks/cflow/InstructionEmulator.cs
similarity index 68%
rename from blocks/cflow/InstructionEmulator.cs
rename to de4dot.blocks/cflow/InstructionEmulator.cs
index 3345cf64..a829d02a 100644
--- a/blocks/cflow/InstructionEmulator.cs
+++ b/de4dot.blocks/cflow/InstructionEmulator.cs
@@ -34,19 +34,24 @@ namespace de4dot.blocks.cflow {
MethodDef prev_method;
List cached_args = new List();
List cached_locals = new List();
+ List cached_zeroed_locals = new List();
public InstructionEmulator() {
}
public InstructionEmulator(MethodDef method) {
- Initialize(method);
+ Initialize(method, false);
}
- public void Initialize(Blocks blocks) {
- Initialize(blocks.Method);
+ public void Initialize(Blocks blocks, bool emulateFromFirstInstruction) {
+ Initialize(blocks.Method, emulateFromFirstInstruction);
}
public void Initialize(MethodDef method) {
+ Initialize(method, false);
+ }
+
+ public void Initialize(MethodDef method, bool emulateFromFirstInstruction) {
this.parameterDefs = method.Parameters;
this.localDefs = method.Body.Variables;
valueStack.Initialize();
@@ -60,14 +65,17 @@ namespace de4dot.blocks.cflow {
cached_args.Add(GetUnknownValue(parameterDefs[i].Type));
cached_locals.Clear();
- for (int i = 0; i < localDefs.Count; i++)
+ cached_zeroed_locals.Clear();
+ for (int i = 0; i < localDefs.Count; i++) {
cached_locals.Add(GetUnknownValue(localDefs[i].Type));
+ cached_zeroed_locals.Add(GetDefaultValue(localDefs[i].Type));
+ }
}
args.Clear();
args.AddRange(cached_args);
locals.Clear();
- locals.AddRange(cached_locals);
+ locals.AddRange(method.Body.InitLocals && emulateFromFirstInstruction ? cached_zeroed_locals : cached_locals);
}
public void SetProtected(Value value) {
@@ -95,6 +103,25 @@ namespace de4dot.blocks.cflow {
return new UnknownValue();
}
+ static Value GetDefaultValue(TypeSig type) {
+ if (type == null)
+ return new UnknownValue();
+ switch (type.ElementType) {
+ case ElementType.Boolean:
+ case ElementType.I1:
+ case ElementType.U1:
+ case ElementType.I2:
+ case ElementType.U2:
+ case ElementType.I4:
+ case ElementType.U4:
+ return Int32Value.Zero;
+ case ElementType.I8:
+ case ElementType.U8:
+ return Int64Value.Zero;
+ }
+ return new UnknownValue();
+ }
+
Value TruncateValue(Value value, TypeSig type) {
if (type == null)
return value;
@@ -141,7 +168,7 @@ namespace de4dot.blocks.cflow {
case ElementType.R4:
if (value.IsReal8())
- return new Real8Value((float)((Real8Value)value).value);
+ return ((Real8Value)value).ToSingle();
return new UnknownValue();
case ElementType.R8:
@@ -297,8 +324,8 @@ namespace de4dot.blocks.cflow {
case Code.Ldc_I8: valueStack.Push(new Int64Value((long)instr.Operand)); break;
case Code.Ldc_R4: valueStack.Push(new Real8Value((float)instr.Operand)); break;
case Code.Ldc_R8: valueStack.Push(new Real8Value((double)instr.Operand)); break;
- case Code.Ldc_I4_0: valueStack.Push(Int32Value.zero); break;
- case Code.Ldc_I4_1: valueStack.Push(Int32Value.one); break;
+ case Code.Ldc_I4_0: valueStack.Push(Int32Value.Zero); break;
+ case Code.Ldc_I4_1: valueStack.Push(Int32Value.One); break;
case Code.Ldc_I4_2: valueStack.Push(new Int32Value(2)); break;
case Code.Ldc_I4_3: valueStack.Push(new Int32Value(3)); break;
case Code.Ldc_I4_4: valueStack.Push(new Int32Value(4)); break;
@@ -347,29 +374,29 @@ namespace de4dot.blocks.cflow {
case Code.Castclass: Emulate_Castclass(instr); break;
case Code.Isinst: Emulate_Isinst(instr); break;
- case Code.Add_Ovf: EmulateIntOps2(); break;
- case Code.Add_Ovf_Un: EmulateIntOps2(); break;
- case Code.Sub_Ovf: EmulateIntOps2(); break;
- case Code.Sub_Ovf_Un: EmulateIntOps2(); break;
- case Code.Mul_Ovf: EmulateIntOps2(); break;
- case Code.Mul_Ovf_Un: EmulateIntOps2(); break;
+ case Code.Add_Ovf: Emulate_Add_Ovf(instr); break;
+ case Code.Add_Ovf_Un: Emulate_Add_Ovf_Un(instr); break;
+ case Code.Sub_Ovf: Emulate_Sub_Ovf(instr); break;
+ case Code.Sub_Ovf_Un: Emulate_Sub_Ovf_Un(instr); break;
+ case Code.Mul_Ovf: Emulate_Mul_Ovf(instr); break;
+ case Code.Mul_Ovf_Un: Emulate_Mul_Ovf_Un(instr); break;
- case Code.Conv_Ovf_I1:
- case Code.Conv_Ovf_I1_Un: valueStack.Pop(); valueStack.Push(Int32Value.CreateUnknown()); break;
- case Code.Conv_Ovf_I2:
- case Code.Conv_Ovf_I2_Un: valueStack.Pop(); valueStack.Push(Int32Value.CreateUnknown()); break;
- case Code.Conv_Ovf_I4:
- case Code.Conv_Ovf_I4_Un: valueStack.Pop(); valueStack.Push(Int32Value.CreateUnknown()); break;
- case Code.Conv_Ovf_I8:
- case Code.Conv_Ovf_I8_Un: valueStack.Pop(); valueStack.Push(Int64Value.CreateUnknown()); break;
- case Code.Conv_Ovf_U1:
- case Code.Conv_Ovf_U1_Un: valueStack.Pop(); valueStack.Push(Int32Value.CreateUnknownUInt8()); break;
- case Code.Conv_Ovf_U2:
- case Code.Conv_Ovf_U2_Un: valueStack.Pop(); valueStack.Push(Int32Value.CreateUnknownUInt16()); break;
- case Code.Conv_Ovf_U4:
- case Code.Conv_Ovf_U4_Un: valueStack.Pop(); valueStack.Push(Int32Value.CreateUnknown()); break;
- case Code.Conv_Ovf_U8:
- case Code.Conv_Ovf_U8_Un: valueStack.Pop(); valueStack.Push(Int64Value.CreateUnknown()); break;
+ case Code.Conv_Ovf_I1: Emulate_Conv_Ovf_I1(instr); break;
+ case Code.Conv_Ovf_I1_Un: Emulate_Conv_Ovf_I1_Un(instr); break;
+ case Code.Conv_Ovf_I2: Emulate_Conv_Ovf_I2(instr); break;
+ case Code.Conv_Ovf_I2_Un: Emulate_Conv_Ovf_I2_Un(instr); break;
+ case Code.Conv_Ovf_I4: Emulate_Conv_Ovf_I4(instr); break;
+ case Code.Conv_Ovf_I4_Un: Emulate_Conv_Ovf_I4_Un(instr); break;
+ case Code.Conv_Ovf_I8: Emulate_Conv_Ovf_I8(instr); break;
+ case Code.Conv_Ovf_I8_Un: Emulate_Conv_Ovf_I8_Un(instr); break;
+ case Code.Conv_Ovf_U1: Emulate_Conv_Ovf_U1(instr); break;
+ case Code.Conv_Ovf_U1_Un: Emulate_Conv_Ovf_U1_Un(instr); break;
+ case Code.Conv_Ovf_U2: Emulate_Conv_Ovf_U2(instr); break;
+ case Code.Conv_Ovf_U2_Un: Emulate_Conv_Ovf_U2_Un(instr); break;
+ case Code.Conv_Ovf_U4: Emulate_Conv_Ovf_U4(instr); break;
+ case Code.Conv_Ovf_U4_Un: Emulate_Conv_Ovf_U4_Un(instr); break;
+ case Code.Conv_Ovf_U8: Emulate_Conv_Ovf_U8(instr); break;
+ case Code.Conv_Ovf_U8_Un: Emulate_Conv_Ovf_U8_Un(instr); break;
case Code.Ldelem_I1: valueStack.Pop(2); valueStack.Push(Int32Value.CreateUnknown()); break;
case Code.Ldelem_I2: valueStack.Pop(2); valueStack.Push(Int32Value.CreateUnknown()); break;
@@ -595,6 +622,166 @@ namespace de4dot.blocks.cflow {
}
}
+ void Emulate_Conv_Ovf_I1(Instruction instr) {
+ var val1 = valueStack.Pop();
+ switch (val1.valueType) {
+ case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_I1((Int32Value)val1)); break;
+ case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_I1((Int64Value)val1)); break;
+ case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_I1((Real8Value)val1)); break;
+ default: valueStack.Push(Int32Value.CreateUnknown()); break;
+ }
+ }
+
+ void Emulate_Conv_Ovf_I1_Un(Instruction instr) {
+ var val1 = valueStack.Pop();
+ switch (val1.valueType) {
+ case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_I1_Un((Int32Value)val1)); break;
+ case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_I1_Un((Int64Value)val1)); break;
+ case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_I1_Un((Real8Value)val1)); break;
+ default: valueStack.Push(Int32Value.CreateUnknown()); break;
+ }
+ }
+
+ void Emulate_Conv_Ovf_I2(Instruction instr) {
+ var val1 = valueStack.Pop();
+ switch (val1.valueType) {
+ case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_I2((Int32Value)val1)); break;
+ case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_I2((Int64Value)val1)); break;
+ case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_I2((Real8Value)val1)); break;
+ default: valueStack.Push(Int32Value.CreateUnknown()); break;
+ }
+ }
+
+ void Emulate_Conv_Ovf_I2_Un(Instruction instr) {
+ var val1 = valueStack.Pop();
+ switch (val1.valueType) {
+ case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_I2_Un((Int32Value)val1)); break;
+ case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_I2_Un((Int64Value)val1)); break;
+ case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_I2_Un((Real8Value)val1)); break;
+ default: valueStack.Push(Int32Value.CreateUnknown()); break;
+ }
+ }
+
+ void Emulate_Conv_Ovf_I4(Instruction instr) {
+ var val1 = valueStack.Pop();
+ switch (val1.valueType) {
+ case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_I4((Int32Value)val1)); break;
+ case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_I4((Int64Value)val1)); break;
+ case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_I4((Real8Value)val1)); break;
+ default: valueStack.Push(Int32Value.CreateUnknown()); break;
+ }
+ }
+
+ void Emulate_Conv_Ovf_I4_Un(Instruction instr) {
+ var val1 = valueStack.Pop();
+ switch (val1.valueType) {
+ case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_I4_Un((Int32Value)val1)); break;
+ case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_I4_Un((Int64Value)val1)); break;
+ case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_I4_Un((Real8Value)val1)); break;
+ default: valueStack.Push(Int32Value.CreateUnknown()); break;
+ }
+ }
+
+ void Emulate_Conv_Ovf_I8(Instruction instr) {
+ var val1 = valueStack.Pop();
+ switch (val1.valueType) {
+ case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_I8((Int32Value)val1)); break;
+ case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_I8((Int64Value)val1)); break;
+ case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_I8((Real8Value)val1)); break;
+ default: valueStack.Push(Int64Value.CreateUnknown()); break;
+ }
+ }
+
+ void Emulate_Conv_Ovf_I8_Un(Instruction instr) {
+ var val1 = valueStack.Pop();
+ switch (val1.valueType) {
+ case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_I8_Un((Int32Value)val1)); break;
+ case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_I8_Un((Int64Value)val1)); break;
+ case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_I8_Un((Real8Value)val1)); break;
+ default: valueStack.Push(Int64Value.CreateUnknown()); break;
+ }
+ }
+
+ void Emulate_Conv_Ovf_U1(Instruction instr) {
+ var val1 = valueStack.Pop();
+ switch (val1.valueType) {
+ case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_U1((Int32Value)val1)); break;
+ case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_U1((Int64Value)val1)); break;
+ case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_U1((Real8Value)val1)); break;
+ default: valueStack.Push(Int32Value.CreateUnknownUInt8()); break;
+ }
+ }
+
+ void Emulate_Conv_Ovf_U1_Un(Instruction instr) {
+ var val1 = valueStack.Pop();
+ switch (val1.valueType) {
+ case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_U1_Un((Int32Value)val1)); break;
+ case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_U1_Un((Int64Value)val1)); break;
+ case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_U1_Un((Real8Value)val1)); break;
+ default: valueStack.Push(Int32Value.CreateUnknownUInt8()); break;
+ }
+ }
+
+ void Emulate_Conv_Ovf_U2(Instruction instr) {
+ var val1 = valueStack.Pop();
+ switch (val1.valueType) {
+ case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_U2((Int32Value)val1)); break;
+ case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_U2((Int64Value)val1)); break;
+ case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_U2((Real8Value)val1)); break;
+ default: valueStack.Push(Int32Value.CreateUnknownUInt16()); break;
+ }
+ }
+
+ void Emulate_Conv_Ovf_U2_Un(Instruction instr) {
+ var val1 = valueStack.Pop();
+ switch (val1.valueType) {
+ case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_U2_Un((Int32Value)val1)); break;
+ case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_U2_Un((Int64Value)val1)); break;
+ case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_U2_Un((Real8Value)val1)); break;
+ default: valueStack.Push(Int32Value.CreateUnknownUInt16()); break;
+ }
+ }
+
+ void Emulate_Conv_Ovf_U4(Instruction instr) {
+ var val1 = valueStack.Pop();
+ switch (val1.valueType) {
+ case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_U4((Int32Value)val1)); break;
+ case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_U4((Int64Value)val1)); break;
+ case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_U4((Real8Value)val1)); break;
+ default: valueStack.Push(Int32Value.CreateUnknown()); break;
+ }
+ }
+
+ void Emulate_Conv_Ovf_U4_Un(Instruction instr) {
+ var val1 = valueStack.Pop();
+ switch (val1.valueType) {
+ case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_U4_Un((Int32Value)val1)); break;
+ case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_U4_Un((Int64Value)val1)); break;
+ case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_U4_Un((Real8Value)val1)); break;
+ default: valueStack.Push(Int32Value.CreateUnknown()); break;
+ }
+ }
+
+ void Emulate_Conv_Ovf_U8(Instruction instr) {
+ var val1 = valueStack.Pop();
+ switch (val1.valueType) {
+ case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_U8((Int32Value)val1)); break;
+ case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_U8((Int64Value)val1)); break;
+ case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_U8((Real8Value)val1)); break;
+ default: valueStack.Push(Int64Value.CreateUnknown()); break;
+ }
+ }
+
+ void Emulate_Conv_Ovf_U8_Un(Instruction instr) {
+ var val1 = valueStack.Pop();
+ switch (val1.valueType) {
+ case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_U8_Un((Int32Value)val1)); break;
+ case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_U8_Un((Int64Value)val1)); break;
+ case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_U8_Un((Real8Value)val1)); break;
+ default: valueStack.Push(Int64Value.CreateUnknown()); break;
+ }
+ }
+
void Emulate_Add(Instruction instr) {
var val2 = valueStack.Pop();
var val1 = valueStack.Pop();
@@ -702,6 +889,90 @@ namespace de4dot.blocks.cflow {
valueStack.PushUnknown();
}
+ void Emulate_Add_Ovf(Instruction instr) {
+ var val2 = valueStack.Pop();
+ var val1 = valueStack.Pop();
+
+ if (val1.IsInt32() && val2.IsInt32())
+ valueStack.Push(Int32Value.Add_Ovf((Int32Value)val1, (Int32Value)val2));
+ else if (val1.IsInt64() && val2.IsInt64())
+ valueStack.Push(Int64Value.Add_Ovf((Int64Value)val1, (Int64Value)val2));
+ else if (val1.IsReal8() && val2.IsReal8())
+ valueStack.Push(Real8Value.Add_Ovf((Real8Value)val1, (Real8Value)val2));
+ else
+ valueStack.PushUnknown();
+ }
+
+ void Emulate_Add_Ovf_Un(Instruction instr) {
+ var val2 = valueStack.Pop();
+ var val1 = valueStack.Pop();
+
+ if (val1.IsInt32() && val2.IsInt32())
+ valueStack.Push(Int32Value.Add_Ovf_Un((Int32Value)val1, (Int32Value)val2));
+ else if (val1.IsInt64() && val2.IsInt64())
+ valueStack.Push(Int64Value.Add_Ovf_Un((Int64Value)val1, (Int64Value)val2));
+ else if (val1.IsReal8() && val2.IsReal8())
+ valueStack.Push(Real8Value.Add_Ovf_Un((Real8Value)val1, (Real8Value)val2));
+ else
+ valueStack.PushUnknown();
+ }
+
+ void Emulate_Sub_Ovf(Instruction instr) {
+ var val2 = valueStack.Pop();
+ var val1 = valueStack.Pop();
+
+ if (val1.IsInt32() && val2.IsInt32())
+ valueStack.Push(Int32Value.Sub_Ovf((Int32Value)val1, (Int32Value)val2));
+ else if (val1.IsInt64() && val2.IsInt64())
+ valueStack.Push(Int64Value.Sub_Ovf((Int64Value)val1, (Int64Value)val2));
+ else if (val1.IsReal8() && val2.IsReal8())
+ valueStack.Push(Real8Value.Sub_Ovf((Real8Value)val1, (Real8Value)val2));
+ else
+ valueStack.PushUnknown();
+ }
+
+ void Emulate_Sub_Ovf_Un(Instruction instr) {
+ var val2 = valueStack.Pop();
+ var val1 = valueStack.Pop();
+
+ if (val1.IsInt32() && val2.IsInt32())
+ valueStack.Push(Int32Value.Sub_Ovf_Un((Int32Value)val1, (Int32Value)val2));
+ else if (val1.IsInt64() && val2.IsInt64())
+ valueStack.Push(Int64Value.Sub_Ovf_Un((Int64Value)val1, (Int64Value)val2));
+ else if (val1.IsReal8() && val2.IsReal8())
+ valueStack.Push(Real8Value.Sub_Ovf_Un((Real8Value)val1, (Real8Value)val2));
+ else
+ valueStack.PushUnknown();
+ }
+
+ void Emulate_Mul_Ovf(Instruction instr) {
+ var val2 = valueStack.Pop();
+ var val1 = valueStack.Pop();
+
+ if (val1.IsInt32() && val2.IsInt32())
+ valueStack.Push(Int32Value.Mul_Ovf((Int32Value)val1, (Int32Value)val2));
+ else if (val1.IsInt64() && val2.IsInt64())
+ valueStack.Push(Int64Value.Mul_Ovf((Int64Value)val1, (Int64Value)val2));
+ else if (val1.IsReal8() && val2.IsReal8())
+ valueStack.Push(Real8Value.Mul_Ovf((Real8Value)val1, (Real8Value)val2));
+ else
+ valueStack.PushUnknown();
+ }
+
+ void Emulate_Mul_Ovf_Un(Instruction instr) {
+ var val2 = valueStack.Pop();
+ var val1 = valueStack.Pop();
+
+ if (val1.IsInt32() && val2.IsInt32())
+ valueStack.Push(Int32Value.Mul_Ovf_Un((Int32Value)val1, (Int32Value)val2));
+ else if (val1.IsInt64() && val2.IsInt64())
+ valueStack.Push(Int64Value.Mul_Ovf_Un((Int64Value)val1, (Int64Value)val2));
+ else if (val1.IsReal8() && val2.IsReal8())
+ valueStack.Push(Real8Value.Mul_Ovf_Un((Real8Value)val1, (Real8Value)val2));
+ else
+ valueStack.PushUnknown();
+ }
+
void Emulate_And(Instruction instr) {
var val2 = valueStack.Pop();
var val1 = valueStack.Pop();
@@ -794,7 +1065,7 @@ namespace de4dot.blocks.cflow {
else if (val1.IsInt64() && val2.IsInt64())
valueStack.Push(Int64Value.Ceq((Int64Value)val1, (Int64Value)val2));
else if (val1.IsNull() && val2.IsNull())
- valueStack.Push(Int32Value.one);
+ valueStack.Push(Int32Value.One);
else
valueStack.Push(Int32Value.CreateUnknownBool());
}
diff --git a/blocks/cflow/Int32Value.cs b/de4dot.blocks/cflow/Int32Value.cs
similarity index 52%
rename from blocks/cflow/Int32Value.cs
rename to de4dot.blocks/cflow/Int32Value.cs
index f885bf6a..bb838288 100644
--- a/blocks/cflow/Int32Value.cs
+++ b/de4dot.blocks/cflow/Int32Value.cs
@@ -21,27 +21,27 @@ using System;
namespace de4dot.blocks.cflow {
public class Int32Value : Value {
- public static readonly Int32Value zero = new Int32Value(0);
- public static readonly Int32Value one = new Int32Value(1);
+ public static readonly Int32Value Zero = new Int32Value(0);
+ public static readonly Int32Value One = new Int32Value(1);
- const uint NO_UNKNOWN_BITS = uint.MaxValue;
- public readonly int value;
- public readonly uint validMask;
+ internal const uint NO_UNKNOWN_BITS = uint.MaxValue;
+ public readonly int Value;
+ public readonly uint ValidMask;
public Int32Value(int value)
: base(ValueType.Int32) {
- this.value = value;
- this.validMask = NO_UNKNOWN_BITS;
+ this.Value = value;
+ this.ValidMask = NO_UNKNOWN_BITS;
}
public Int32Value(int value, uint validMask)
: base(ValueType.Int32) {
- this.value = value;
- this.validMask = validMask;
+ this.Value = value;
+ this.ValidMask = validMask;
}
public bool HasUnknownBits() {
- return validMask != NO_UNKNOWN_BITS;
+ return ValidMask != NO_UNKNOWN_BITS;
}
public bool AllBitsValid() {
@@ -49,13 +49,17 @@ namespace de4dot.blocks.cflow {
}
bool IsBitValid(int n) {
- return IsBitValid(validMask, n);
+ return IsBitValid(ValidMask, n);
}
static bool IsBitValid(uint validMask, int n) {
return (validMask & (1U << n)) != 0;
}
+ bool AreBitsValid(uint bitsToTest) {
+ return (ValidMask & bitsToTest) == bitsToTest;
+ }
+
public static Int32Value CreateUnknownBool() {
return new Int32Value(0, NO_UNKNOWN_BITS << 1);
}
@@ -77,11 +81,11 @@ namespace de4dot.blocks.cflow {
}
public bool IsNonZero() {
- return (value & validMask) != 0;
+ return ((uint)Value & ValidMask) != 0;
}
public bool HasValue(int value) {
- return AllBitsValid() && this.value == value;
+ return AllBitsValid() && this.Value == value;
}
public bool HasValue(uint value) {
@@ -113,11 +117,11 @@ namespace de4dot.blocks.cflow {
}
public static Int32Value Conv_U1(Int32Value a) {
- return Conv_U1(a.value, a.validMask);
+ return Conv_U1(a.Value, a.ValidMask);
}
public static Int32Value Conv_U1(Int64Value a) {
- return Conv_U1((int)a.value, (uint)a.validMask);
+ return Conv_U1((int)a.Value, (uint)a.ValidMask);
}
public static Int32Value Conv_U1(int value, uint validMask) {
@@ -127,15 +131,17 @@ namespace de4dot.blocks.cflow {
}
public static Int32Value Conv_U1(Real8Value a) {
- return new Int32Value((int)(byte)a.value);
+ if (!a.IsValid)
+ return CreateUnknownUInt8();
+ return new Int32Value((int)(byte)a.Value);
}
public static Int32Value Conv_I1(Int32Value a) {
- return Conv_I1(a.value, a.validMask);
+ return Conv_I1(a.Value, a.ValidMask);
}
public static Int32Value Conv_I1(Int64Value a) {
- return Conv_I1((int)a.value, (uint)a.validMask);
+ return Conv_I1((int)a.Value, (uint)a.ValidMask);
}
public static Int32Value Conv_I1(int value, uint validMask) {
@@ -148,15 +154,17 @@ namespace de4dot.blocks.cflow {
}
public static Int32Value Conv_I1(Real8Value a) {
- return new Int32Value((int)(sbyte)a.value);
+ if (!a.IsValid)
+ return CreateUnknown();
+ return new Int32Value((int)(sbyte)a.Value);
}
public static Int32Value Conv_U2(Int32Value a) {
- return Conv_U2(a.value, a.validMask);
+ return Conv_U2(a.Value, a.ValidMask);
}
public static Int32Value Conv_U2(Int64Value a) {
- return Conv_U2((int)a.value, (uint)a.validMask);
+ return Conv_U2((int)a.Value, (uint)a.ValidMask);
}
public static Int32Value Conv_U2(int value, uint validMask) {
@@ -166,15 +174,17 @@ namespace de4dot.blocks.cflow {
}
public static Int32Value Conv_U2(Real8Value a) {
- return new Int32Value((int)(ushort)a.value);
+ if (!a.IsValid)
+ return CreateUnknownUInt16();
+ return new Int32Value((int)(ushort)a.Value);
}
public static Int32Value Conv_I2(Int32Value a) {
- return Conv_I2(a.value, a.validMask);
+ return Conv_I2(a.Value, a.ValidMask);
}
public static Int32Value Conv_I2(Int64Value a) {
- return Conv_I2((int)a.value, (uint)a.validMask);
+ return Conv_I2((int)a.Value, (uint)a.ValidMask);
}
public static Int32Value Conv_I2(int value, uint validMask) {
@@ -187,7 +197,9 @@ namespace de4dot.blocks.cflow {
}
public static Int32Value Conv_I2(Real8Value a) {
- return new Int32Value((int)(short)a.value);
+ if (!a.IsValid)
+ return CreateUnknown();
+ return new Int32Value((int)(short)a.Value);
}
public static Int32Value Conv_U4(Int32Value a) {
@@ -195,11 +207,13 @@ namespace de4dot.blocks.cflow {
}
public static Int32Value Conv_U4(Int64Value a) {
- return new Int32Value((int)(uint)a.value, (uint)a.validMask);
+ return new Int32Value((int)(uint)a.Value, (uint)a.ValidMask);
}
public static Int32Value Conv_U4(Real8Value a) {
- return new Int32Value((int)(uint)a.value);
+ if (!a.IsValid)
+ return CreateUnknown();
+ return new Int32Value((int)(uint)a.Value);
}
public static Int32Value Conv_I4(Int32Value a) {
@@ -207,34 +221,137 @@ namespace de4dot.blocks.cflow {
}
public static Int32Value Conv_I4(Int64Value a) {
- return new Int32Value((int)a.value, (uint)a.validMask);
+ return new Int32Value((int)a.Value, (uint)a.ValidMask);
}
public static Int32Value Conv_I4(Real8Value a) {
- return new Int32Value((int)a.value);
+ if (!a.IsValid)
+ return CreateUnknown();
+ return new Int32Value((int)a.Value);
+ }
+
+ bool CheckSign(uint mask) {
+ return ((uint)Value & mask) == 0 || ((uint)Value & mask) == mask;
+ }
+
+ public static Int32Value Conv_Ovf_I1(Int32Value a) {
+ if (!a.AreBitsValid(NO_UNKNOWN_BITS << 7) ||
+ !a.CheckSign(NO_UNKNOWN_BITS << 7))
+ return CreateUnknown();
+ return Conv_I1(a);
+ }
+
+ public static Int32Value Conv_Ovf_I1_Un(Int32Value a) {
+ if (!a.AreBitsValid(NO_UNKNOWN_BITS << 7) ||
+ (uint)a.Value > sbyte.MaxValue)
+ return CreateUnknown();
+ return Conv_I1(a);
+ }
+
+ public static Int32Value Conv_Ovf_I2(Int32Value a) {
+ if (!a.AreBitsValid(NO_UNKNOWN_BITS << 15) ||
+ !a.CheckSign(NO_UNKNOWN_BITS << 15))
+ return CreateUnknown();
+ return Conv_I2(a);
+ }
+
+ public static Int32Value Conv_Ovf_I2_Un(Int32Value a) {
+ if (!a.AreBitsValid(NO_UNKNOWN_BITS << 15) ||
+ (uint)a.Value > short.MaxValue)
+ return CreateUnknown();
+ return Conv_I2(a);
+ }
+
+ public static Int32Value Conv_Ovf_I4(Int32Value a) {
+ return a;
+ }
+
+ public static Int32Value Conv_Ovf_I4_Un(Int32Value a) {
+ if (!IsBitValid(a.ValidMask, 31) || a.Value < 0)
+ return CreateUnknown();
+ return a;
+ }
+
+ public static Int64Value Conv_Ovf_I8(Int32Value a) {
+ ulong validMask = a.ValidMask;
+ if (IsBitValid(a.ValidMask, 31))
+ validMask |= Int64Value.NO_UNKNOWN_BITS << 32;
+ return new Int64Value(a.Value, validMask);
+ }
+
+ public static Int64Value Conv_Ovf_I8_Un(Int32Value a) {
+ return new Int64Value((long)(uint)a.Value, a.ValidMask | (Int64Value.NO_UNKNOWN_BITS << 32));
+ }
+
+ public static Int32Value Conv_Ovf_U1(Int32Value a) {
+ if (!a.AreBitsValid(NO_UNKNOWN_BITS << 7) ||
+ a.Value < 0 || a.Value > byte.MaxValue)
+ return CreateUnknownUInt8();
+ return Conv_U1(a);
+ }
+
+ public static Int32Value Conv_Ovf_U1_Un(Int32Value a) {
+ if (!a.AreBitsValid(NO_UNKNOWN_BITS << 8) ||
+ (uint)a.Value > byte.MaxValue)
+ return CreateUnknownUInt8();
+ return Conv_U1(a);
+ }
+
+ public static Int32Value Conv_Ovf_U2(Int32Value a) {
+ if (!a.AreBitsValid(NO_UNKNOWN_BITS << 15) ||
+ a.Value < 0 || a.Value > ushort.MaxValue)
+ return CreateUnknownUInt16();
+ return Conv_U2(a);
+ }
+
+ public static Int32Value Conv_Ovf_U2_Un(Int32Value a) {
+ if (!a.AreBitsValid(NO_UNKNOWN_BITS << 16) ||
+ (uint)a.Value > ushort.MaxValue)
+ return CreateUnknownUInt16();
+ return Conv_U2(a);
+ }
+
+ public static Int32Value Conv_Ovf_U4(Int32Value a) {
+ if (!IsBitValid(a.ValidMask, 31) || a.Value < 0)
+ return CreateUnknown();
+ return a;
+ }
+
+ public static Int32Value Conv_Ovf_U4_Un(Int32Value a) {
+ return a;
+ }
+
+ public static Int64Value Conv_Ovf_U8(Int32Value a) {
+ if (!IsBitValid(a.ValidMask, 31) || a.Value < 0)
+ return Int64Value.CreateUnknown();
+ return new Int64Value(a.Value, (ulong)a.ValidMask | (Int64Value.NO_UNKNOWN_BITS << 32));
+ }
+
+ public static Int64Value Conv_Ovf_U8_Un(Int32Value a) {
+ return new Int64Value((long)(uint)a.Value, a.ValidMask | (Int64Value.NO_UNKNOWN_BITS << 32));
}
public static Int32Value Add(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
- return new Int32Value(a.value + b.value);
+ return new Int32Value(a.Value + b.Value);
if (ReferenceEquals(a, b))
- return new Int32Value(a.value << 1, (a.validMask << 1) | 1);
+ return new Int32Value(a.Value << 1, (a.ValidMask << 1) | 1);
return CreateUnknown();
}
public static Int32Value Sub(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
- return new Int32Value(a.value - b.value);
+ return new Int32Value(a.Value - b.Value);
if (ReferenceEquals(a, b))
- return zero;
+ return Zero;
return CreateUnknown();
}
public static Int32Value Mul(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
- return new Int32Value(a.value * b.value);
+ return new Int32Value(a.Value * b.Value);
if (a.IsZero() || b.IsZero())
- return zero;
+ return Zero;
if (a.HasValue(1))
return b;
if (b.HasValue(1))
@@ -245,14 +362,14 @@ namespace de4dot.blocks.cflow {
public static Int32Value Div(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid()) {
try {
- return new Int32Value(a.value / b.value);
+ return new Int32Value(a.Value / b.Value);
}
catch (ArithmeticException) {
return CreateUnknown();
}
}
if (ReferenceEquals(a, b) && a.IsNonZero())
- return one;
+ return One;
if (b.HasValue(1))
return a;
return CreateUnknown();
@@ -261,14 +378,14 @@ namespace de4dot.blocks.cflow {
public static Int32Value Div_Un(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid()) {
try {
- return new Int32Value((int)((uint)a.value / (uint)b.value));
+ return new Int32Value((int)((uint)a.Value / (uint)b.Value));
}
catch (ArithmeticException) {
return CreateUnknown();
}
}
if (ReferenceEquals(a, b) && a.IsNonZero())
- return one;
+ return One;
if (b.HasValue(1))
return a;
return CreateUnknown();
@@ -277,150 +394,219 @@ namespace de4dot.blocks.cflow {
public static Int32Value Rem(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid()) {
try {
- return new Int32Value(a.value % b.value);
+ return new Int32Value(a.Value % b.Value);
}
catch (ArithmeticException) {
return CreateUnknown();
}
}
if ((ReferenceEquals(a, b) && a.IsNonZero()) || b.HasValue(1))
- return zero;
+ return Zero;
return CreateUnknown();
}
public static Int32Value Rem_Un(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid()) {
try {
- return new Int32Value((int)((uint)a.value % (uint)b.value));
+ return new Int32Value((int)((uint)a.Value % (uint)b.Value));
}
catch (ArithmeticException) {
return CreateUnknown();
}
}
if ((ReferenceEquals(a, b) && a.IsNonZero()) || b.HasValue(1))
- return zero;
+ return Zero;
return CreateUnknown();
}
public static Int32Value Neg(Int32Value a) {
if (a.AllBitsValid())
- return new Int32Value(-a.value);
+ return new Int32Value(-a.Value);
+ return CreateUnknown();
+ }
+
+ public static Int32Value Add_Ovf(Int32Value a, Int32Value b) {
+ if (a.AllBitsValid() && b.AllBitsValid()) {
+ try {
+ return new Int32Value(checked(a.Value + b.Value));
+ }
+ catch (OverflowException) {
+ }
+ }
+ return CreateUnknown();
+ }
+
+ public static Int32Value Add_Ovf_Un(Int32Value a, Int32Value b) {
+ if (a.AllBitsValid() && b.AllBitsValid()) {
+ uint aa = (uint)a.Value, bb = (uint)b.Value;
+ try {
+ return new Int32Value((int)checked(aa + bb));
+ }
+ catch (OverflowException) {
+ }
+ }
+ return CreateUnknown();
+ }
+
+ public static Int32Value Sub_Ovf(Int32Value a, Int32Value b) {
+ if (a.AllBitsValid() && b.AllBitsValid()) {
+ try {
+ return new Int32Value(checked(a.Value - b.Value));
+ }
+ catch (OverflowException) {
+ }
+ }
+ return CreateUnknown();
+ }
+
+ public static Int32Value Sub_Ovf_Un(Int32Value a, Int32Value b) {
+ if (a.AllBitsValid() && b.AllBitsValid()) {
+ uint aa = (uint)a.Value, bb = (uint)b.Value;
+ try {
+ return new Int32Value((int)checked(aa - bb));
+ }
+ catch (OverflowException) {
+ }
+ }
+ return CreateUnknown();
+ }
+
+ public static Int32Value Mul_Ovf(Int32Value a, Int32Value b) {
+ if (a.AllBitsValid() && b.AllBitsValid()) {
+ try {
+ return new Int32Value(checked(a.Value * b.Value));
+ }
+ catch (OverflowException) {
+ }
+ }
+ return CreateUnknown();
+ }
+
+ public static Int32Value Mul_Ovf_Un(Int32Value a, Int32Value b) {
+ if (a.AllBitsValid() && b.AllBitsValid()) {
+ uint aa = (uint)a.Value, bb = (uint)b.Value;
+ try {
+ return new Int32Value((int)checked(aa * bb));
+ }
+ catch (OverflowException) {
+ }
+ }
return CreateUnknown();
}
public static Int32Value And(Int32Value a, Int32Value b) {
- int av = a.value, bv = b.value;
- uint am = a.validMask, bm = b.validMask;
- return new Int32Value(av & bv, (uint)((am & bm) | ((av & am) ^ am) | ((bv & bm) ^ bm)));
+ int av = a.Value, bv = b.Value;
+ uint am = a.ValidMask, bm = b.ValidMask;
+ return new Int32Value(av & bv, (am & bm) | (((uint)av & am) ^ am) | (((uint)bv & bm) ^ bm));
}
public static Int32Value Or(Int32Value a, Int32Value b) {
- int av = a.value, bv = b.value;
- uint am = a.validMask, bm = b.validMask;
- return new Int32Value(av | bv, (uint)((am & bm) | (av & am) | (bv & bm)));
+ int av = a.Value, bv = b.Value;
+ uint am = a.ValidMask, bm = b.ValidMask;
+ return new Int32Value(av | bv, (am & bm) | ((uint)av & am) | ((uint)bv & bm));
}
public static Int32Value Xor(Int32Value a, Int32Value b) {
if (ReferenceEquals(a, b))
- return zero;
- int av = a.value, bv = b.value;
- uint am = a.validMask, bm = b.validMask;
- return new Int32Value(av ^ bv, (uint)(am & bm));
+ return Zero;
+ int av = a.Value, bv = b.Value;
+ uint am = a.ValidMask, bm = b.ValidMask;
+ return new Int32Value(av ^ bv, am & bm);
}
public static Int32Value Not(Int32Value a) {
- return new Int32Value(~a.value, a.validMask);
+ return new Int32Value(~a.Value, a.ValidMask);
}
public static Int32Value Shl(Int32Value a, Int32Value b) {
if (b.HasUnknownBits())
return CreateUnknown();
- if (b.value == 0)
+ if (b.Value == 0)
return a;
- if (b.value < 0 || b.value >= sizeof(int) * 8)
+ if (b.Value < 0 || b.Value >= sizeof(int) * 8)
return CreateUnknown();
- int shift = b.value;
- uint validMask = (a.validMask << shift) | (uint.MaxValue >> (sizeof(int) * 8 - shift));
- return new Int32Value(a.value << shift, validMask);
+ int shift = b.Value;
+ uint validMask = (a.ValidMask << shift) | (uint.MaxValue >> (sizeof(int) * 8 - shift));
+ return new Int32Value(a.Value << shift, validMask);
}
public static Int32Value Shr(Int32Value a, Int32Value b) {
if (b.HasUnknownBits())
return CreateUnknown();
- if (b.value == 0)
+ if (b.Value == 0)
return a;
- if (b.value < 0 || b.value >= sizeof(int) * 8)
+ if (b.Value < 0 || b.Value >= sizeof(int) * 8)
return CreateUnknown();
- int shift = b.value;
- uint validMask = a.validMask >> shift;
+ int shift = b.Value;
+ uint validMask = a.ValidMask >> shift;
if (a.IsBitValid(sizeof(int) * 8 - 1))
validMask |= (uint.MaxValue << (sizeof(int) * 8 - shift));
- return new Int32Value(a.value >> shift, validMask);
+ return new Int32Value(a.Value >> shift, validMask);
}
public static Int32Value Shr_Un(Int32Value a, Int32Value b) {
if (b.HasUnknownBits())
return CreateUnknown();
- if (b.value == 0)
+ if (b.Value == 0)
return a;
- if (b.value < 0 || b.value >= sizeof(int) * 8)
+ if (b.Value < 0 || b.Value >= sizeof(int) * 8)
return CreateUnknown();
- int shift = b.value;
- uint validMask = (a.validMask >> shift) | (uint.MaxValue << (sizeof(int) * 8 - shift));
- return new Int32Value((int)((uint)a.value >> shift), validMask);
+ int shift = b.Value;
+ uint validMask = (a.ValidMask >> shift) | (uint.MaxValue << (sizeof(int) * 8 - shift));
+ return new Int32Value((int)((uint)a.Value >> shift), validMask);
}
- static Int32Value create(Bool3 b) {
+ static Int32Value Create(Bool3 b) {
switch (b) {
- case Bool3.False: return zero;
- case Bool3.True: return one;
+ case Bool3.False: return Zero;
+ case Bool3.True: return One;
default: return CreateUnknownBool();
}
}
public static Int32Value Ceq(Int32Value a, Int32Value b) {
- return create(CompareEq(a, b));
+ return Create(CompareEq(a, b));
}
public static Int32Value Cgt(Int32Value a, Int32Value b) {
- return create(CompareGt(a, b));
+ return Create(CompareGt(a, b));
}
public static Int32Value Cgt_Un(Int32Value a, Int32Value b) {
- return create(CompareGt_Un(a, b));
+ return Create(CompareGt_Un(a, b));
}
public static Int32Value Clt(Int32Value a, Int32Value b) {
- return create(CompareLt(a, b));
+ return Create(CompareLt(a, b));
}
public static Int32Value Clt_Un(Int32Value a, Int32Value b) {
- return create(CompareLt_Un(a, b));
+ return Create(CompareLt_Un(a, b));
}
public static Bool3 CompareEq(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
- return a.value == b.value ? Bool3.True : Bool3.False;
+ return a.Value == b.Value ? Bool3.True : Bool3.False;
if (ReferenceEquals(a, b))
return Bool3.True;
- if ((a.value & a.validMask & b.validMask) != (b.value & a.validMask & b.validMask))
+ if (((uint)a.Value & a.ValidMask & b.ValidMask) != ((uint)b.Value & a.ValidMask & b.ValidMask))
return Bool3.False;
return Bool3.Unknown;
}
public static Bool3 CompareNeq(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
- return a.value != b.value ? Bool3.True : Bool3.False;
+ return a.Value != b.Value ? Bool3.True : Bool3.False;
if (ReferenceEquals(a, b))
return Bool3.False;
- if ((a.value & a.validMask & b.validMask) != (b.value & a.validMask & b.validMask))
+ if (((uint)a.Value & a.ValidMask & b.ValidMask) != ((uint)b.Value & a.ValidMask & b.ValidMask))
return Bool3.True;
return Bool3.Unknown;
}
public static Bool3 CompareGt(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
- return a.value > b.value ? Bool3.True : Bool3.False;
+ return a.Value > b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(int.MinValue))
return Bool3.False; // min > x => false
if (b.HasValue(int.MaxValue))
@@ -430,7 +616,7 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareGt_Un(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
- return (uint)a.value > (uint)b.value ? Bool3.True : Bool3.False;
+ return (uint)a.Value > (uint)b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(uint.MinValue))
return Bool3.False; // min > x => false
if (b.HasValue(uint.MaxValue))
@@ -440,7 +626,7 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareGe(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
- return a.value >= b.value ? Bool3.True : Bool3.False;
+ return a.Value >= b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(int.MaxValue))
return Bool3.True; // max >= x => true
if (b.HasValue(int.MinValue))
@@ -450,7 +636,7 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareGe_Un(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
- return (uint)a.value >= (uint)b.value ? Bool3.True : Bool3.False;
+ return (uint)a.Value >= (uint)b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(uint.MaxValue))
return Bool3.True; // max >= x => true
if (b.HasValue(uint.MinValue))
@@ -460,7 +646,7 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareLe(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
- return a.value <= b.value ? Bool3.True : Bool3.False;
+ return a.Value <= b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(int.MinValue))
return Bool3.True; // min <= x => true
if (b.HasValue(int.MaxValue))
@@ -470,7 +656,7 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareLe_Un(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
- return (uint)a.value <= (uint)b.value ? Bool3.True : Bool3.False;
+ return (uint)a.Value <= (uint)b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(uint.MinValue))
return Bool3.True; // min <= x => true
if (b.HasValue(uint.MaxValue))
@@ -480,7 +666,7 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareLt(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
- return a.value < b.value ? Bool3.True : Bool3.False;
+ return a.Value < b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(int.MaxValue))
return Bool3.False; // max < x => false
if (b.HasValue(int.MinValue))
@@ -490,7 +676,7 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareLt_Un(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
- return (uint)a.value < (uint)b.value ? Bool3.True : Bool3.False;
+ return (uint)a.Value < (uint)b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(uint.MaxValue))
return Bool3.False; // max < x => false
if (b.HasValue(uint.MinValue))
@@ -500,24 +686,24 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareTrue(Int32Value a) {
if (a.AllBitsValid())
- return a.value != 0 ? Bool3.True : Bool3.False;
- if ((a.value & a.validMask) != 0)
+ return a.Value != 0 ? Bool3.True : Bool3.False;
+ if (((uint)a.Value & a.ValidMask) != 0)
return Bool3.True;
return Bool3.Unknown;
}
public static Bool3 CompareFalse(Int32Value a) {
if (a.AllBitsValid())
- return a.value == 0 ? Bool3.True : Bool3.False;
- if ((a.value & a.validMask) != 0)
+ return a.Value == 0 ? Bool3.True : Bool3.False;
+ if (((uint)a.Value & a.ValidMask) != 0)
return Bool3.False;
return Bool3.Unknown;
}
public override string ToString() {
if (AllBitsValid())
- return value.ToString();
- return string.Format("0x{0:X8}({1:X8})", value, validMask);
+ return Value.ToString();
+ return string.Format("0x{0:X8}({1:X8})", Value, ValidMask);
}
}
}
diff --git a/blocks/cflow/Int64Value.cs b/de4dot.blocks/cflow/Int64Value.cs
similarity index 51%
rename from blocks/cflow/Int64Value.cs
rename to de4dot.blocks/cflow/Int64Value.cs
index 9ec2ff41..48a236e3 100644
--- a/blocks/cflow/Int64Value.cs
+++ b/de4dot.blocks/cflow/Int64Value.cs
@@ -21,27 +21,27 @@ using System;
namespace de4dot.blocks.cflow {
public class Int64Value : Value {
- public static readonly Int64Value zero = new Int64Value(0);
- public static readonly Int64Value one = new Int64Value(1);
+ public static readonly Int64Value Zero = new Int64Value(0);
+ public static readonly Int64Value One = new Int64Value(1);
- const ulong NO_UNKNOWN_BITS = ulong.MaxValue;
- public readonly long value;
- public readonly ulong validMask;
+ internal const ulong NO_UNKNOWN_BITS = ulong.MaxValue;
+ public readonly long Value;
+ public readonly ulong ValidMask;
public Int64Value(long value)
: base(ValueType.Int64) {
- this.value = value;
- this.validMask = NO_UNKNOWN_BITS;
+ this.Value = value;
+ this.ValidMask = NO_UNKNOWN_BITS;
}
public Int64Value(long value, ulong validMask)
: base(ValueType.Int64) {
- this.value = value;
- this.validMask = validMask;
+ this.Value = value;
+ this.ValidMask = validMask;
}
bool HasUnknownBits() {
- return validMask != NO_UNKNOWN_BITS;
+ return ValidMask != NO_UNKNOWN_BITS;
}
public bool AllBitsValid() {
@@ -49,13 +49,17 @@ namespace de4dot.blocks.cflow {
}
bool IsBitValid(int n) {
- return IsBitValid(validMask, n);
+ return IsBitValid(ValidMask, n);
}
static bool IsBitValid(ulong validMask, int n) {
return (validMask & (1UL << n)) != 0;
}
+ bool AreBitsValid(ulong bitsToTest) {
+ return (ValidMask & bitsToTest) == bitsToTest;
+ }
+
public static Int64Value CreateUnknown() {
return new Int64Value(0, 0UL);
}
@@ -65,11 +69,11 @@ namespace de4dot.blocks.cflow {
}
public bool IsNonZero() {
- return ((ulong)value & validMask) != 0;
+ return ((ulong)Value & ValidMask) != 0;
}
public bool HasValue(long value) {
- return AllBitsValid() && this.value == value;
+ return AllBitsValid() && this.Value == value;
}
public bool HasValue(ulong value) {
@@ -77,8 +81,8 @@ namespace de4dot.blocks.cflow {
}
public static Int64Value Conv_U8(Int32Value a) {
- long value = (long)(ulong)(uint)a.value;
- ulong validMask = a.validMask | (NO_UNKNOWN_BITS << 32);
+ long value = (long)(ulong)(uint)a.Value;
+ ulong validMask = a.ValidMask | (NO_UNKNOWN_BITS << 32);
return new Int64Value(value, validMask);
}
@@ -87,12 +91,14 @@ namespace de4dot.blocks.cflow {
}
public static Int64Value Conv_U8(Real8Value a) {
- return new Int64Value((long)(ulong)a.value);
+ if (!a.IsValid)
+ return CreateUnknown();
+ return new Int64Value((long)(ulong)a.Value);
}
public static Int64Value Conv_I8(Int32Value a) {
- long value = a.value;
- ulong validMask = a.validMask;
+ long value = a.Value;
+ ulong validMask = a.ValidMask;
if (IsBitValid(validMask, 31))
validMask |= NO_UNKNOWN_BITS << 32;
else
@@ -105,30 +111,140 @@ namespace de4dot.blocks.cflow {
}
public static Int64Value Conv_I8(Real8Value a) {
- return new Int64Value((long)a.value);
+ if (!a.IsValid)
+ return CreateUnknown();
+ return new Int64Value((long)a.Value);
+ }
+
+ bool CheckSign(ulong mask) {
+ return ((ulong)Value & mask) == 0 || ((ulong)Value & mask) == mask;
+ }
+
+ public static Int32Value Conv_Ovf_I1(Int64Value a) {
+ if (!a.AreBitsValid(NO_UNKNOWN_BITS << 7) ||
+ !a.CheckSign(NO_UNKNOWN_BITS << 7))
+ return Int32Value.CreateUnknown();
+ return Int32Value.Conv_I1(a);
+ }
+
+ public static Int32Value Conv_Ovf_I1_Un(Int64Value a) {
+ if (!a.AreBitsValid(NO_UNKNOWN_BITS << 7) ||
+ (ulong)a.Value > (ulong)sbyte.MaxValue)
+ return Int32Value.CreateUnknown();
+ return Int32Value.Conv_I1(a);
+ }
+
+ public static Int32Value Conv_Ovf_I2(Int64Value a) {
+ if (!a.AreBitsValid(NO_UNKNOWN_BITS << 15) ||
+ !a.CheckSign(NO_UNKNOWN_BITS << 15))
+ return Int32Value.CreateUnknown();
+ return Int32Value.Conv_I2(a);
+ }
+
+ public static Int32Value Conv_Ovf_I2_Un(Int64Value a) {
+ if (!a.AreBitsValid(NO_UNKNOWN_BITS << 15) ||
+ (ulong)a.Value > (ulong)short.MaxValue)
+ return Int32Value.CreateUnknown();
+ return Int32Value.Conv_I2(a);
+ }
+
+ public static Int32Value Conv_Ovf_I4(Int64Value a) {
+ if (!a.AreBitsValid(NO_UNKNOWN_BITS << 31) ||
+ !a.CheckSign(NO_UNKNOWN_BITS << 31))
+ return Int32Value.CreateUnknown();
+ return Int32Value.Conv_I4(a);
+ }
+
+ public static Int32Value Conv_Ovf_I4_Un(Int64Value a) {
+ if (!a.AreBitsValid(NO_UNKNOWN_BITS << 31) ||
+ (ulong)a.Value > (ulong)int.MaxValue)
+ return Int32Value.CreateUnknown();
+ return Int32Value.Conv_I4(a);
+ }
+
+ public static Int64Value Conv_Ovf_I8(Int64Value a) {
+ return a;
+ }
+
+ public static Int64Value Conv_Ovf_I8_Un(Int64Value a) {
+ if (!IsBitValid(a.ValidMask, 63) || a.Value < 0)
+ return CreateUnknown();
+ return a;
+ }
+
+ public static Int32Value Conv_Ovf_U1(Int64Value a) {
+ if (!a.AreBitsValid(NO_UNKNOWN_BITS << 7) ||
+ a.Value < 0 || a.Value > byte.MaxValue)
+ return Int32Value.CreateUnknownUInt8();
+ return Int32Value.Conv_U1(a);
+ }
+
+ public static Int32Value Conv_Ovf_U1_Un(Int64Value a) {
+ if (!a.AreBitsValid(NO_UNKNOWN_BITS << 8) ||
+ (ulong)a.Value > byte.MaxValue)
+ return Int32Value.CreateUnknownUInt8();
+ return Int32Value.Conv_U1(a);
+ }
+
+ public static Int32Value Conv_Ovf_U2(Int64Value a) {
+ if (!a.AreBitsValid(NO_UNKNOWN_BITS << 15) ||
+ a.Value < 0 || a.Value > ushort.MaxValue)
+ return Int32Value.CreateUnknownUInt16();
+ return Int32Value.Conv_U2(a);
+ }
+
+ public static Int32Value Conv_Ovf_U2_Un(Int64Value a) {
+ if (!a.AreBitsValid(NO_UNKNOWN_BITS << 16) ||
+ (ulong)a.Value > ushort.MaxValue)
+ return Int32Value.CreateUnknownUInt16();
+ return Int32Value.Conv_U2(a);
+ }
+
+ public static Int32Value Conv_Ovf_U4(Int64Value a) {
+ if (!a.AreBitsValid(NO_UNKNOWN_BITS << 31) ||
+ a.Value < 0 || a.Value > uint.MaxValue)
+ return Int32Value.CreateUnknown();
+ return Int32Value.Conv_U4(a);
+ }
+
+ public static Int32Value Conv_Ovf_U4_Un(Int64Value a) {
+ if (!a.AreBitsValid(NO_UNKNOWN_BITS << 32) ||
+ (ulong)a.Value > uint.MaxValue)
+ return Int32Value.CreateUnknown();
+ return Int32Value.Conv_U4(a);
+ }
+
+ public static Int64Value Conv_Ovf_U8(Int64Value a) {
+ if (!IsBitValid(a.ValidMask, 63) || a.Value < 0)
+ return CreateUnknown();
+ return a;
+ }
+
+ public static Int64Value Conv_Ovf_U8_Un(Int64Value a) {
+ return a;
}
public static Int64Value Add(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
- return new Int64Value(a.value + b.value);
+ return new Int64Value(a.Value + b.Value);
if (ReferenceEquals(a, b))
- return new Int64Value(a.value << 1, (a.validMask << 1) | 1);
+ return new Int64Value(a.Value << 1, (a.ValidMask << 1) | 1);
return CreateUnknown();
}
public static Int64Value Sub(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
- return new Int64Value(a.value - b.value);
+ return new Int64Value(a.Value - b.Value);
if (ReferenceEquals(a, b))
- return zero;
+ return Zero;
return CreateUnknown();
}
public static Int64Value Mul(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
- return new Int64Value(a.value * b.value);
+ return new Int64Value(a.Value * b.Value);
if (a.IsZero() || b.IsZero())
- return zero;
+ return Zero;
if (a.HasValue(1))
return b;
if (b.HasValue(1))
@@ -139,14 +255,14 @@ namespace de4dot.blocks.cflow {
public static Int64Value Div(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid()) {
try {
- return new Int64Value(a.value / b.value);
+ return new Int64Value(a.Value / b.Value);
}
catch (ArithmeticException) {
return CreateUnknown();
}
}
if (ReferenceEquals(a, b) && a.IsNonZero())
- return one;
+ return One;
if (b.HasValue(1))
return a;
return CreateUnknown();
@@ -155,14 +271,14 @@ namespace de4dot.blocks.cflow {
public static Int64Value Div_Un(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid()) {
try {
- return new Int64Value((long)((ulong)a.value / (ulong)b.value));
+ return new Int64Value((long)((ulong)a.Value / (ulong)b.Value));
}
catch (ArithmeticException) {
return CreateUnknown();
}
}
if (ReferenceEquals(a, b) && a.IsNonZero())
- return one;
+ return One;
if (b.HasValue(1))
return a;
return CreateUnknown();
@@ -171,103 +287,172 @@ namespace de4dot.blocks.cflow {
public static Int64Value Rem(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid()) {
try {
- return new Int64Value(a.value % b.value);
+ return new Int64Value(a.Value % b.Value);
}
catch (ArithmeticException) {
return CreateUnknown();
}
}
if ((ReferenceEquals(a, b) && a.IsNonZero()) || b.HasValue(1))
- return zero;
+ return Zero;
return CreateUnknown();
}
public static Int64Value Rem_Un(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid()) {
try {
- return new Int64Value((long)((ulong)a.value % (ulong)b.value));
+ return new Int64Value((long)((ulong)a.Value % (ulong)b.Value));
}
catch (ArithmeticException) {
return CreateUnknown();
}
}
if ((ReferenceEquals(a, b) && a.IsNonZero()) || b.HasValue(1))
- return zero;
+ return Zero;
return CreateUnknown();
}
public static Int64Value Neg(Int64Value a) {
if (a.AllBitsValid())
- return new Int64Value(-a.value);
+ return new Int64Value(-a.Value);
+ return CreateUnknown();
+ }
+
+ public static Int64Value Add_Ovf(Int64Value a, Int64Value b) {
+ if (a.AllBitsValid() && b.AllBitsValid()) {
+ try {
+ return new Int64Value(checked(a.Value + b.Value));
+ }
+ catch (OverflowException) {
+ }
+ }
+ return CreateUnknown();
+ }
+
+ public static Int64Value Add_Ovf_Un(Int64Value a, Int64Value b) {
+ if (a.AllBitsValid() && b.AllBitsValid()) {
+ ulong aa = (ulong)a.Value, bb = (ulong)b.Value;
+ try {
+ return new Int64Value((long)checked(aa + bb));
+ }
+ catch (OverflowException) {
+ }
+ }
+ return CreateUnknown();
+ }
+
+ public static Int64Value Sub_Ovf(Int64Value a, Int64Value b) {
+ if (a.AllBitsValid() && b.AllBitsValid()) {
+ try {
+ return new Int64Value(checked(a.Value - b.Value));
+ }
+ catch (OverflowException) {
+ }
+ }
+ return CreateUnknown();
+ }
+
+ public static Int64Value Sub_Ovf_Un(Int64Value a, Int64Value b) {
+ if (a.AllBitsValid() && b.AllBitsValid()) {
+ ulong aa = (ulong)a.Value, bb = (ulong)b.Value;
+ try {
+ return new Int64Value((long)checked(aa - bb));
+ }
+ catch (OverflowException) {
+ }
+ }
+ return CreateUnknown();
+ }
+
+ public static Int64Value Mul_Ovf(Int64Value a, Int64Value b) {
+ if (a.AllBitsValid() && b.AllBitsValid()) {
+ try {
+ return new Int64Value(checked(a.Value * b.Value));
+ }
+ catch (OverflowException) {
+ }
+ }
+ return CreateUnknown();
+ }
+
+ public static Int64Value Mul_Ovf_Un(Int64Value a, Int64Value b) {
+ if (a.AllBitsValid() && b.AllBitsValid()) {
+ ulong aa = (ulong)a.Value, bb = (ulong)b.Value;
+ try {
+ return new Int64Value((long)checked(aa * bb));
+ }
+ catch (OverflowException) {
+ }
+ }
return CreateUnknown();
}
public static Int64Value And(Int64Value a, Int64Value b) {
- long av = a.value, bv = b.value;
- ulong am = a.validMask, bm = b.validMask;
+ long av = a.Value, bv = b.Value;
+ ulong am = a.ValidMask, bm = b.ValidMask;
return new Int64Value(av & bv, (am & bm) | (((ulong)av & am) ^ am) | (((ulong)bv & bm) ^ bm));
}
public static Int64Value Or(Int64Value a, Int64Value b) {
- long av = a.value, bv = b.value;
- ulong am = a.validMask, bm = b.validMask;
+ long av = a.Value, bv = b.Value;
+ ulong am = a.ValidMask, bm = b.ValidMask;
return new Int64Value(av | bv, (am & bm) | ((ulong)av & am) | ((ulong)bv & bm));
}
public static Int64Value Xor(Int64Value a, Int64Value b) {
if (ReferenceEquals(a, b))
- return zero;
- long av = a.value, bv = b.value;
- ulong am = a.validMask, bm = b.validMask;
+ return Zero;
+ long av = a.Value, bv = b.Value;
+ ulong am = a.ValidMask, bm = b.ValidMask;
return new Int64Value(av ^ bv, am & bm);
}
public static Int64Value Not(Int64Value a) {
- return new Int64Value(~a.value, a.validMask);
+ return new Int64Value(~a.Value, a.ValidMask);
}
public static Int64Value Shl(Int64Value a, Int32Value b) {
if (b.HasUnknownBits())
return CreateUnknown();
- if (b.value == 0)
+ if (b.Value == 0)
return a;
- if (b.value < 0 || b.value >= sizeof(long) * 8)
+ if (b.Value < 0 || b.Value >= sizeof(long) * 8)
return CreateUnknown();
- int shift = b.value;
- ulong validMask = (a.validMask << shift) | (ulong.MaxValue >> (sizeof(long) * 8 - shift));
- return new Int64Value(a.value << shift, validMask);
+ int shift = b.Value;
+ ulong validMask = (a.ValidMask << shift) | (ulong.MaxValue >> (sizeof(long) * 8 - shift));
+ return new Int64Value(a.Value << shift, validMask);
}
public static Int64Value Shr(Int64Value a, Int32Value b) {
if (b.HasUnknownBits())
return CreateUnknown();
- if (b.value == 0)
+ if (b.Value == 0)
return a;
- if (b.value < 0 || b.value >= sizeof(long) * 8)
+ if (b.Value < 0 || b.Value >= sizeof(long) * 8)
return CreateUnknown();
- int shift = b.value;
- ulong validMask = a.validMask >> shift;
+ int shift = b.Value;
+ ulong validMask = a.ValidMask >> shift;
if (a.IsBitValid(sizeof(long) * 8 - 1))
validMask |= (ulong.MaxValue << (sizeof(long) * 8 - shift));
- return new Int64Value(a.value >> shift, validMask);
+ return new Int64Value(a.Value >> shift, validMask);
}
public static Int64Value Shr_Un(Int64Value a, Int32Value b) {
if (b.HasUnknownBits())
return CreateUnknown();
- if (b.value == 0)
+ if (b.Value == 0)
return a;
- if (b.value < 0 || b.value >= sizeof(long) * 8)
+ if (b.Value < 0 || b.Value >= sizeof(long) * 8)
return CreateUnknown();
- int shift = b.value;
- ulong validMask = (a.validMask >> shift) | (ulong.MaxValue << (sizeof(long) * 8 - shift));
- return new Int64Value((long)((ulong)a.value >> shift), validMask);
+ int shift = b.Value;
+ ulong validMask = (a.ValidMask >> shift) | (ulong.MaxValue << (sizeof(long) * 8 - shift));
+ 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;
+ case Bool3.False: return Int32Value.Zero;
+ case Bool3.True: return Int32Value.One;
default: return Int32Value.CreateUnknownBool();
}
}
@@ -294,27 +479,27 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareEq(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
- return a.value == b.value ? Bool3.True : Bool3.False;
+ return a.Value == b.Value ? Bool3.True : Bool3.False;
if (ReferenceEquals(a, b))
return Bool3.True;
- if (((ulong)a.value & a.validMask & b.validMask) != ((ulong)b.value & a.validMask & b.validMask))
+ if (((ulong)a.Value & a.ValidMask & b.ValidMask) != ((ulong)b.Value & a.ValidMask & b.ValidMask))
return Bool3.False;
return Bool3.Unknown;
}
public static Bool3 CompareNeq(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
- return a.value != b.value ? Bool3.True : Bool3.False;
+ return a.Value != b.Value ? Bool3.True : Bool3.False;
if (ReferenceEquals(a, b))
return Bool3.False;
- if (((ulong)a.value & a.validMask & b.validMask) != ((ulong)b.value & a.validMask & b.validMask))
+ if (((ulong)a.Value & a.ValidMask & b.ValidMask) != ((ulong)b.Value & a.ValidMask & b.ValidMask))
return Bool3.True;
return Bool3.Unknown;
}
public static Bool3 CompareGt(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
- return a.value > b.value ? Bool3.True : Bool3.False;
+ return a.Value > b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(long.MinValue))
return Bool3.False; // min > x => false
if (b.HasValue(long.MaxValue))
@@ -324,7 +509,7 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareGt_Un(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
- return (ulong)a.value > (ulong)b.value ? Bool3.True : Bool3.False;
+ return (ulong)a.Value > (ulong)b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(ulong.MinValue))
return Bool3.False; // min > x => false
if (b.HasValue(ulong.MaxValue))
@@ -334,7 +519,7 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareGe(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
- return a.value >= b.value ? Bool3.True : Bool3.False;
+ return a.Value >= b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(long.MaxValue))
return Bool3.True; // max >= x => true
if (b.HasValue(long.MinValue))
@@ -344,7 +529,7 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareGe_Un(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
- return (ulong)a.value >= (ulong)b.value ? Bool3.True : Bool3.False;
+ return (ulong)a.Value >= (ulong)b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(ulong.MaxValue))
return Bool3.True; // max >= x => true
if (b.HasValue(ulong.MinValue))
@@ -354,7 +539,7 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareLe(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
- return a.value <= b.value ? Bool3.True : Bool3.False;
+ return a.Value <= b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(long.MinValue))
return Bool3.True; // min <= x => true
if (b.HasValue(long.MaxValue))
@@ -364,7 +549,7 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareLe_Un(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
- return (ulong)a.value <= (ulong)b.value ? Bool3.True : Bool3.False;
+ return (ulong)a.Value <= (ulong)b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(ulong.MinValue))
return Bool3.True; // min <= x => true
if (b.HasValue(ulong.MaxValue))
@@ -374,7 +559,7 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareLt(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
- return a.value < b.value ? Bool3.True : Bool3.False;
+ return a.Value < b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(long.MaxValue))
return Bool3.False; // max < x => false
if (b.HasValue(long.MinValue))
@@ -384,7 +569,7 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareLt_Un(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
- return (ulong)a.value < (ulong)b.value ? Bool3.True : Bool3.False;
+ return (ulong)a.Value < (ulong)b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(ulong.MaxValue))
return Bool3.False; // max < x => false
if (b.HasValue(ulong.MinValue))
@@ -394,24 +579,24 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareTrue(Int64Value a) {
if (a.AllBitsValid())
- return a.value != 0 ? Bool3.True : Bool3.False;
- if (((ulong)a.value & a.validMask) != 0)
+ return a.Value != 0 ? Bool3.True : Bool3.False;
+ if (((ulong)a.Value & a.ValidMask) != 0)
return Bool3.True;
return Bool3.Unknown;
}
public static Bool3 CompareFalse(Int64Value a) {
if (a.AllBitsValid())
- return a.value == 0 ? Bool3.True : Bool3.False;
- if (((ulong)a.value & a.validMask) != 0)
+ return a.Value == 0 ? Bool3.True : Bool3.False;
+ if (((ulong)a.Value & a.ValidMask) != 0)
return Bool3.False;
return Bool3.Unknown;
}
public override string ToString() {
if (AllBitsValid())
- return value.ToString();
- return string.Format("0x{0:X8}L({1:X8})", value, validMask);
+ return Value.ToString();
+ return string.Format("0x{0:X8}L({1:X8})", Value, ValidMask);
}
}
}
diff --git a/blocks/cflow/MethodCallInliner.cs b/de4dot.blocks/cflow/MethodCallInliner.cs
similarity index 83%
rename from blocks/cflow/MethodCallInliner.cs
rename to de4dot.blocks/cflow/MethodCallInliner.cs
index a44fc610..4265e706 100644
--- a/blocks/cflow/MethodCallInliner.cs
+++ b/de4dot.blocks/cflow/MethodCallInliner.cs
@@ -55,6 +55,10 @@ namespace de4dot.blocks.cflow {
return inlineInstanceMethods;
}
+ protected virtual Instruction GetFirstInstruction(IList instrs, ref int index) {
+ return DotNetUtils.GetInstruction(instrs, ref index);
+ }
+
bool InlineMethod(Instruction callInstr, int instrIndex) {
var methodToInline = callInstr.Operand as MethodDef;
if (methodToInline == null)
@@ -67,10 +71,11 @@ namespace de4dot.blocks.cflow {
return false;
int index = 0;
- var instr = DotNetUtils.GetInstruction(body.Instructions, ref index);
+ var instr = GetFirstInstruction(body.Instructions, ref index);
if (instr == null)
return false;
+ bool inlinedMethod;
switch (instr.OpCode.Code) {
case Code.Ldarg:
case Code.Ldarg_S:
@@ -83,7 +88,8 @@ namespace de4dot.blocks.cflow {
case Code.Call:
case Code.Callvirt:
case Code.Newobj:
- return InlineOtherMethod(instrIndex, methodToInline, instr, index);
+ inlinedMethod = InlineOtherMethod(instrIndex, methodToInline, instr, index);
+ break;
case Code.Ldc_I4:
case Code.Ldc_I4_0:
@@ -106,11 +112,18 @@ namespace de4dot.blocks.cflow {
case Code.Ldtoken:
case Code.Ldsfld:
case Code.Ldsflda:
- return InlineLoadMethod(instrIndex, methodToInline, instr, index);
+ inlinedMethod = InlineLoadMethod(instrIndex, methodToInline, instr, index);
+ break;
default:
- return false;
+ inlinedMethod = false;
+ break;
}
+ OnInlinedMethod(methodToInline, inlinedMethod);
+ return inlinedMethod;
+ }
+
+ protected virtual void OnInlinedMethod(MethodDef methodToInline, bool inlinedMethod) {
}
protected override bool IsCompatibleType(int paramIndex, IType origType, IType newType) {
diff --git a/blocks/cflow/MethodCallInlinerBase.cs b/de4dot.blocks/cflow/MethodCallInlinerBase.cs
similarity index 94%
rename from blocks/cflow/MethodCallInlinerBase.cs
rename to de4dot.blocks/cflow/MethodCallInlinerBase.cs
index 873c4d62..d8ed9247 100644
--- a/blocks/cflow/MethodCallInlinerBase.cs
+++ b/de4dot.blocks/cflow/MethodCallInlinerBase.cs
@@ -142,7 +142,9 @@ namespace de4dot.blocks.cflow {
if (instr == null || loadIndex != methodArgsCount - popLastArgs)
return null;
- if (instr.OpCode.Code == Code.Call || instr.OpCode.Code == Code.Callvirt) {
+ switch (instr.OpCode.Code) {
+ case Code.Call:
+ case Code.Callvirt:
if (foundLdarga)
return null;
var callInstr = instr;
@@ -160,8 +162,8 @@ namespace de4dot.blocks.cflow {
return null;
return new InstructionPatcher(patchIndex, instrIndex, callInstr);
- }
- else if (instr.OpCode.Code == Code.Newobj) {
+
+ case Code.Newobj:
if (foundLdarga)
return null;
var newobjInstr = instr;
@@ -185,20 +187,30 @@ namespace de4dot.blocks.cflow {
return null;
return new InstructionPatcher(patchIndex, instrIndex, newobjInstr);
- }
- else if (instr.OpCode.Code == Code.Ldfld || instr.OpCode.Code == Code.Ldflda ||
- instr.OpCode.Code == Code.Ldftn || instr.OpCode.Code == Code.Ldvirtftn) {
+
+ case Code.Ldfld:
+ case Code.Ldflda:
+ case Code.Ldftn:
+ case Code.Ldvirtftn:
+ case Code.Ldlen:
+ case Code.Initobj:
+ case Code.Isinst:
+ case Code.Castclass:
+ case Code.Newarr:
+ case Code.Ldtoken:
+ case Code.Unbox_Any:
var ldInstr = instr;
if (methodArgsCount != 1)
return null;
- if (!HasAccessTo(instr.Operand))
+ if (instr.OpCode.OperandType != OperandType.InlineNone && !HasAccessTo(instr.Operand))
return null;
return new InstructionPatcher(patchIndex, instrIndex, ldInstr);
- }
- return null;
+ default:
+ return null;
+ }
}
bool HasAccessTo(object operand) {
diff --git a/de4dot.blocks/cflow/Real8Value.cs b/de4dot.blocks/cflow/Real8Value.cs
new file mode 100644
index 00000000..5087046d
--- /dev/null
+++ b/de4dot.blocks/cflow/Real8Value.cs
@@ -0,0 +1,177 @@
+/*
+ Copyright (C) 2011-2013 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 .
+*/
+
+namespace de4dot.blocks.cflow {
+ public class Real8Value : Value {
+ public readonly double Value;
+ public readonly bool IsValid;
+
+ public Real8Value(double value)
+ : base(ValueType.Real8) {
+ this.Value = value;
+ this.IsValid = true;
+ }
+
+ public Real8Value(double value, bool isValid)
+ : base(ValueType.Real8) {
+ this.Value = value;
+ this.IsValid = isValid;
+ }
+
+ public static Real8Value CreateUnknown() {
+ return new Real8Value(0, false);
+ }
+
+ public Real8Value ToSingle() {
+ if (!IsValid)
+ return CreateUnknown();
+ return new Real8Value((float)Value);
+ }
+
+ public static Real8Value Add(Real8Value a, Real8Value b) {
+ if (!a.IsValid || !b.IsValid)
+ return CreateUnknown();
+ return new Real8Value(a.Value + b.Value);
+ }
+
+ public static Real8Value Sub(Real8Value a, Real8Value b) {
+ if (!a.IsValid || !b.IsValid)
+ return CreateUnknown();
+ return new Real8Value(a.Value - b.Value);
+ }
+
+ public static Real8Value Mul(Real8Value a, Real8Value b) {
+ if (!a.IsValid || !b.IsValid)
+ return CreateUnknown();
+ return new Real8Value(a.Value * b.Value);
+ }
+
+ public static Real8Value Div(Real8Value a, Real8Value b) {
+ if (!a.IsValid || !b.IsValid)
+ return CreateUnknown();
+ return new Real8Value(a.Value / b.Value);
+ }
+
+ public static Real8Value Rem(Real8Value a, Real8Value b) {
+ if (!a.IsValid || !b.IsValid)
+ return CreateUnknown();
+ return new Real8Value(a.Value % b.Value);
+ }
+
+ public static Real8Value Neg(Real8Value a) {
+ if (!a.IsValid)
+ return CreateUnknown();
+ return new Real8Value(-a.Value);
+ }
+
+ public static Real8Value Add_Ovf(Real8Value a, Real8Value b) {
+ return CreateUnknown();
+ }
+
+ public static Real8Value Add_Ovf_Un(Real8Value a, Real8Value b) {
+ return CreateUnknown();
+ }
+
+ public static Real8Value Sub_Ovf(Real8Value a, Real8Value b) {
+ return CreateUnknown();
+ }
+
+ public static Real8Value Sub_Ovf_Un(Real8Value a, Real8Value b) {
+ return CreateUnknown();
+ }
+
+ public static Real8Value Mul_Ovf(Real8Value a, Real8Value b) {
+ return CreateUnknown();
+ }
+
+ public static Real8Value Mul_Ovf_Un(Real8Value a, Real8Value b) {
+ return CreateUnknown();
+ }
+
+ public static Int32Value Conv_Ovf_I1(Real8Value a) {
+ return Int32Value.CreateUnknown();
+ }
+
+ public static Int32Value Conv_Ovf_I1_Un(Real8Value a) {
+ return Int32Value.CreateUnknown();
+ }
+
+ public static Int32Value Conv_Ovf_I2(Real8Value a) {
+ return Int32Value.CreateUnknown();
+ }
+
+ public static Int32Value Conv_Ovf_I2_Un(Real8Value a) {
+ return Int32Value.CreateUnknown();
+ }
+
+ public static Int32Value Conv_Ovf_I4(Real8Value a) {
+ return Int32Value.CreateUnknown();
+ }
+
+ public static Int32Value Conv_Ovf_I4_Un(Real8Value a) {
+ return Int32Value.CreateUnknown();
+ }
+
+ public static Int64Value Conv_Ovf_I8(Real8Value a) {
+ return Int64Value.CreateUnknown();
+ }
+
+ public static Int64Value Conv_Ovf_I8_Un(Real8Value a) {
+ return Int64Value.CreateUnknown();
+ }
+
+ public static Int32Value Conv_Ovf_U1(Real8Value a) {
+ return Int32Value.CreateUnknownUInt8();
+ }
+
+ public static Int32Value Conv_Ovf_U1_Un(Real8Value a) {
+ return Int32Value.CreateUnknownUInt8();
+ }
+
+ public static Int32Value Conv_Ovf_U2(Real8Value a) {
+ return Int32Value.CreateUnknownUInt16();
+ }
+
+ public static Int32Value Conv_Ovf_U2_Un(Real8Value a) {
+ return Int32Value.CreateUnknownUInt16();
+ }
+
+ public static Int32Value Conv_Ovf_U4(Real8Value a) {
+ return Int32Value.CreateUnknown();
+ }
+
+ public static Int32Value Conv_Ovf_U4_Un(Real8Value a) {
+ return Int32Value.CreateUnknown();
+ }
+
+ public static Int64Value Conv_Ovf_U8(Real8Value a) {
+ return Int64Value.CreateUnknown();
+ }
+
+ public static Int64Value Conv_Ovf_U8_Un(Real8Value a) {
+ return Int64Value.CreateUnknown();
+ }
+
+ public override string ToString() {
+ if (!IsValid)
+ return "";
+ return Value.ToString();
+ }
+ }
+}
diff --git a/blocks/cflow/StLdlocFixer.cs b/de4dot.blocks/cflow/StLdlocFixer.cs
similarity index 100%
rename from blocks/cflow/StLdlocFixer.cs
rename to de4dot.blocks/cflow/StLdlocFixer.cs
diff --git a/blocks/cflow/SwitchCflowDeobfuscator.cs b/de4dot.blocks/cflow/SwitchCflowDeobfuscator.cs
similarity index 97%
rename from blocks/cflow/SwitchCflowDeobfuscator.cs
rename to de4dot.blocks/cflow/SwitchCflowDeobfuscator.cs
index 329843f3..abec82b8 100644
--- a/blocks/cflow/SwitchCflowDeobfuscator.cs
+++ b/de4dot.blocks/cflow/SwitchCflowDeobfuscator.cs
@@ -158,7 +158,7 @@ namespace de4dot.blocks.cflow {
foreach (var source in new List(block.Sources)) {
if (!isBranchBlock(source))
continue;
- instructionEmulator.Initialize(blocks);
+ instructionEmulator.Initialize(blocks, allBlocks[0] == source);
instructionEmulator.Emulate(source.Instructions);
var target = GetSwitchTarget(switchTargets, switchFallThrough, instructionEmulator.Pop());
@@ -183,7 +183,7 @@ namespace de4dot.blocks.cflow {
bool modified = false;
foreach (var source in new List(block.Sources)) {
if (isBranchBlock(source)) {
- instructionEmulator.Initialize(blocks);
+ instructionEmulator.Initialize(blocks, allBlocks[0] == source);
instructionEmulator.Emulate(source.Instructions);
var target = GetSwitchTarget(switchTargets, switchFallThrough, instructionEmulator.GetLocal(switchVariable));
@@ -193,7 +193,7 @@ namespace de4dot.blocks.cflow {
modified = true;
}
else if (IsBccBlock(source)) {
- instructionEmulator.Initialize(blocks);
+ instructionEmulator.Initialize(blocks, allBlocks[0] == source);
instructionEmulator.Emulate(source.Instructions);
var target = GetSwitchTarget(switchTargets, switchFallThrough, instructionEmulator.GetLocal(switchVariable));
@@ -223,7 +223,7 @@ namespace de4dot.blocks.cflow {
foreach (var source in new List(block.Sources)) {
if (!isBranchBlock(source))
continue;
- instructionEmulator.Initialize(blocks);
+ instructionEmulator.Initialize(blocks, allBlocks[0] == source);
instructionEmulator.Emulate(source.Instructions);
var target = GetSwitchTarget(switchTargets, switchFallThrough, instructionEmulator.Pop());
@@ -407,7 +407,7 @@ namespace de4dot.blocks.cflow {
}
bool EmulateGetTarget(Block switchBlock, out Block target) {
- instructionEmulator.Initialize(blocks);
+ instructionEmulator.Initialize(blocks, allBlocks[0] == switchBlock);
try {
instructionEmulator.Emulate(switchBlock.Instructions, 0, switchBlock.Instructions.Count - 1);
}
@@ -421,7 +421,7 @@ namespace de4dot.blocks.cflow {
}
bool WillHaveKnownTarget(Block switchBlock, Block source) {
- instructionEmulator.Initialize(blocks);
+ instructionEmulator.Initialize(blocks, allBlocks[0] == source);
try {
instructionEmulator.Emulate(source.Instructions);
instructionEmulator.Emulate(switchBlock.Instructions, 0, switchBlock.Instructions.Count - 1);
diff --git a/blocks/cflow/Value.cs b/de4dot.blocks/cflow/Value.cs
similarity index 100%
rename from blocks/cflow/Value.cs
rename to de4dot.blocks/cflow/Value.cs
diff --git a/blocks/cflow/ValueStack.cs b/de4dot.blocks/cflow/ValueStack.cs
similarity index 100%
rename from blocks/cflow/ValueStack.cs
rename to de4dot.blocks/cflow/ValueStack.cs
diff --git a/blocks/blocks.csproj b/de4dot.blocks/de4dot.blocks.csproj
similarity index 97%
rename from blocks/blocks.csproj
rename to de4dot.blocks/de4dot.blocks.csproj
index a0bae6cc..677d22f4 100644
--- a/blocks/blocks.csproj
+++ b/de4dot.blocks/de4dot.blocks.csproj
@@ -9,7 +9,7 @@
Library
Properties
de4dot.blocks
- blocks
+ de4dot.blocks
v2.0
512
true
@@ -76,6 +76,7 @@
+
diff --git a/de4dot.code/AssemblyClient/AssemblyClient.cs b/de4dot.code/AssemblyClient/AssemblyClient.cs
index 68bca68e..b6a01103 100644
--- a/de4dot.code/AssemblyClient/AssemblyClient.cs
+++ b/de4dot.code/AssemblyClient/AssemblyClient.cs
@@ -35,8 +35,16 @@ namespace de4dot.code.AssemblyClient {
get { return service; }
}
- public AssemblyClient()
- : this(new NewProcessAssemblyServerLoader()) {
+ public IStringDecrypterService StringDecrypterService {
+ get { return (IStringDecrypterService)service; }
+ }
+
+ public IMethodDecrypterService MethodDecrypterService {
+ get { return (IMethodDecrypterService)service; }
+ }
+
+ public IGenericService GenericService {
+ get { return (IGenericService)service; }
}
public AssemblyClient(IAssemblyServerLoader loader) {
diff --git a/de4dot.code/AssemblyClient/AssemblyClientFactory.cs b/de4dot.code/AssemblyClient/AssemblyClientFactory.cs
index fdcd9a59..83a1967b 100644
--- a/de4dot.code/AssemblyClient/AssemblyClientFactory.cs
+++ b/de4dot.code/AssemblyClient/AssemblyClientFactory.cs
@@ -18,21 +18,22 @@
*/
using dnlib.DotNet;
+using AssemblyData;
namespace de4dot.code.AssemblyClient {
public interface IAssemblyClientFactory {
- IAssemblyClient Create();
+ IAssemblyClient Create(AssemblyServiceType serviceType);
}
public class SameAppDomainAssemblyClientFactory : IAssemblyClientFactory {
- public IAssemblyClient Create() {
- return new AssemblyClient(new SameAppDomainAssemblyServerLoader());
+ public IAssemblyClient Create(AssemblyServiceType serviceType) {
+ return new AssemblyClient(new SameAppDomainAssemblyServerLoader(serviceType));
}
}
public class NewAppDomainAssemblyClientFactory : IAssemblyClientFactory {
- public IAssemblyClient Create() {
- return new AssemblyClient(new NewAppDomainAssemblyServerLoader());
+ public IAssemblyClient Create(AssemblyServiceType serviceType) {
+ return new AssemblyClient(new NewAppDomainAssemblyServerLoader(serviceType));
}
}
@@ -47,12 +48,12 @@ namespace de4dot.code.AssemblyClient {
this.serverVersion = serverVersion;
}
- public IAssemblyClient Create(ModuleDef module) {
- return new AssemblyClient(new NewProcessAssemblyServerLoader(GetServerClrVersion(module)));
+ public IAssemblyClient Create(AssemblyServiceType serviceType, ModuleDef module) {
+ return new AssemblyClient(new NewProcessAssemblyServerLoader(serviceType, GetServerClrVersion(module)));
}
- public IAssemblyClient Create() {
- return new AssemblyClient(new NewProcessAssemblyServerLoader(serverVersion));
+ public IAssemblyClient Create(AssemblyServiceType serviceType) {
+ return new AssemblyClient(new NewProcessAssemblyServerLoader(serviceType, serverVersion));
}
internal static ServerClrVersion GetServerClrVersion(ModuleDef module) {
diff --git a/de4dot.code/AssemblyClient/IAssemblyClient.cs b/de4dot.code/AssemblyClient/IAssemblyClient.cs
index 0449796b..1b7a2547 100644
--- a/de4dot.code/AssemblyClient/IAssemblyClient.cs
+++ b/de4dot.code/AssemblyClient/IAssemblyClient.cs
@@ -23,6 +23,9 @@ using AssemblyData;
namespace de4dot.code.AssemblyClient {
public interface IAssemblyClient : IDisposable {
IAssemblyService Service { get; }
+ IStringDecrypterService StringDecrypterService { get; }
+ IMethodDecrypterService MethodDecrypterService { get; }
+ IGenericService GenericService { get; }
void Connect();
void WaitConnected();
}
diff --git a/de4dot.code/AssemblyClient/IpcAssemblyServerLoader.cs b/de4dot.code/AssemblyClient/IpcAssemblyServerLoader.cs
index 423f4eb7..f2af1232 100644
--- a/de4dot.code/AssemblyClient/IpcAssemblyServerLoader.cs
+++ b/de4dot.code/AssemblyClient/IpcAssemblyServerLoader.cs
@@ -35,13 +35,15 @@ namespace de4dot.code.AssemblyClient {
readonly string assemblyServerFilename;
protected string ipcName;
protected string ipcUri;
+ protected AssemblyServiceType serviceType;
string url;
- protected IpcAssemblyServerLoader()
- : this(ServerClrVersion.CLR_ANY_ANYCPU) {
+ protected IpcAssemblyServerLoader(AssemblyServiceType serviceType)
+ : this(serviceType, ServerClrVersion.CLR_ANY_ANYCPU) {
}
- protected IpcAssemblyServerLoader(ServerClrVersion serverVersion) {
+ protected IpcAssemblyServerLoader(AssemblyServiceType serviceType, ServerClrVersion serverVersion) {
+ this.serviceType = serviceType;
assemblyServerFilename = GetServerName(serverVersion);
ipcName = Utils.RandomName(15, 20);
ipcUri = Utils.RandomName(15, 20);
@@ -69,7 +71,7 @@ namespace de4dot.code.AssemblyClient {
public abstract void LoadServer(string filename);
public IAssemblyService CreateService() {
- return (IAssemblyService)Activator.GetObject(typeof(AssemblyService), url);
+ return (IAssemblyService)Activator.GetObject(AssemblyService.GetType(serviceType), url);
}
public abstract void Dispose();
diff --git a/de4dot.code/AssemblyClient/NewAppDomainAssemblyServerLoader.cs b/de4dot.code/AssemblyClient/NewAppDomainAssemblyServerLoader.cs
index 16b274ce..f7521663 100644
--- a/de4dot.code/AssemblyClient/NewAppDomainAssemblyServerLoader.cs
+++ b/de4dot.code/AssemblyClient/NewAppDomainAssemblyServerLoader.cs
@@ -19,6 +19,7 @@
using System;
using System.Threading;
+using AssemblyData;
namespace de4dot.code.AssemblyClient {
// Starts the server in a new app domain.
@@ -26,6 +27,10 @@ namespace de4dot.code.AssemblyClient {
AppDomain appDomain;
Thread thread;
+ public NewAppDomainAssemblyServerLoader(AssemblyServiceType serviceType)
+ : base(serviceType) {
+ }
+
public override void LoadServer(string filename) {
if (appDomain != null)
throw new ApplicationException("Server is already loaded");
@@ -33,7 +38,9 @@ namespace de4dot.code.AssemblyClient {
appDomain = AppDomain.CreateDomain(Utils.RandomName(15, 20));
thread = new Thread(new ThreadStart(() => {
try {
- appDomain.ExecuteAssembly(filename, null, new string[] { ipcName, ipcUri });
+ appDomain.ExecuteAssembly(filename, null, new string[] {
+ ((int)serviceType).ToString(), ipcName, ipcUri
+ });
}
catch (NullReferenceException) {
// Here if appDomain was set to null by Dispose() before this thread started
diff --git a/de4dot.code/AssemblyClient/NewProcessAssemblyServerLoader.cs b/de4dot.code/AssemblyClient/NewProcessAssemblyServerLoader.cs
index 379ed0ce..9aa00537 100644
--- a/de4dot.code/AssemblyClient/NewProcessAssemblyServerLoader.cs
+++ b/de4dot.code/AssemblyClient/NewProcessAssemblyServerLoader.cs
@@ -19,17 +19,19 @@
using System;
using System.Diagnostics;
+using AssemblyData;
namespace de4dot.code.AssemblyClient {
// Starts the server in a new process
class NewProcessAssemblyServerLoader : IpcAssemblyServerLoader {
Process process;
- public NewProcessAssemblyServerLoader() {
+ public NewProcessAssemblyServerLoader(AssemblyServiceType serviceType)
+ : base(serviceType) {
}
- public NewProcessAssemblyServerLoader(ServerClrVersion version)
- : base(version) {
+ public NewProcessAssemblyServerLoader(AssemblyServiceType serviceType, ServerClrVersion version)
+ : base(serviceType, version) {
}
public override void LoadServer(string filename) {
@@ -37,7 +39,8 @@ namespace de4dot.code.AssemblyClient {
throw new ApplicationException("Server is already loaded");
var psi = new ProcessStartInfo {
- Arguments = string.Format("{0} {1}", Utils.ShellEscape(ipcName), Utils.ShellEscape(ipcUri)),
+ Arguments = string.Format("{0} {1} {2}", (int)serviceType,
+ Utils.ShellEscape(ipcName), Utils.ShellEscape(ipcUri)),
CreateNoWindow = true,
ErrorDialog = false,
FileName = filename,
diff --git a/de4dot.code/AssemblyClient/SameAppDomainAssemblyServerLoader.cs b/de4dot.code/AssemblyClient/SameAppDomainAssemblyServerLoader.cs
index 978a205c..8cd8096b 100644
--- a/de4dot.code/AssemblyClient/SameAppDomainAssemblyServerLoader.cs
+++ b/de4dot.code/AssemblyClient/SameAppDomainAssemblyServerLoader.cs
@@ -24,11 +24,16 @@ namespace de4dot.code.AssemblyClient {
// Starts the server in the current app domain.
class SameAppDomainAssemblyServerLoader : IAssemblyServerLoader {
IAssemblyService service;
+ AssemblyServiceType serviceType;
+
+ public SameAppDomainAssemblyServerLoader(AssemblyServiceType serviceType) {
+ this.serviceType = serviceType;
+ }
public void LoadServer() {
if (service != null)
throw new ApplicationException("Server already loaded");
- service = new AssemblyService();
+ service = AssemblyService.Create(serviceType);
}
public IAssemblyService CreateService() {
diff --git a/de4dot.code/HandleProcessCorruptedStateExceptionsAttribute.cs b/de4dot.code/HandleProcessCorruptedStateExceptionsAttribute.cs
new file mode 100644
index 00000000..35fa3230
--- /dev/null
+++ b/de4dot.code/HandleProcessCorruptedStateExceptionsAttribute.cs
@@ -0,0 +1,24 @@
+/*
+ Copyright (C) 2011-2013 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 .
+*/
+
+namespace System.Runtime.ExceptionServices {
+ [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
+ class HandleProcessCorruptedStateExceptionsAttribute : Attribute {
+ }
+}
diff --git a/de4dot.code/ObfuscatedFile.cs b/de4dot.code/ObfuscatedFile.cs
index c4cfa2bf..35cc83e0 100644
--- a/de4dot.code/ObfuscatedFile.cs
+++ b/de4dot.code/ObfuscatedFile.cs
@@ -26,6 +26,7 @@ using dnlib.DotNet;
using dnlib.DotNet.Emit;
using dnlib.DotNet.Writer;
using dnlib.PE;
+using AssemblyData;
using de4dot.code.deobfuscators;
using de4dot.blocks;
using de4dot.blocks.cflow;
@@ -375,9 +376,9 @@ namespace de4dot.code {
CheckSupportedStringDecrypter(StringFeatures.AllowDynamicDecryption);
var newProcFactory = assemblyClientFactory as NewProcessAssemblyClientFactory;
if (newProcFactory != null)
- assemblyClient = newProcFactory.Create(module);
+ assemblyClient = newProcFactory.Create(AssemblyServiceType.StringDecrypter, module);
else
- assemblyClient = assemblyClientFactory.Create();
+ assemblyClient = assemblyClientFactory.Create(AssemblyServiceType.StringDecrypter);
assemblyClient.Connect();
break;
@@ -432,12 +433,12 @@ namespace de4dot.code {
return;
assemblyClient.WaitConnected();
- assemblyClient.Service.LoadAssembly(options.Filename);
+ assemblyClient.StringDecrypterService.LoadAssembly(options.Filename);
if (options.StringDecrypterType == DecrypterType.Delegate)
- assemblyClient.Service.SetStringDecrypterType(AssemblyData.StringDecrypterType.Delegate);
+ assemblyClient.StringDecrypterService.SetStringDecrypterType(AssemblyData.StringDecrypterType.Delegate);
else if (options.StringDecrypterType == DecrypterType.Emulate)
- assemblyClient.Service.SetStringDecrypterType(AssemblyData.StringDecrypterType.Emulate);
+ assemblyClient.StringDecrypterService.SetStringDecrypterType(AssemblyData.StringDecrypterType.Emulate);
else
throw new ApplicationException(string.Format("Invalid string decrypter type '{0}'", options.StringDecrypterType));
@@ -752,11 +753,22 @@ namespace de4dot.code {
}
Dictionary simpleDeobfuscatorFlags = new Dictionary();
bool Check(MethodDef method, SimpleDeobFlags flag) {
+ if (method == null)
+ return false;
SimpleDeobFlags oldFlags;
simpleDeobfuscatorFlags.TryGetValue(method, out oldFlags);
simpleDeobfuscatorFlags[method] = oldFlags | flag;
return (oldFlags & flag) == flag;
}
+ bool Clear(MethodDef method, SimpleDeobFlags flag) {
+ if (method == null)
+ return false;
+ SimpleDeobFlags oldFlags;
+ if (!simpleDeobfuscatorFlags.TryGetValue(method, out oldFlags))
+ return false;
+ simpleDeobfuscatorFlags[method] = oldFlags & ~flag;
+ return true;
+ }
void Deobfuscate(MethodDef method, string msg, Action handler) {
if (savedMethodBodies != null)
@@ -784,12 +796,16 @@ namespace de4dot.code {
Logger.Instance.DeIndent();
}
+ void ISimpleDeobfuscator.MethodModified(MethodDef method) {
+ Clear(method, SimpleDeobFlags.HasDeobfuscated);
+ }
+
void ISimpleDeobfuscator.Deobfuscate(MethodDef method) {
((ISimpleDeobfuscator)this).Deobfuscate(method, false);
}
void ISimpleDeobfuscator.Deobfuscate(MethodDef method, bool force) {
- if (!force && Check(method, SimpleDeobFlags.HasDeobfuscated))
+ if (method == null || (!force && Check(method, SimpleDeobFlags.HasDeobfuscated)))
return;
Deobfuscate(method, "Deobfuscating control flow", (blocks) => {
diff --git a/de4dot.code/StringInliner.cs b/de4dot.code/StringInliner.cs
index afbd29ee..ac77dc02 100644
--- a/de4dot.code/StringInliner.cs
+++ b/de4dot.code/StringInliner.cs
@@ -89,7 +89,7 @@ namespace de4dot.code {
foreach (var methodToken in methodTokens) {
if (methodTokenToId.ContainsKey(methodToken))
continue;
- methodTokenToId[methodToken] = assemblyClient.Service.DefineStringDecrypter(methodToken);
+ methodTokenToId[methodToken] = assemblyClient.StringDecrypterService.DefineStringDecrypter(methodToken);
}
}
@@ -117,7 +117,7 @@ namespace de4dot.code {
AssemblyData.SimpleData.Pack(list[i].args);
args[i] = list[i].args;
}
- var decryptedStrings = assemblyClient.Service.DecryptStrings(methodId, args, Method.MDToken.ToInt32());
+ var decryptedStrings = assemblyClient.StringDecrypterService.DecryptStrings(methodId, args, Method.MDToken.ToInt32());
if (decryptedStrings.Length != args.Length)
throw new ApplicationException("Invalid decrypted strings array length");
AssemblyData.SimpleData.Unpack(decryptedStrings);
diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj
index 31a7bd34..0e189fae 100644
--- a/de4dot.code/de4dot.code.csproj
+++ b/de4dot.code/de4dot.code.csproj
@@ -24,6 +24,7 @@
DEBUG;TRACE
prompt
4
+ true
AnyCPU
@@ -34,6 +35,7 @@
prompt
4
true
+ true
@@ -72,16 +74,36 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+ CsvmResources.resx
+
+
+
+
+
+
+
+
+
+
+
+
@@ -155,9 +177,12 @@
+
+
+
@@ -183,7 +208,14 @@
-
+
+
+
+
+
+
+
+
@@ -235,7 +267,7 @@
-
+
@@ -257,6 +289,7 @@
+
@@ -297,6 +330,7 @@
+
@@ -361,9 +395,9 @@
{FBD84077-9D35-41FE-89DF-8D79EFE0B595}
AssemblyData
-
+
{045B96F2-AF80-4C4C-8D27-E38635AC705E}
- blocks
+ de4dot.blocks
{5C93C5E2-196F-4877-BF65-96FEBFCEFCA1}
@@ -374,6 +408,12 @@
dnlib
+
+
+ ResXFileCodeGenerator
+ CsvmResources.Designer.cs
+
+
mkdir "..\$(OutDir)..\LICENSES"
diff --git a/de4dot.code/deobfuscators/Agile_NET/CliSecureRtType.cs b/de4dot.code/deobfuscators/Agile_NET/CliSecureRtType.cs
index 6f6f233e..3eb06f57 100644
--- a/de4dot.code/deobfuscators/Agile_NET/CliSecureRtType.cs
+++ b/de4dot.code/deobfuscators/Agile_NET/CliSecureRtType.cs
@@ -88,19 +88,6 @@ namespace de4dot.code.deobfuscators.Agile_NET {
static readonly string[] requiredFields1 = new string[] {
"System.Boolean",
};
- static readonly string[] requiredFields2 = new string[] {
- "System.Boolean",
- "System.Reflection.Assembly",
- };
- static readonly string[] requiredFields3 = new string[] {
- "System.Boolean",
- "System.Byte[]",
- };
- static readonly string[] requiredFields4 = new string[] {
- "System.Boolean",
- "System.Reflection.Assembly",
- "System.Byte[]",
- };
bool Find2() {
foreach (var cctor in DeobUtils.GetInitCctors(module, 3)) {
foreach (var calledMethod in DotNetUtils.GetCalledMethods(module, cctor)) {
@@ -108,8 +95,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
if (type.IsPublic)
continue;
var fieldTypes = new FieldTypes(type);
- if (!fieldTypes.Exactly(requiredFields1) && !fieldTypes.Exactly(requiredFields2) &&
- !fieldTypes.Exactly(requiredFields3) && !fieldTypes.Exactly(requiredFields4))
+ if (!fieldTypes.All(requiredFields1))
continue;
if (!HasInitializeMethod(type, "_Initialize") && !HasInitializeMethod(type, "_Initialize64"))
continue;
@@ -126,11 +112,19 @@ namespace de4dot.code.deobfuscators.Agile_NET {
return false;
}
+ static string[] requiredFields6 = new string[] {
+ "System.Byte[]",
+ };
+ static string[] requiredFields7 = new string[] {
+ "System.Byte[]",
+ "System.Collections.Hashtable",
+ };
bool Find3() {
foreach (var type in module.Types) {
- if (type.Fields.Count != 1)
+ if (type.Fields.Count < 1 || type.Fields.Count > 2)
continue;
- if (type.Fields[0].FieldSig.GetFieldType().GetFullName() != "System.Byte[]")
+ var fieldTypes = new FieldTypes(type);
+ if (!fieldTypes.Exactly(requiredFields6) && !fieldTypes.Exactly(requiredFields7))
continue;
if (type.Methods.Count != 2)
continue;
diff --git a/de4dot.code/deobfuscators/Agile_NET/Deobfuscator.cs b/de4dot.code/deobfuscators/Agile_NET/Deobfuscator.cs
index 4caf59ad..e0546f3f 100644
--- a/de4dot.code/deobfuscators/Agile_NET/Deobfuscator.cs
+++ b/de4dot.code/deobfuscators/Agile_NET/Deobfuscator.cs
@@ -85,7 +85,8 @@ namespace de4dot.code.deobfuscators.Agile_NET {
ResourceDecrypter resourceDecrypter;
StackFrameHelper stackFrameHelper;
- vm.Csvm csvm;
+ vm.v1.Csvm csvmV1;
+ vm.v2.Csvm csvmV2;
internal class Options : OptionsBase {
public bool DecryptMethods { get; set; }
@@ -166,7 +167,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
ToInt32(stringDecrypter.Detected) +
ToInt32(proxyCallFixer.Detected) +
ToInt32(resourceDecrypter.Detected) +
- ToInt32(csvm.Detected);
+ ToInt32(csvmV1.Detected || csvmV2.Detected);
if (sum > 0)
val += 100 + 10 * (sum - 1);
if (cliSecureAttributes.Count != 0)
@@ -185,8 +186,10 @@ namespace de4dot.code.deobfuscators.Agile_NET {
resourceDecrypter.Find();
proxyCallFixer = new ProxyCallFixer(module);
proxyCallFixer.FindDelegateCreator();
- csvm = new vm.Csvm(DeobfuscatedFile.DeobfuscatorContext, module);
- csvm.Find();
+ csvmV1 = new vm.v1.Csvm(DeobfuscatedFile.DeobfuscatorContext, module);
+ csvmV1.Find();
+ csvmV2 = new vm.v2.Csvm(DeobfuscatedFile.DeobfuscatorContext, module);
+ csvmV2.Find();
}
void FindCliSecureAttribute() {
@@ -227,7 +230,8 @@ namespace de4dot.code.deobfuscators.Agile_NET {
newOne.stringDecrypter = new StringDecrypter(module, stringDecrypter);
newOne.resourceDecrypter = new ResourceDecrypter(module, resourceDecrypter);
newOne.proxyCallFixer = new ProxyCallFixer(module, proxyCallFixer);
- newOne.csvm = new vm.Csvm(DeobfuscatedFile.DeobfuscatorContext, module, csvm);
+ newOne.csvmV1 = new vm.v1.Csvm(DeobfuscatedFile.DeobfuscatorContext, module, csvmV1);
+ newOne.csvmV2 = new vm.v2.Csvm(DeobfuscatedFile.DeobfuscatorContext, module, csvmV2);
return newOne;
}
@@ -270,9 +274,11 @@ namespace de4dot.code.deobfuscators.Agile_NET {
FindPossibleNamesToRemove(cliSecureRtType.LoadMethod);
}
- if (options.RestoreVmCode) {
- if (csvm.Restore())
- AddResourceToBeRemoved(csvm.Resource, "CSVM data resource");
+ if (options.RestoreVmCode && (csvmV1.Detected || csvmV2.Detected)) {
+ if (csvmV1.Detected && csvmV1.Restore())
+ AddResourceToBeRemoved(csvmV1.Resource, "CSVM data resource");
+ else if (csvmV2.Detected && csvmV2.Restore())
+ AddResourceToBeRemoved(csvmV2.Resource, "CSVM data resource");
else {
Logger.e("Couldn't restore VM methods. Use --dont-rename or it will not run");
PreserveTokensAndTypes();
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/CilOperandInstructionRestorer.cs b/de4dot.code/deobfuscators/Agile_NET/vm/CilOperandInstructionRestorer.cs
index 313243c0..4df28e4c 100644
--- a/de4dot.code/deobfuscators/Agile_NET/vm/CilOperandInstructionRestorer.cs
+++ b/de4dot.code/deobfuscators/Agile_NET/vm/CilOperandInstructionRestorer.cs
@@ -23,9 +23,7 @@ using de4dot.blocks;
namespace de4dot.code.deobfuscators.Agile_NET.vm {
// Tries to restore the operands of the following CIL instructions:
- // ldelema
- // ldobj
- // stobj
+ // ldelema, ldelem.*, stelem.*, ldobj, stobj
class CilOperandInstructionRestorer {
MethodDef method;
@@ -42,10 +40,66 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
if (instr.Operand != null)
continue;
- TypeSig operandType = null;
+ TypeSig operandType = null, operandTypeTmp;
+ OpCode newOpCode = null;
+ SZArraySig arrayType;
switch (instr.OpCode.Code) {
+ case Code.Ldelem:
+ arrayType = MethodStack.GetLoadedType(method, instrs, i, 1) as SZArraySig;
+ if (arrayType == null)
+ break;
+ operandTypeTmp = arrayType.Next;
+ if (operandTypeTmp == null)
+ newOpCode = OpCodes.Ldelem_Ref;
+ else {
+ switch (operandTypeTmp.ElementType) {
+ case ElementType.I: newOpCode = OpCodes.Ldelem_I; break;
+ case ElementType.I1: newOpCode = OpCodes.Ldelem_I1; break;
+ case ElementType.I2: newOpCode = OpCodes.Ldelem_I2; break;
+ case ElementType.I4: newOpCode = OpCodes.Ldelem_I4; break;
+ case ElementType.I8: newOpCode = OpCodes.Ldelem_I8; break;
+ case ElementType.U: newOpCode = OpCodes.Ldelem_I; break;
+ case ElementType.U1: newOpCode = OpCodes.Ldelem_U1; break;
+ case ElementType.U2: newOpCode = OpCodes.Ldelem_U2; break;
+ case ElementType.U4: newOpCode = OpCodes.Ldelem_U4; break;
+ case ElementType.U8: newOpCode = OpCodes.Ldelem_I8; break;
+ case ElementType.R4: newOpCode = OpCodes.Ldelem_R4; break;
+ case ElementType.R8: newOpCode = OpCodes.Ldelem_R8; break;
+ default: newOpCode = OpCodes.Ldelem_Ref; break;
+ //TODO: Ldelem
+ }
+ }
+ break;
+
+ case Code.Stelem:
+ arrayType = MethodStack.GetLoadedType(method, instrs, i, 2) as SZArraySig;
+ if (arrayType == null)
+ break;
+ operandTypeTmp = arrayType.Next;
+ if (operandTypeTmp == null)
+ newOpCode = OpCodes.Stelem_Ref;
+ else {
+ switch (operandTypeTmp.ElementType) {
+ case ElementType.U:
+ case ElementType.I: newOpCode = OpCodes.Stelem_I; break;
+ case ElementType.U1:
+ case ElementType.I1: newOpCode = OpCodes.Stelem_I1; break;
+ case ElementType.U2:
+ case ElementType.I2: newOpCode = OpCodes.Stelem_I2; break;
+ case ElementType.U4:
+ case ElementType.I4: newOpCode = OpCodes.Stelem_I4; break;
+ case ElementType.U8:
+ case ElementType.I8: newOpCode = OpCodes.Stelem_I8; break;
+ case ElementType.R4: newOpCode = OpCodes.Stelem_R4; break;
+ case ElementType.R8: newOpCode = OpCodes.Stelem_R8; break;
+ default: newOpCode = OpCodes.Stelem_Ref; break;
+ //TODO: Stelem
+ }
+ }
+ break;
+
case Code.Ldelema:
- var arrayType = MethodStack.GetLoadedType(method, instrs, i, 1) as SZArraySig;
+ arrayType = MethodStack.GetLoadedType(method, instrs, i, 1) as SZArraySig;
if (arrayType == null)
break;
operandType = arrayType.Next;
@@ -64,12 +118,14 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
default:
continue;
}
- if (!IsValidType(operandType)) {
+ if (newOpCode == null && !IsValidType(operandType)) {
atLeastOneFailed = true;
continue;
}
instr.Operand = operandType.ToTypeDefOrRef();
+ if (newOpCode != null)
+ instr.OpCode = newOpCode;
}
return !atLeastOneFailed;
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/CsvmToCilMethodConverter.cs b/de4dot.code/deobfuscators/Agile_NET/vm/CsvmToCilMethodConverterBase.cs
similarity index 75%
rename from de4dot.code/deobfuscators/Agile_NET/vm/CsvmToCilMethodConverter.cs
rename to de4dot.code/deobfuscators/Agile_NET/vm/CsvmToCilMethodConverterBase.cs
index b468ef9e..00757dab 100644
--- a/de4dot.code/deobfuscators/Agile_NET/vm/CsvmToCilMethodConverter.cs
+++ b/de4dot.code/deobfuscators/Agile_NET/vm/CsvmToCilMethodConverterBase.cs
@@ -25,22 +25,33 @@ using dnlib.DotNet.Emit;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.Agile_NET.vm {
- class CsvmToCilMethodConverter {
- IDeobfuscatorContext deobfuscatorContext;
- ModuleDefMD module;
- VmOpCodeHandlerDetector opCodeDetector;
- CilOperandInstructionRestorer operandRestorer = new CilOperandInstructionRestorer();
+ abstract class CsvmToCilMethodConverterBase {
+ readonly IDeobfuscatorContext deobfuscatorContext;
+ readonly protected ModuleDefMD module;
+ readonly CilOperandInstructionRestorer operandRestorer = new CilOperandInstructionRestorer();
+ readonly Dictionary cilToVmIndex = new Dictionary();
+ readonly Dictionary vmIndexToCil = new Dictionary();
- public CsvmToCilMethodConverter(IDeobfuscatorContext deobfuscatorContext, ModuleDefMD module, VmOpCodeHandlerDetector opCodeDetector) {
+ public CsvmToCilMethodConverterBase(IDeobfuscatorContext deobfuscatorContext, ModuleDefMD module) {
this.deobfuscatorContext = deobfuscatorContext;
this.module = module;
- this.opCodeDetector = opCodeDetector;
+ }
+
+ protected void SetCilToVmIndex(Instruction instr, int vmIndex) {
+ cilToVmIndex[instr] = vmIndex;
+ }
+
+ protected void SetVmIndexToCil(Instruction instr, int vmIndex) {
+ vmIndexToCil[vmIndex] = instr;
}
public void Convert(MethodDef cilMethod, CsvmMethodData csvmMethod) {
+ cilToVmIndex.Clear();
+ vmIndexToCil.Clear();
+
var newInstructions = ReadInstructions(cilMethod, csvmMethod);
var newLocals = ReadLocals(cilMethod, csvmMethod);
- var newExceptions = ReadExceptions(cilMethod, csvmMethod, newInstructions);
+ var newExceptions = ReadExceptions(cilMethod, csvmMethod);
FixInstructionOperands(newInstructions);
FixLocals(newInstructions, cilMethod.Body.Variables);
@@ -59,7 +70,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
if (op == null)
continue;
- UpdateLocalInstruction(instr, locals[op.local], op.local);
+ UpdateLocalInstruction(instr, locals[op.Local], op.Local);
}
}
@@ -134,7 +145,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
if (op == null)
continue;
- UpdateArgInstruction(instr, method.Parameters[op.arg], op.arg);
+ UpdateArgInstruction(instr, method.Parameters[op.Arg], op.Arg);
}
}
@@ -197,28 +208,16 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
}
}
- List ReadInstructions(MethodDef cilMethod, CsvmMethodData csvmMethod) {
- var reader = new BinaryReader(new MemoryStream(csvmMethod.Instructions));
- var instrs = new List();
- uint offset = 0;
- while (reader.BaseStream.Position < reader.BaseStream.Length) {
- int vmOpCode = reader.ReadUInt16();
- var instr = opCodeDetector.Handlers[vmOpCode].Read(reader);
- instr.Offset = offset;
- offset += (uint)GetInstructionSize(instr);
- instrs.Add(instr);
- }
- return instrs;
- }
+ protected abstract List ReadInstructions(MethodDef cilMethod, CsvmMethodData csvmMethod);
- static int GetInstructionSize(Instruction instr) {
+ protected static int GetInstructionSize(Instruction instr) {
var opcode = instr.OpCode;
if (opcode == null)
return 5; // Load store/field
var op = instr.Operand as SwitchTargetDisplOperand;
if (op == null)
return instr.GetSize();
- return instr.OpCode.Size + (op.targetDisplacements.Length + 1) * 4;
+ return instr.OpCode.Size + (op.TargetDisplacements.Length + 1) * 4;
}
List ReadLocals(MethodDef cilMethod, CsvmMethodData csvmMethod) {
@@ -289,7 +288,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
}
}
- List ReadExceptions(MethodDef cilMethod, CsvmMethodData csvmMethod, List cilInstructions) {
+ List ReadExceptions(MethodDef cilMethod, CsvmMethodData csvmMethod) {
var reader = new BinaryReader(new MemoryStream(csvmMethod.Exceptions));
var ehs = new List();
@@ -302,14 +301,14 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
for (int i = 0; i < numExceptions; i++) {
var eh = new ExceptionHandler((ExceptionHandlerType)reader.ReadInt32());
- eh.TryStart = GetInstruction(cilInstructions, reader.ReadInt32());
- eh.TryEnd = GetInstructionEnd(cilInstructions, reader.ReadInt32());
- eh.HandlerStart = GetInstruction(cilInstructions, reader.ReadInt32());
- eh.HandlerEnd = GetInstructionEnd(cilInstructions, reader.ReadInt32());
+ eh.TryStart = GetInstruction(reader.ReadInt32());
+ eh.TryEnd = GetInstructionEnd(reader.ReadInt32());
+ eh.HandlerStart = GetInstruction(reader.ReadInt32());
+ eh.HandlerEnd = GetInstructionEnd(reader.ReadInt32());
if (eh.HandlerType == ExceptionHandlerType.Catch)
eh.CatchType = module.ResolveToken(reader.ReadUInt32()) as ITypeDefOrRef;
else if (eh.HandlerType == ExceptionHandlerType.Filter)
- eh.FilterStart = GetInstruction(cilInstructions, reader.ReadInt32());
+ eh.FilterStart = GetInstruction(reader.ReadInt32());
ehs.Add(eh);
}
@@ -317,22 +316,20 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
return ehs;
}
- static Instruction GetInstruction(IList instrs, int index) {
- return instrs[index];
+ Instruction GetInstruction(int vmIndex) {
+ return vmIndexToCil[vmIndex];
}
- static Instruction GetInstructionEnd(IList instrs, int index) {
- index++;
- if (index == instrs.Count)
- return null;
- return instrs[index];
+ Instruction GetInstructionEnd(int vmIndex) {
+ vmIndex++;
+ Instruction instr;
+ vmIndexToCil.TryGetValue(vmIndex, out instr);
+ return instr;
}
- static Instruction GetInstruction(IList instrs, Instruction source, int displ) {
- int sourceIndex = instrs.IndexOf(source);
- if (sourceIndex < 0)
- throw new ApplicationException("Could not find source instruction");
- return instrs[sourceIndex + displ];
+ Instruction GetInstruction(Instruction source, int displ) {
+ int vmIndex = cilToVmIndex[source];
+ return vmIndexToCil[vmIndex + displ];
}
void FixInstructionOperands(IList instrs) {
@@ -344,41 +341,33 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
}
object FixOperand(IList instrs, Instruction instr, IVmOperand vmOperand) {
- if (vmOperand is TokenOperand)
- return GetMemberRef(((TokenOperand)vmOperand).token);
-
if (vmOperand is TargetDisplOperand)
- return GetInstruction(instrs, instr, ((TargetDisplOperand)vmOperand).displacement);
+ return GetInstruction(instr, ((TargetDisplOperand)vmOperand).Displacement);
if (vmOperand is SwitchTargetDisplOperand) {
- var targetDispls = ((SwitchTargetDisplOperand)vmOperand).targetDisplacements;
+ var targetDispls = ((SwitchTargetDisplOperand)vmOperand).TargetDisplacements;
Instruction[] targets = new Instruction[targetDispls.Length];
for (int i = 0; i < targets.Length; i++)
- targets[i] = GetInstruction(instrs, instr, targetDispls[i]);
+ targets[i] = GetInstruction(instr, targetDispls[i]);
return targets;
}
if (vmOperand is ArgOperand || vmOperand is LocalOperand)
return vmOperand;
- if (vmOperand is LoadFieldOperand)
- return FixLoadStoreFieldInstruction(instr, ((LoadFieldOperand)vmOperand).token, OpCodes.Ldsfld, OpCodes.Ldfld);
-
- if (vmOperand is LoadFieldAddressOperand)
- return FixLoadStoreFieldInstruction(instr, ((LoadFieldAddressOperand)vmOperand).token, OpCodes.Ldsflda, OpCodes.Ldflda);
-
- if (vmOperand is StoreFieldOperand)
- return FixLoadStoreFieldInstruction(instr, ((StoreFieldOperand)vmOperand).token, OpCodes.Stsfld, OpCodes.Stfld);
+ if (vmOperand is FieldInstructionOperand) {
+ var fieldInfo = (FieldInstructionOperand)vmOperand;
+ return FixLoadStoreFieldInstruction(instr, fieldInfo.Field, fieldInfo.StaticOpCode, fieldInfo.InstanceOpCode);
+ }
throw new ApplicationException(string.Format("Unknown operand type: {0}", vmOperand.GetType()));
}
- IField FixLoadStoreFieldInstruction(Instruction instr, int token, OpCode staticInstr, OpCode instanceInstr) {
- var fieldRef = module.ResolveToken(token) as IField;
+ IField FixLoadStoreFieldInstruction(Instruction instr, IField fieldRef, OpCode staticInstr, OpCode instanceInstr) {
var field = deobfuscatorContext.ResolveField(fieldRef);
bool isStatic;
if (field == null) {
- Logger.w("Could not resolve field {0:X8}. Assuming it's not static.", token);
+ Logger.w("Could not resolve field {0:X8}. Assuming it's not static.", fieldRef == null ? 0 : fieldRef.MDToken.Raw);
isStatic = false;
}
else
@@ -387,13 +376,6 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
return fieldRef;
}
- ITokenOperand GetMemberRef(int token) {
- var memberRef = module.ResolveToken(token) as ITokenOperand;
- if (memberRef == null)
- throw new ApplicationException(string.Format("Could not find member ref: {0:X8}", token));
- return memberRef;
- }
-
static void RestoreConstrainedPrefix(MethodDef method) {
if (method == null || method.Body == null)
return;
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/VmOperands.cs b/de4dot.code/deobfuscators/Agile_NET/vm/VmOperand.cs
similarity index 54%
rename from de4dot.code/deobfuscators/Agile_NET/vm/VmOperands.cs
rename to de4dot.code/deobfuscators/Agile_NET/vm/VmOperand.cs
index bfb143a8..03cde6c4 100644
--- a/de4dot.code/deobfuscators/Agile_NET/vm/VmOperands.cs
+++ b/de4dot.code/deobfuscators/Agile_NET/vm/VmOperand.cs
@@ -17,66 +17,50 @@
along with de4dot. If not, see .
*/
+using dnlib.DotNet;
+using dnlib.DotNet.Emit;
+
namespace de4dot.code.deobfuscators.Agile_NET.vm {
interface IVmOperand {
}
- class TokenOperand : IVmOperand {
- public int token; // any type of token
- public TokenOperand(int token) {
- this.token = token;
- }
- }
-
class TargetDisplOperand : IVmOperand {
- public int displacement; // number of instructions from current instr
+ public readonly int Displacement; // number of VM instructions from current VM instr
public TargetDisplOperand(int displacement) {
- this.displacement = displacement;
+ this.Displacement = displacement;
}
}
class SwitchTargetDisplOperand : IVmOperand {
- public int[] targetDisplacements; // number of instructions from current instr
+ public readonly int[] TargetDisplacements; // number of VM instructions from current VM instr
public SwitchTargetDisplOperand(int[] targetDisplacements) {
- this.targetDisplacements = targetDisplacements;
+ this.TargetDisplacements = targetDisplacements;
}
}
class ArgOperand : IVmOperand {
- public ushort arg;
+ public readonly ushort Arg;
public ArgOperand(ushort arg) {
- this.arg = arg;
+ this.Arg = arg;
}
}
class LocalOperand : IVmOperand {
- public ushort local;
+ public readonly ushort Local;
public LocalOperand(ushort local) {
- this.local = local;
+ this.Local = local;
}
}
- // OpCode must be changed to ldfld / ldsfld
- class LoadFieldOperand : IVmOperand {
- public int token;
- public LoadFieldOperand(int token) {
- this.token = token;
- }
- }
+ class FieldInstructionOperand : IVmOperand {
+ public readonly OpCode StaticOpCode;
+ public readonly OpCode InstanceOpCode;
+ public readonly IField Field;
- // OpCode must be changed to ldflda / ldsflda
- class LoadFieldAddressOperand : IVmOperand {
- public int token;
- public LoadFieldAddressOperand(int token) {
- this.token = token;
- }
- }
-
- // OpCode must be changed to stfld / stsfld
- class StoreFieldOperand : IVmOperand {
- public int token;
- public StoreFieldOperand(int token) {
- this.token = token;
+ public FieldInstructionOperand(OpCode staticOpCode, OpCode instanceOpCode, IField field) {
+ this.StaticOpCode = staticOpCode;
+ this.InstanceOpCode = instanceOpCode;
+ this.Field = field;
}
}
}
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/Csvm.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v1/Csvm.cs
similarity index 97%
rename from de4dot.code/deobfuscators/Agile_NET/vm/Csvm.cs
rename to de4dot.code/deobfuscators/Agile_NET/vm/v1/Csvm.cs
index e3030940..91339051 100644
--- a/de4dot.code/deobfuscators/Agile_NET/vm/Csvm.cs
+++ b/de4dot.code/deobfuscators/Agile_NET/vm/v1/Csvm.cs
@@ -23,7 +23,7 @@ using System.IO;
using dnlib.DotNet;
using de4dot.blocks;
-namespace de4dot.code.deobfuscators.Agile_NET.vm {
+namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
class Csvm {
IDeobfuscatorContext deobfuscatorContext;
ModuleDefMD module;
@@ -140,7 +140,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
var vmModulePath = Path.Combine(Path.GetDirectoryName(module.Location), vmFilename);
Logger.v("CSVM filename: {0}", vmFilename);
- var dataKey = "cs cached VmOpCodeHandlerDetector";
+ var dataKey = "cs cached VmOpCodeHandlerDetector v1";
var dict = (Dictionary)deobfuscatorContext.GetData(dataKey);
if (dict == null)
deobfuscatorContext.SetData(dataKey, dict = new Dictionary(StringComparer.OrdinalIgnoreCase));
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v1/CsvmToCilMethodConverter.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v1/CsvmToCilMethodConverter.cs
new file mode 100644
index 00000000..93516c18
--- /dev/null
+++ b/de4dot.code/deobfuscators/Agile_NET/vm/v1/CsvmToCilMethodConverter.cs
@@ -0,0 +1,52 @@
+/*
+ Copyright (C) 2011-2013 de4dot@gmail.com
+
+ This file is part of de4dot.
+
+ de4dot is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ de4dot is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with de4dot. If not, see .
+*/
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using dnlib.DotNet;
+using dnlib.DotNet.Emit;
+using de4dot.blocks;
+
+namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
+ class CsvmToCilMethodConverter : CsvmToCilMethodConverterBase {
+ VmOpCodeHandlerDetector opCodeDetector;
+
+ public CsvmToCilMethodConverter(IDeobfuscatorContext deobfuscatorContext, ModuleDefMD module, VmOpCodeHandlerDetector opCodeDetector)
+ : base(deobfuscatorContext, module) {
+ this.opCodeDetector = opCodeDetector;
+ }
+
+ protected override List ReadInstructions(MethodDef cilMethod, CsvmMethodData csvmMethod) {
+ var reader = new BinaryReader(new MemoryStream(csvmMethod.Instructions));
+ var instrs = new List();
+ uint offset = 0;
+ while (reader.BaseStream.Position < reader.BaseStream.Length) {
+ int vmOpCode = reader.ReadUInt16();
+ var instr = opCodeDetector.Handlers[vmOpCode].Read(reader, module);
+ instr.Offset = offset;
+ offset += (uint)GetInstructionSize(instr);
+ SetCilToVmIndex(instr, instrs.Count);
+ SetVmIndexToCil(instr, instrs.Count);
+ instrs.Add(instr);
+ }
+ return instrs;
+ }
+ }
+}
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/FieldsInfo.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v1/FieldsInfo.cs
similarity index 97%
rename from de4dot.code/deobfuscators/Agile_NET/vm/FieldsInfo.cs
rename to de4dot.code/deobfuscators/Agile_NET/vm/v1/FieldsInfo.cs
index a6945092..875d349d 100644
--- a/de4dot.code/deobfuscators/Agile_NET/vm/FieldsInfo.cs
+++ b/de4dot.code/deobfuscators/Agile_NET/vm/v1/FieldsInfo.cs
@@ -21,7 +21,7 @@ using System;
using System.Collections.Generic;
using dnlib.DotNet;
-namespace de4dot.code.deobfuscators.Agile_NET.vm {
+namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
class FieldsInfo {
public static readonly object EnumType = new object();
Dictionary fieldTypes = new Dictionary(StringComparer.Ordinal);
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/OpCodeHandler.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v1/OpCodeHandler.cs
similarity index 78%
rename from de4dot.code/deobfuscators/Agile_NET/vm/OpCodeHandler.cs
rename to de4dot.code/deobfuscators/Agile_NET/vm/v1/OpCodeHandler.cs
index 1a911df6..9c572780 100644
--- a/de4dot.code/deobfuscators/Agile_NET/vm/OpCodeHandler.cs
+++ b/de4dot.code/deobfuscators/Agile_NET/vm/v1/OpCodeHandler.cs
@@ -24,12 +24,12 @@ using de4dot.blocks;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
-namespace de4dot.code.deobfuscators.Agile_NET.vm {
+namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
partial class OpCodeHandler {
public string Name { get; set; }
public OpCodeHandlerSigInfo OpCodeHandlerSigInfo { get; set; }
public Predicate Check { get; set; }
- public Func Read { get; set; }
+ public Func Read { get; set; }
public bool Detect(UnknownHandlerInfo info) {
var sigInfo = OpCodeHandlerSigInfo;
@@ -68,7 +68,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
}
static partial class OpCodeHandlers {
- static Instruction arithmetic_read(BinaryReader reader) {
+ static Instruction arithmetic_read(BinaryReader reader, IInstructionOperandResolver resolver) {
switch (reader.ReadByte()) {
case 0: return OpCodes.Add.ToInstruction();
case 1: return OpCodes.Add_Ovf.ToInstruction();
@@ -91,25 +91,22 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
return DotNetUtils.CallsMethod(info.ExecuteMethod, "System.Type System.Reflection.Module::ResolveType(System.Int32)");
}
- static Instruction newarr_read(BinaryReader reader) {
- return new Instruction {
- OpCode = OpCodes.Newarr,
- Operand = new TokenOperand(reader.ReadInt32()),
- };
+ static Instruction newarr_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ return new Instruction(OpCodes.Newarr, resolver.ResolveToken(reader.ReadUInt32()));
}
- static Instruction box_read(BinaryReader reader) {
+ static Instruction box_read(BinaryReader reader, IInstructionOperandResolver resolver) {
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 = new TokenOperand(reader.ReadInt32());
+ instr.Operand = resolver.ResolveToken(reader.ReadUInt32());
return instr;
}
- static Instruction call_read(BinaryReader reader) {
+ static Instruction call_read(BinaryReader reader, IInstructionOperandResolver resolver) {
var instr = new Instruction();
switch (reader.ReadByte()) {
case 0: instr.OpCode = OpCodes.Newobj; break;
@@ -117,22 +114,22 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
case 2: instr.OpCode = OpCodes.Callvirt; break;
default: throw new ApplicationException("Invalid opcode");
}
- instr.Operand = new TokenOperand(reader.ReadInt32());
+ instr.Operand = resolver.ResolveToken(reader.ReadUInt32());
return instr;
}
- static Instruction cast_read(BinaryReader reader) {
+ static Instruction cast_read(BinaryReader reader, IInstructionOperandResolver resolver) {
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 = new TokenOperand(reader.ReadInt32());
+ instr.Operand = resolver.ResolveToken(reader.ReadUInt32());
return instr;
}
- static Instruction compare_read(BinaryReader reader) {
+ static Instruction compare_read(BinaryReader reader, IInstructionOperandResolver resolver) {
int type = reader.ReadByte();
Instruction instr = new Instruction();
switch (type) {
@@ -205,7 +202,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
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) {
+ static Instruction convert_read(BinaryReader reader, IInstructionOperandResolver resolver) {
byte type = reader.ReadByte();
bool second = reader.ReadBoolean();
bool third = reader.ReadBoolean();
@@ -215,7 +212,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
if (type != info.Type || info.Second != second || info.Third != third)
continue;
- instr = new Instruction { OpCode = info.OpCode };
+ instr = new Instruction(info.OpCode);
break;
}
if (instr == null)
@@ -224,7 +221,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
return instr;
}
- static Instruction dup_read(BinaryReader reader) {
+ static Instruction dup_read(BinaryReader reader, IInstructionOperandResolver resolver) {
switch (reader.ReadByte()) {
case 0: return OpCodes.Dup.ToInstruction();
case 1: return OpCodes.Pop.ToInstruction();
@@ -262,7 +259,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
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) {
+ static Instruction ldelem_read(BinaryReader reader, IInstructionOperandResolver resolver) {
Instruction instr = null;
bool first = reader.ReadBoolean();
bool second = reader.ReadBoolean();
@@ -274,9 +271,9 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
continue;
if (second)
- instr = new Instruction { OpCode = info.OpCode };
+ instr = new Instruction(info.OpCode);
else
- instr = new Instruction { OpCode = info.OpCode, Operand = new TokenOperand(value) };
+ instr = new Instruction(info.OpCode, resolver.ResolveToken((uint)value));
break;
}
if (instr == null)
@@ -289,29 +286,26 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
return DotNetUtils.CallsMethod(info.ExecuteMethod, "System.Reflection.MethodInfo System.Type::GetMethod(System.String,System.Reflection.BindingFlags)");
}
- static Instruction endfinally_read(BinaryReader reader) {
+ static Instruction endfinally_read(BinaryReader reader, IInstructionOperandResolver resolver) {
return OpCodes.Endfinally.ToInstruction();
}
- static Instruction ldfld_read(BinaryReader reader) {
- var instr = new Instruction();
- switch (reader.ReadByte()) {
- case 0: instr.Operand = new LoadFieldOperand(reader.ReadInt32()); break;
- case 1: instr.Operand = new LoadFieldAddressOperand(reader.ReadInt32()); break;
- case 2: instr.Operand = new StoreFieldOperand(reader.ReadInt32()); break;
+ static Instruction ldfld_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ byte b = reader.ReadByte();
+ var field = resolver.ResolveToken(reader.ReadUInt32()) 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));
+ case 2: return new Instruction(null, new FieldInstructionOperand(OpCodes.Stsfld, OpCodes.Stfld, field));
default: throw new ApplicationException("Invalid opcode");
}
- return instr;
}
- static Instruction initobj_read(BinaryReader reader) {
- return new Instruction {
- OpCode = OpCodes.Initobj,
- Operand = new TokenOperand(reader.ReadInt32()),
- };
+ static Instruction initobj_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ return new Instruction(OpCodes.Initobj, resolver.ResolveToken(reader.ReadUInt32()));
}
- static Instruction ldloc_read(BinaryReader reader) {
+ static Instruction ldloc_read(BinaryReader reader, IInstructionOperandResolver resolver) {
bool isLdarg = reader.ReadBoolean();
ushort index = reader.ReadUInt16();
@@ -328,7 +322,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
return instr;
}
- static Instruction ldloca_read(BinaryReader reader) {
+ static Instruction ldloca_read(BinaryReader reader, IInstructionOperandResolver resolver) {
Instruction instr = new Instruction();
if (reader.ReadBoolean()) {
instr.OpCode = OpCodes.Ldarga;
@@ -342,25 +336,19 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
return instr;
}
- static Instruction ldelema_read(BinaryReader reader) {
- return new Instruction {
- OpCode = OpCodes.Ldelema,
- Operand = null,
- };
+ static Instruction ldelema_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ return new Instruction(OpCodes.Ldelema, null);
}
- static Instruction ldlen_read(BinaryReader reader) {
+ static Instruction ldlen_read(BinaryReader reader, IInstructionOperandResolver resolver) {
return OpCodes.Ldlen.ToInstruction();
}
- static Instruction ldobj_read(BinaryReader reader) {
- return new Instruction {
- OpCode = OpCodes.Ldobj,
- Operand = null,
- };
+ static Instruction ldobj_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ return new Instruction(OpCodes.Ldobj, null);
}
- static Instruction ldstr_read(BinaryReader reader) {
+ static Instruction ldstr_read(BinaryReader reader, IInstructionOperandResolver resolver) {
return OpCodes.Ldstr.ToInstruction(reader.ReadString());
}
@@ -368,11 +356,8 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
return DotNetUtils.CallsMethod(info.ExecuteMethod, "System.Reflection.MemberInfo System.Reflection.Module::ResolveMember(System.Int32)");
}
- static Instruction ldtoken_read(BinaryReader reader) {
- return new Instruction {
- OpCode = OpCodes.Ldtoken,
- Operand = new TokenOperand(reader.ReadInt32()),
- };
+ static Instruction ldtoken_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ return new Instruction(OpCodes.Ldtoken, resolver.ResolveToken(reader.ReadUInt32()));
}
static bool leave_check(UnknownHandlerInfo info) {
@@ -381,15 +366,12 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
!DotNetUtils.CallsMethod(info.ExecuteMethod, "System.Reflection.MemberInfo System.Reflection.Module::ResolveMember(System.Int32)");
}
- static Instruction leave_read(BinaryReader reader) {
+ static Instruction leave_read(BinaryReader reader, IInstructionOperandResolver resolver) {
int displacement = reader.ReadInt32();
- return new Instruction {
- OpCode = OpCodes.Leave,
- Operand = new TargetDisplOperand(displacement),
- };
+ return new Instruction(OpCodes.Leave, new TargetDisplOperand(displacement));
}
- static Instruction ldc_read(BinaryReader reader) {
+ static Instruction ldc_read(BinaryReader reader, IInstructionOperandResolver resolver) {
switch ((ElementType)reader.ReadByte()) {
case ElementType.I4: return Instruction.CreateLdcI4(reader.ReadInt32());
case ElementType.I8: return OpCodes.Ldc_I8.ToInstruction(reader.ReadInt64());
@@ -400,29 +382,24 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
}
}
- static Instruction ldftn_read(BinaryReader reader) {
+ static Instruction ldftn_read(BinaryReader reader, IInstructionOperandResolver resolver) {
byte code = reader.ReadByte();
- int token = reader.ReadInt32();
+ uint token = reader.ReadUInt32();
- Instruction instr;
switch (code) {
case 0:
- instr = new Instruction { OpCode = OpCodes.Ldftn, Operand = new TokenOperand(token) };
- break;
+ return new Instruction(OpCodes.Ldftn, resolver.ResolveToken(token));
case 1:
reader.ReadInt32(); // token of newobj .ctor
- instr = new Instruction { OpCode = OpCodes.Ldvirtftn, Operand = new TokenOperand(token) };
- break;
+ return new Instruction(OpCodes.Ldvirtftn, resolver.ResolveToken(token));
default:
throw new ApplicationException("Invalid opcode");
}
-
- return instr;
}
- static Instruction logical_read(BinaryReader reader) {
+ static Instruction logical_read(BinaryReader reader, IInstructionOperandResolver resolver) {
switch (reader.ReadByte()) {
case 0: return OpCodes.And.ToInstruction();
case 1: return OpCodes.Or.ToInstruction();
@@ -448,7 +425,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
return false;
}
- static Instruction nop_read(BinaryReader reader) {
+ static Instruction nop_read(BinaryReader reader, IInstructionOperandResolver resolver) {
return OpCodes.Nop.ToInstruction();
}
@@ -456,7 +433,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
return DotNetUtils.CallsMethod(info.ExecuteMethod, "System.Reflection.MethodBase System.Reflection.Module::ResolveMethod(System.Int32)");
}
- static Instruction ret_read(BinaryReader reader) {
+ static Instruction ret_read(BinaryReader reader, IInstructionOperandResolver resolver) {
reader.ReadInt32(); // token of current method
return OpCodes.Ret.ToInstruction();
}
@@ -465,11 +442,11 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
return info.ExecuteMethod.Body.Variables.Count == 0;
}
- static Instruction rethrow_read(BinaryReader reader) {
+ static Instruction rethrow_read(BinaryReader reader, IInstructionOperandResolver resolver) {
return OpCodes.Rethrow.ToInstruction();
}
- static Instruction stloc_read(BinaryReader reader) {
+ static Instruction stloc_read(BinaryReader reader, IInstructionOperandResolver resolver) {
bool isStarg = reader.ReadBoolean();
ushort index = reader.ReadUInt16();
@@ -487,33 +464,27 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
return instr;
}
- static Instruction stobj_read(BinaryReader reader) {
- return new Instruction {
- OpCode = OpCodes.Stobj,
- Operand = null,
- };
+ static Instruction stobj_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ return new Instruction(OpCodes.Stobj, null);
}
- static Instruction switch_read(BinaryReader reader) {
+ static Instruction switch_read(BinaryReader reader, IInstructionOperandResolver resolver) {
int numTargets = reader.ReadInt32();
int[] targetDispls = new int[numTargets];
for (int i = 0; i < targetDispls.Length; i++)
targetDispls[i] = reader.ReadInt32();
- return new Instruction {
- OpCode = OpCodes.Switch,
- Operand = new SwitchTargetDisplOperand(targetDispls),
- };
+ return new Instruction(OpCodes.Switch, new SwitchTargetDisplOperand(targetDispls));
}
static bool throw_check(UnknownHandlerInfo info) {
return !DotNetUtils.CallsMethod(info.ExecuteMethod, "System.Reflection.MethodInfo System.Type::GetMethod(System.String,System.Reflection.BindingFlags)");
}
- static Instruction throw_read(BinaryReader reader) {
+ static Instruction throw_read(BinaryReader reader, IInstructionOperandResolver resolver) {
return OpCodes.Throw.ToInstruction();
}
- static Instruction neg_read(BinaryReader reader) {
+ static Instruction neg_read(BinaryReader reader, IInstructionOperandResolver resolver) {
switch (reader.ReadByte()) {
case 0: return OpCodes.Neg.ToInstruction();
case 1: return OpCodes.Not.ToInstruction();
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/OpCodeHandlers.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v1/OpCodeHandlers.cs
similarity index 99%
rename from de4dot.code/deobfuscators/Agile_NET/vm/OpCodeHandlers.cs
rename to de4dot.code/deobfuscators/Agile_NET/vm/v1/OpCodeHandlers.cs
index 6b9dd252..aa8419a3 100644
--- a/de4dot.code/deobfuscators/Agile_NET/vm/OpCodeHandlers.cs
+++ b/de4dot.code/deobfuscators/Agile_NET/vm/v1/OpCodeHandlers.cs
@@ -17,9 +17,9 @@
along with de4dot. If not, see .
*/
-namespace de4dot.code.deobfuscators.Agile_NET.vm {
+namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
static partial class OpCodeHandlers {
- public static readonly OpCodeHandler[][] opcodeHandlers = new OpCodeHandler[][] {
+ public static readonly OpCodeHandler[][] Handlers = new OpCodeHandler[][] {
new OpCodeHandler[] {
new OpCodeHandler {
Name = "arithmetic",
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/UnknownHandlerInfo.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v1/UnknownHandlerInfo.cs
similarity index 98%
rename from de4dot.code/deobfuscators/Agile_NET/vm/UnknownHandlerInfo.cs
rename to de4dot.code/deobfuscators/Agile_NET/vm/v1/UnknownHandlerInfo.cs
index 05557708..b2a08276 100644
--- a/de4dot.code/deobfuscators/Agile_NET/vm/UnknownHandlerInfo.cs
+++ b/de4dot.code/deobfuscators/Agile_NET/vm/v1/UnknownHandlerInfo.cs
@@ -23,7 +23,7 @@ using dnlib.DotNet;
using dnlib.DotNet.Emit;
using de4dot.blocks;
-namespace de4dot.code.deobfuscators.Agile_NET.vm {
+namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
class UnknownHandlerInfo {
TypeDef type;
CsvmInfo csvmInfo;
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/VmOpCodeHandlerDetector.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v1/VmOpCodeHandlerDetector.cs
similarity index 98%
rename from de4dot.code/deobfuscators/Agile_NET/vm/VmOpCodeHandlerDetector.cs
rename to de4dot.code/deobfuscators/Agile_NET/vm/v1/VmOpCodeHandlerDetector.cs
index 5be219cc..b06ca9c8 100644
--- a/de4dot.code/deobfuscators/Agile_NET/vm/VmOpCodeHandlerDetector.cs
+++ b/de4dot.code/deobfuscators/Agile_NET/vm/v1/VmOpCodeHandlerDetector.cs
@@ -24,7 +24,7 @@ using dnlib.DotNet.Emit;
using de4dot.blocks;
using de4dot.blocks.cflow;
-namespace de4dot.code.deobfuscators.Agile_NET.vm {
+namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
class OpCodeHandlerSigInfo {
public object[] RequiredFieldTypes { get; set; }
public string[] ExecuteMethodLocals { get; set; }
@@ -214,7 +214,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
opCodeHandlers = new List();
var detected = new List();
- foreach (var handlersList in OpCodeHandlers.opcodeHandlers) {
+ foreach (var handlersList in OpCodeHandlers.Handlers) {
opCodeHandlers.Clear();
foreach (var handlerType in handlerTypes) {
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM1_v2.bin b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM1_v2.bin
new file mode 100644
index 00000000..156f0777
Binary files /dev/null and b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM1_v2.bin differ
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM2_v2.bin b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM2_v2.bin
new file mode 100644
index 00000000..81bd5ae6
Binary files /dev/null and b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM2_v2.bin differ
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM3_v2.bin b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM3_v2.bin
new file mode 100644
index 00000000..a86daab3
Binary files /dev/null and b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM3_v2.bin differ
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CompositeHandlerDetector.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CompositeHandlerDetector.cs
new file mode 100644
index 00000000..9ae1debc
--- /dev/null
+++ b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CompositeHandlerDetector.cs
@@ -0,0 +1,335 @@
+/*
+ Copyright (C) 2011-2013 de4dot@gmail.com
+
+ This file is part of de4dot.
+
+ de4dot is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ de4dot is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with de4dot. If not, see .
+*/
+
+using System;
+using System.Collections.Generic;
+using dnlib.DotNet;
+using dnlib.DotNet.Emit;
+using de4dot.blocks;
+
+namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
+ class CompositeHandlerDetector {
+ readonly List handlers;
+
+ public CompositeHandlerDetector(IList handlers) {
+ this.handlers = new List(handlers.Count);
+ OpCodeHandler nop = null;
+ foreach (var handler in handlers) {
+ if (nop == null && handler.OpCodeHandlerInfo.TypeCode == HandlerTypeCode.Nop)
+ nop = handler;
+ else
+ this.handlers.Add(handler);
+ }
+ if (nop != null)
+ this.handlers.Add(nop);
+ }
+
+ struct MatchState {
+ public HandlerState OtherState;
+ public HandlerState CompositeState;
+
+ public MatchState(HandlerState OtherState, HandlerState CompositeState) {
+ this.OtherState = OtherState;
+ this.CompositeState = CompositeState;
+ }
+ }
+
+ struct HandlerState {
+ public readonly HandlerMethod HandlerMethod;
+ public readonly IList Blocks;
+ public readonly int BlockIndex;
+ public int InstructionIndex;
+
+ public HandlerState(HandlerMethod handlerMethod, int blockIndex, int instructionIndex) {
+ this.HandlerMethod = handlerMethod;
+ this.Blocks = handlerMethod.Blocks.MethodBlocks.GetAllBlocks();
+ this.BlockIndex = blockIndex;
+ this.InstructionIndex = instructionIndex;
+ }
+
+ public HandlerState(HandlerMethod handlerMethod, IList blocks, int blockIndex, int instructionIndex) {
+ this.HandlerMethod = handlerMethod;
+ this.Blocks = blocks;
+ this.BlockIndex = blockIndex;
+ this.InstructionIndex = instructionIndex;
+ }
+
+ public HandlerState Clone() {
+ return new HandlerState(HandlerMethod, Blocks, BlockIndex, InstructionIndex);
+ }
+ }
+
+ struct FindHandlerState {
+ public HandlerState CompositeState;
+ public readonly Dictionary VisitedCompositeBlocks;
+ public bool Done;
+
+ public FindHandlerState(HandlerState compositeState) {
+ this.CompositeState = compositeState;
+ this.VisitedCompositeBlocks = new Dictionary();
+ this.Done = false;
+ }
+
+ public FindHandlerState(HandlerState compositeState, Dictionary visitedCompositeBlocks, bool done) {
+ this.CompositeState = compositeState;
+ this.VisitedCompositeBlocks = new Dictionary(visitedCompositeBlocks);
+ this.Done = done;
+ }
+
+ public FindHandlerState Clone() {
+ return new FindHandlerState(CompositeState.Clone(), VisitedCompositeBlocks, Done);
+ }
+ }
+
+ public bool FindHandlers(CompositeOpCodeHandler composite) {
+ composite.OpCodeHandlerInfos.Clear();
+ var compositeExecState = new FindHandlerState(new HandlerState(composite.ExecMethod, 0, 0));
+ while (!compositeExecState.Done) {
+ var handler = FindHandlerMethod(ref compositeExecState);
+ if (handler == null)
+ return false;
+
+ composite.OpCodeHandlerInfos.Add(handler.OpCodeHandlerInfo);
+ }
+ return composite.OpCodeHandlerInfos.Count != 0;
+ }
+
+ OpCodeHandler FindHandlerMethod(ref FindHandlerState findExecState) {
+ foreach (var handler in handlers) {
+ FindHandlerState findExecStateNew = findExecState.Clone();
+ if (!Matches(handler.ExecMethod, ref findExecStateNew))
+ continue;
+
+ findExecState = findExecStateNew;
+ return handler;
+ }
+ return null;
+ }
+
+ Stack stack = new Stack();
+ bool Matches(HandlerMethod handler, ref FindHandlerState findState) {
+ HandlerState? nextState = null;
+ stack.Clear();
+ stack.Push(new MatchState(new HandlerState(handler, 0, 0), findState.CompositeState));
+ while (stack.Count > 0) {
+ var matchState = stack.Pop();
+
+ if (matchState.CompositeState.InstructionIndex == 0) {
+ if (findState.VisitedCompositeBlocks.ContainsKey(matchState.CompositeState.BlockIndex))
+ continue;
+ findState.VisitedCompositeBlocks[matchState.CompositeState.BlockIndex] = true;
+ }
+ else {
+ if (!findState.VisitedCompositeBlocks.ContainsKey(matchState.CompositeState.BlockIndex))
+ throw new ApplicationException("Block hasn't been visited");
+ }
+
+ if (!Compare(ref matchState.OtherState, ref matchState.CompositeState))
+ return false;
+
+ var hblock = matchState.OtherState.Blocks[matchState.OtherState.BlockIndex];
+ var hinstrs = hblock.Instructions;
+ int hi = matchState.OtherState.InstructionIndex;
+ var cblock = matchState.CompositeState.Blocks[matchState.CompositeState.BlockIndex];
+ var cinstrs = cblock.Instructions;
+ int ci = matchState.CompositeState.InstructionIndex;
+ if (hi < hinstrs.Count)
+ return false;
+
+ if (ci < cinstrs.Count) {
+ if (hblock.CountTargets() != 0)
+ return false;
+ if (hblock.LastInstr.OpCode.Code == Code.Ret) {
+ if (nextState != null)
+ return false;
+ nextState = matchState.CompositeState;
+ }
+ }
+ else {
+ if (cblock.CountTargets() != hblock.CountTargets())
+ return false;
+ if (cblock.FallThrough != null || hblock.FallThrough != null) {
+ if (cblock.FallThrough == null || hblock.FallThrough == null)
+ return false;
+
+ var hs = CreateHandlerState(handler, matchState.OtherState.Blocks, hblock.FallThrough);
+ var cs = CreateHandlerState(findState.CompositeState.HandlerMethod, findState.CompositeState.Blocks, cblock.FallThrough);
+ stack.Push(new MatchState(hs, cs));
+ }
+ if (cblock.Targets != null || hblock.Targets != null) {
+ if (cblock.Targets == null || hblock.Targets == null ||
+ cblock.Targets.Count != hblock.Targets.Count)
+ return false;
+
+ for (int i = 0; i < cblock.Targets.Count; i++) {
+ var hs = CreateHandlerState(handler, matchState.OtherState.Blocks, hblock.Targets[i]);
+ var cs = CreateHandlerState(findState.CompositeState.HandlerMethod, findState.CompositeState.Blocks, cblock.Targets[i]);
+ stack.Push(new MatchState(hs, cs));
+ }
+ }
+ }
+ }
+
+ if (nextState == null) {
+ findState.Done = true;
+ return true;
+ }
+ else {
+ if (findState.CompositeState.BlockIndex == nextState.Value.BlockIndex &&
+ findState.CompositeState.InstructionIndex == nextState.Value.InstructionIndex)
+ return false;
+ findState.CompositeState = nextState.Value;
+ return true;
+ }
+ }
+
+ static HandlerState CreateHandlerState(HandlerMethod handler, IList blocks, Block target) {
+ return new HandlerState(handler, blocks.IndexOf(target), 0);
+ }
+
+ static bool Compare(ref HandlerState handler, ref HandlerState composite) {
+ var hinstrs = handler.Blocks[handler.BlockIndex].Instructions;
+ int hi = handler.InstructionIndex;
+ var cinstrs = composite.Blocks[composite.BlockIndex].Instructions;
+ int ci = composite.InstructionIndex;
+
+ while (true) {
+ if (hi >= hinstrs.Count && ci >= cinstrs.Count)
+ break;
+ if (hi >= hinstrs.Count || ci >= cinstrs.Count)
+ return false;
+
+ var hinstr = hinstrs[hi++];
+ var cinstr = cinstrs[ci++];
+ if (hinstr.OpCode.Code == Code.Nop ||
+ cinstr.OpCode.Code == Code.Nop) {
+ if (hinstr.OpCode.Code != Code.Nop)
+ hi--;
+ if (cinstr.OpCode.Code != Code.Nop)
+ ci--;
+ continue;
+ }
+
+ if (hi == hinstrs.Count && hinstr.OpCode.Code == Code.Ret) {
+ if (cinstr.OpCode.Code != Code.Br && cinstr.OpCode.Code != Code.Ret)
+ ci--;
+ break;
+ }
+
+ if (hinstr.OpCode.Code != cinstr.OpCode.Code)
+ return false;
+
+ if (hinstr.OpCode.Code == Code.Ldfld &&
+ hi + 1 < hinstrs.Count && ci + 1 < cinstrs.Count) {
+ var hfield = hinstr.Operand as FieldDef;
+ var cfield = cinstr.Operand as FieldDef;
+ if (hfield != null && cfield != null &&
+ !hfield.IsStatic && !cfield.IsStatic &&
+ hfield.DeclaringType == handler.HandlerMethod.Method.DeclaringType &&
+ cfield.DeclaringType == composite.HandlerMethod.Method.DeclaringType &&
+ SignatureEqualityComparer.Instance.Equals(hfield.Signature, cfield.Signature)) {
+ cinstr = cinstrs[ci++];
+ hinstr = hinstrs[hi++];
+ if (cinstr.OpCode.Code != Code.Ldc_I4 ||
+ hinstr.OpCode.Code != Code.Ldc_I4)
+ return false;
+ continue;
+ }
+ }
+
+ if (!CompareOperand(hinstr.OpCode.OperandType, cinstr.Operand, hinstr.Operand))
+ return false;
+ }
+
+ handler.InstructionIndex = hi;
+ composite.InstructionIndex = ci;
+ return true;
+ }
+
+ static bool CompareOperand(OperandType opType, object a, object b) {
+ switch (opType) {
+ case OperandType.ShortInlineI:
+ return (a is byte && b is byte && (byte)a == (byte)b) ||
+ (a is sbyte && b is sbyte && (sbyte)a == (sbyte)b);
+
+ case OperandType.InlineI:
+ return a is int && b is int && (int)a == (int)b;
+
+ case OperandType.InlineI8:
+ return a is long && b is long && (long)a == (long)b;
+
+ case OperandType.ShortInlineR:
+ return a is float && b is float && (float)a == (float)b;
+
+ case OperandType.InlineR:
+ return a is double && b is double && (double)a == (double)b;
+
+ case OperandType.InlineField:
+ return FieldEqualityComparer.CompareDeclaringTypes.Equals(a as IField, b as IField);
+
+ case OperandType.InlineMethod:
+ return MethodEqualityComparer.CompareDeclaringTypes.Equals(a as IMethod, b as IMethod);
+
+ case OperandType.InlineSig:
+ return SignatureEqualityComparer.Instance.Equals(a as MethodSig, b as MethodSig);
+
+ case OperandType.InlineString:
+ return string.Equals(a as string, b as string);
+
+ case OperandType.InlineSwitch:
+ var al = a as IList;
+ var bl = b as IList;
+ return al != null && bl != null && al.Count == bl.Count;
+
+ case OperandType.InlineTok:
+ var fa = a as IField;
+ var fb = b as IField;
+ if (fa != null && fb != null)
+ return FieldEqualityComparer.CompareDeclaringTypes.Equals(fa, fb);
+ var ma = a as IMethod;
+ var mb = b as IMethod;
+ if (ma != null && mb != null)
+ return MethodEqualityComparer.CompareDeclaringTypes.Equals(ma, mb);
+ return TypeEqualityComparer.Instance.Equals(a as ITypeDefOrRef, b as ITypeDefOrRef);
+
+ case OperandType.InlineType:
+ return TypeEqualityComparer.Instance.Equals(a as ITypeDefOrRef, b as ITypeDefOrRef);
+
+ case OperandType.InlineVar:
+ case OperandType.ShortInlineVar:
+ var la = a as Local;
+ var lb = b as Local;
+ if (la != null && lb != null)
+ return true;
+ var pa = a as Parameter;
+ var pb = b as Parameter;
+ return pa != null && pb != null && pa.Index == pb.Index;
+
+ case OperandType.InlineBrTarget:
+ case OperandType.ShortInlineBrTarget:
+ case OperandType.InlineNone:
+ case OperandType.InlinePhi:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+ }
+}
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CompositeOpCodeHandler.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CompositeOpCodeHandler.cs
new file mode 100644
index 00000000..2508d020
--- /dev/null
+++ b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CompositeOpCodeHandler.cs
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2011-2013 de4dot@gmail.com
+
+ This file is part of de4dot.
+
+ de4dot is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ de4dot is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with de4dot. If not, see .
+*/
+
+using System.Collections.Generic;
+using System.Text;
+using dnlib.DotNet;
+using de4dot.blocks;
+
+namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
+ class HandlerMethod {
+ public MethodDef Method { get; private set; }
+ public Blocks Blocks { get; private set; }
+
+ public HandlerMethod(MethodDef method) {
+ this.Method = method;
+ this.Blocks = new Blocks(method);
+ }
+ }
+
+ class PrimitiveHandlerMethod : HandlerMethod {
+ public MethodSigInfo Sig { get; set; }
+
+ public PrimitiveHandlerMethod(MethodDef method)
+ : base(method) {
+ }
+ }
+
+ class CompositeOpCodeHandler {
+ public TypeDef HandlerType { get; private set; }
+ public HandlerMethod ExecMethod { get; private set; }
+ public List OpCodeHandlerInfos { get; private set; }
+
+ public CompositeOpCodeHandler(TypeDef handlerType, HandlerMethod execMethod) {
+ this.HandlerType = handlerType;
+ this.ExecMethod = execMethod;
+ this.OpCodeHandlerInfos = new List();
+ }
+
+ public override string ToString() {
+ if (OpCodeHandlerInfos.Count == 0)
+ return "";
+ var sb = new StringBuilder();
+ foreach (var handler in OpCodeHandlerInfos) {
+ if (sb.Length != 0)
+ sb.Append(", ");
+ sb.Append(handler.Name);
+ }
+ return sb.ToString();
+ }
+ }
+}
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/Csvm.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v2/Csvm.cs
new file mode 100644
index 00000000..9b6f0c10
--- /dev/null
+++ b/de4dot.code/deobfuscators/Agile_NET/vm/v2/Csvm.cs
@@ -0,0 +1,164 @@
+/*
+ Copyright (C) 2011-2013 de4dot@gmail.com
+
+ This file is part of de4dot.
+
+ de4dot is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ de4dot is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with de4dot. If not, see .
+*/
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using dnlib.DotNet;
+using de4dot.blocks;
+
+namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
+ class Csvm {
+ IDeobfuscatorContext deobfuscatorContext;
+ ModuleDefMD module;
+ EmbeddedResource resource;
+ AssemblyRef vmAssemblyRef;
+
+ public bool Detected {
+ get { return resource != null && vmAssemblyRef != null; }
+ }
+
+ public EmbeddedResource Resource {
+ get { return Detected ? resource : null; }
+ }
+
+ public Csvm(IDeobfuscatorContext deobfuscatorContext, ModuleDefMD module) {
+ this.deobfuscatorContext = deobfuscatorContext;
+ this.module = module;
+ }
+
+ public Csvm(IDeobfuscatorContext deobfuscatorContext, ModuleDefMD module, Csvm oldOne) {
+ this.deobfuscatorContext = deobfuscatorContext;
+ this.module = module;
+ if (oldOne.resource != null)
+ this.resource = (EmbeddedResource)module.Resources[oldOne.module.Resources.IndexOf(oldOne.resource)];
+ if (oldOne.vmAssemblyRef != null)
+ this.vmAssemblyRef = module.ResolveAssemblyRef(oldOne.vmAssemblyRef.Rid);
+ }
+
+ public void Find() {
+ resource = FindCsvmResource();
+ vmAssemblyRef = FindVmAssemblyRef();
+ }
+
+ AssemblyRef FindVmAssemblyRef() {
+ foreach (var memberRef in module.GetMemberRefs()) {
+ var sig = memberRef.MethodSig;
+ if (sig == null)
+ continue;
+ if (sig.RetType.GetElementType() != ElementType.Object)
+ continue;
+ if (sig.Params.Count != 2)
+ continue;
+ if (memberRef.Name != "RunMethod")
+ continue;
+ if (memberRef.FullName == "System.Object VMRuntime.Libraries.CSVMRuntime::RunMethod(System.String,System.Object[])")
+ return memberRef.DeclaringType.Scope as AssemblyRef;
+ }
+ return null;
+ }
+
+ EmbeddedResource FindCsvmResource() {
+ return DotNetUtils.GetResource(module, "_CSVM") as EmbeddedResource;
+ }
+
+ public bool Restore() {
+ if (!Detected)
+ return true;
+
+ int oldIndent = Logger.Instance.IndentLevel;
+ try {
+ Restore2();
+ return true;
+ }
+ catch {
+ return false;
+ }
+ finally {
+ Logger.Instance.IndentLevel = oldIndent;
+ }
+ }
+
+ void Restore2() {
+ Logger.n("Restoring CSVM methods");
+ Logger.Instance.Indent();
+
+ var opcodeDetector = GetVmOpCodeHandlerDetector();
+ var csvmMethods = new CsvmDataReader(resource.Data).Read();
+
+ var converter = new CsvmToCilMethodConverter(deobfuscatorContext, module, opcodeDetector);
+ var methodPrinter = new MethodPrinter();
+ foreach (var csvmMethod in csvmMethods) {
+ var cilMethod = module.ResolveToken(csvmMethod.Token) as MethodDef;
+ if (cilMethod == null)
+ throw new ApplicationException(string.Format("Could not find method {0:X8}", csvmMethod.Token));
+ converter.Convert(cilMethod, csvmMethod);
+ Logger.v("Restored method {0:X8}", cilMethod.MDToken.ToInt32());
+ PrintMethod(methodPrinter, cilMethod);
+ }
+ Logger.Instance.DeIndent();
+ Logger.n("Restored {0} CSVM methods", csvmMethods.Count);
+ }
+
+ static void PrintMethod(MethodPrinter methodPrinter, MethodDef method) {
+ const LoggerEvent dumpLogLevel = LoggerEvent.Verbose;
+ if (Logger.Instance.IgnoresEvent(dumpLogLevel))
+ return;
+
+ Logger.Instance.Indent();
+
+ Logger.v("Locals:");
+ Logger.Instance.Indent();
+ for (int i = 0; i < method.Body.Variables.Count; i++)
+ Logger.v("#{0}: {1}", i, method.Body.Variables[i].Type);
+ Logger.Instance.DeIndent();
+
+ Logger.v("Code:");
+ Logger.Instance.Indent();
+ methodPrinter.Print(dumpLogLevel, method.Body.Instructions, method.Body.ExceptionHandlers);
+ Logger.Instance.DeIndent();
+
+ Logger.Instance.DeIndent();
+ }
+
+ VmOpCodeHandlerDetector GetVmOpCodeHandlerDetector() {
+ var vmFilename = vmAssemblyRef.Name + ".dll";
+ var vmModulePath = Path.Combine(Path.GetDirectoryName(module.Location), vmFilename);
+ Logger.v("CSVM filename: {0}", vmFilename);
+
+ var dataKey = "cs cached VmOpCodeHandlerDetector v2";
+ var dict = (Dictionary)deobfuscatorContext.GetData(dataKey);
+ if (dict == null)
+ deobfuscatorContext.SetData(dataKey, dict = new Dictionary(StringComparer.OrdinalIgnoreCase));
+ VmOpCodeHandlerDetector detector;
+ if (dict.TryGetValue(vmModulePath, out detector))
+ return detector;
+ dict[vmModulePath] = detector = new VmOpCodeHandlerDetector(ModuleDefMD.Load(vmModulePath));
+
+ detector.FindHandlers();
+ Logger.v("CSVM opcodes: {0}", detector.Handlers.Count);
+ Logger.Instance.Indent();
+ for (int i = 0; i < detector.Handlers.Count; i++)
+ Logger.v("{0:X4}: {1}", i, detector.Handlers[i]);
+ Logger.Instance.DeIndent();
+
+ return detector;
+ }
+ }
+}
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmInfo.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmInfo.cs
new file mode 100644
index 00000000..815cc53d
--- /dev/null
+++ b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmInfo.cs
@@ -0,0 +1,779 @@
+/*
+ Copyright (C) 2011-2013 de4dot@gmail.com
+
+ This file is part of de4dot.
+
+ de4dot is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ de4dot is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with de4dot. If not, see .
+*/
+
+using System;
+using dnlib.DotNet;
+using dnlib.DotNet.Emit;
+using de4dot.blocks;
+
+namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
+ class CsvmInfo {
+ ModuleDef module;
+
+ public TypeDef VmHandlerBaseType;
+
+ public MethodDef LogicalOpShrUn;
+ public MethodDef LogicalOpShl;
+ public MethodDef LogicalOpShr;
+ public MethodDef LogicalOpAnd;
+ public MethodDef LogicalOpXor;
+ public MethodDef LogicalOpOr;
+
+ public MethodDef CompareLt;
+ public MethodDef CompareLte;
+ public MethodDef CompareGt;
+ public MethodDef CompareGte;
+ public MethodDef CompareEq;
+ public MethodDef CompareEqz;
+
+ public MethodDef ArithmeticSubOvfUn;
+ public MethodDef ArithmeticMulOvfUn;
+ public MethodDef ArithmeticRemUn;
+ public MethodDef ArithmeticRem;
+ public MethodDef ArithmeticDivUn;
+ public MethodDef ArithmeticDiv;
+ public MethodDef ArithmeticMul;
+ public MethodDef ArithmeticMulOvf;
+ public MethodDef ArithmeticSub;
+ public MethodDef ArithmeticSubOvf;
+ public MethodDef ArithmeticAddOvfUn;
+ public MethodDef ArithmeticAddOvf;
+ public MethodDef ArithmeticAdd;
+
+ public MethodDef UnaryNot;
+ public MethodDef UnaryNeg;
+
+ public MethodDef ArgsGet;
+ public MethodDef ArgsSet;
+ public MethodDef LocalsGet;
+ public MethodDef LocalsSet;
+
+ public CsvmInfo(ModuleDef module) {
+ this.module = module;
+ }
+
+ public bool Initialize() {
+ return FindVmHandlerBase() &&
+ FindLocalOpsMethods() &&
+ FindComparerMethods() &&
+ FindArithmeticMethods() &&
+ FindUnaryOpsMethods() &&
+ FindArgsLocals();
+ }
+
+ public bool FindVmHandlerBase() {
+ foreach (var type in module.Types) {
+ if (!type.IsPublic || !type.IsAbstract)
+ continue;
+ if (type.HasFields || type.HasProperties || type.HasEvents)
+ continue;
+ if (type.BaseType == null || type.BaseType.FullName != "System.Object")
+ continue;
+ if (CountVirtual(type) != 2)
+ continue;
+
+ VmHandlerBaseType = type;
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool FindLocalOpsMethods() {
+ foreach (var type in module.Types) {
+ if (type.BaseType == null || type.BaseType.FullName != "System.Object")
+ continue;
+ if (type.Methods.Count != 6 && type.Methods.Count != 7)
+ continue;
+ LogicalOpShrUn = FindLogicalOpMethodShrUn(type);
+ if (LogicalOpShrUn == null)
+ continue;
+ LogicalOpShl = FindLogicalOpMethodShl(type);
+ LogicalOpShr = FindLogicalOpMethodShr(type);
+ LogicalOpAnd = FindLogicalOpMethodAnd(type);
+ LogicalOpXor = FindLogicalOpMethodXor(type);
+ LogicalOpOr = FindLogicalOpMethodOr(type);
+ if (LogicalOpShrUn != null && LogicalOpShl != null &&
+ LogicalOpShr != null && LogicalOpAnd != null &&
+ LogicalOpXor != null && LogicalOpOr != null)
+ return true;
+ }
+
+ return false;
+ }
+
+ MethodDef FindLogicalOpMethodShrUn(TypeDef type) {
+ return FindLogicalOpMethod(type, ElementType.U4, ElementType.I4, ElementType.U4, Code.Shr_Un);
+ }
+
+ MethodDef FindLogicalOpMethodShl(TypeDef type) {
+ return FindLogicalOpMethod(type, ElementType.I4, ElementType.I4, ElementType.I4, Code.Shl);
+ }
+
+ MethodDef FindLogicalOpMethodShr(TypeDef type) {
+ return FindLogicalOpMethod(type, ElementType.I4, ElementType.I4, ElementType.I4, Code.Shr);
+ }
+
+ MethodDef FindLogicalOpMethod(TypeDef type, ElementType e1, ElementType e2, ElementType e3, Code code) {
+ foreach (var method in type.Methods) {
+ if (!CheckLogicalMethodSig(method))
+ continue;
+ if (method.Body == null)
+ continue;
+ var instrs = method.Body.Instructions;
+ for (int i = 0; i < instrs.Count - 7; i++) {
+ var ldarg0 = instrs[i];
+ if (!ldarg0.IsLdarg() || ldarg0.GetParameterIndex() != 0)
+ continue;
+ if (!CheckUnboxAny(instrs[i + 1], e1))
+ continue;
+ var ldarg1 = instrs[i + 2];
+ if (!ldarg1.IsLdarg() || ldarg1.GetParameterIndex() != 1)
+ continue;
+ if (!CheckUnboxAny(instrs[i + 3], e2))
+ continue;
+ var ldci4 = instrs[i + 4];
+ if (!ldci4.IsLdcI4() || ldci4.GetLdcI4Value() != 0x1F)
+ continue;
+ if (instrs[i + 5].OpCode.Code != Code.And)
+ continue;
+ if (instrs[i + 6].OpCode.Code != code)
+ continue;
+ if (!CheckBox(instrs[i + 7], e3))
+ continue;
+
+ return method;
+ }
+ }
+
+ return null;
+ }
+
+ MethodDef FindLogicalOpMethodAnd(TypeDef type) {
+ return FindLogicalOpMethod(type, Code.And);
+ }
+
+ MethodDef FindLogicalOpMethodXor(TypeDef type) {
+ return FindLogicalOpMethod(type, Code.Xor);
+ }
+
+ MethodDef FindLogicalOpMethodOr(TypeDef type) {
+ return FindLogicalOpMethod(type, Code.Or);
+ }
+
+ MethodDef FindLogicalOpMethod(TypeDef type, Code code) {
+ foreach (var method in type.Methods) {
+ if (!CheckLogicalMethodSig(method))
+ continue;
+ if (method.Body == null)
+ continue;
+ var instrs = method.Body.Instructions;
+ for (int i = 0; i < instrs.Count - 5; i++) {
+ var ldarg0 = instrs[i];
+ if (!ldarg0.IsLdarg() || ldarg0.GetParameterIndex() != 0)
+ continue;
+ if (!CheckUnboxAny(instrs[i + 1], ElementType.I4))
+ continue;
+ var ldarg1 = instrs[i + 2];
+ if (!ldarg1.IsLdarg() || ldarg1.GetParameterIndex() != 1)
+ continue;
+ if (!CheckUnboxAny(instrs[i + 3], ElementType.I4))
+ continue;
+ if (instrs[i + 4].OpCode.Code != code)
+ continue;
+ if (!CheckBox(instrs[i + 5], ElementType.I4))
+ continue;
+
+ return method;
+ }
+ }
+
+ return null;
+ }
+
+ static bool CheckLogicalMethodSig(MethodDef method) {
+ return method != null &&
+ method.IsStatic &&
+ method.MethodSig.GetParamCount() == 2 &&
+ method.MethodSig.RetType.GetElementType() == ElementType.Object &&
+ method.MethodSig.Params[0].GetElementType() == ElementType.Object &&
+ method.MethodSig.Params[1].GetElementType() == ElementType.Object;
+ }
+
+ public bool FindComparerMethods() {
+ foreach (var type in module.Types) {
+ if (type.BaseType == null || type.BaseType.FullName != "System.Object")
+ continue;
+ if (type.Methods.Count != 9)
+ continue;
+ CompareLt = FindCompareLt(type);
+ if (CompareLt == null)
+ continue;
+ CompareLte = FindCompareLte(type);
+ CompareGt = FindCompareGt(type);
+ CompareGte = FindCompareGte(type);
+ CompareEq = FindCompareEq(type);
+ CompareEqz = FindCompareEqz(type);
+ if (CompareLt != null && CompareLte != null &&
+ CompareGt != null && CompareGte != null &&
+ CompareEq != null && CompareEqz != null)
+ return true;
+ }
+
+ return false;
+ }
+
+ MethodDef FindCompareLt(TypeDef type) {
+ return FindCompareMethod(type, Code.Clt, false);
+ }
+
+ MethodDef FindCompareLte(TypeDef type) {
+ return FindCompareMethod(type, Code.Cgt, true);
+ }
+
+ MethodDef FindCompareGt(TypeDef type) {
+ return FindCompareMethod(type, Code.Cgt, false);
+ }
+
+ MethodDef FindCompareGte(TypeDef type) {
+ return FindCompareMethod(type, Code.Clt, true);
+ }
+
+ MethodDef FindCompareMethod(TypeDef type, Code code, bool invert) {
+ foreach (var method in type.Methods) {
+ if (!CheckCompareMethodSig(method))
+ continue;
+ if (method.Body == null)
+ continue;
+ var instrs = method.Body.Instructions;
+ int end = instrs.Count - 6;
+ if (invert)
+ end -= 2;
+ for (int i = 0; i < end; i++) {
+ int index = i;
+ var ldarg0 = instrs[index++];
+ if (!ldarg0.IsLdarg() || ldarg0.GetParameterIndex() != 0)
+ continue;
+ if (!CheckUnboxAny(instrs[index++], ElementType.I4))
+ continue;
+ var ldarg1 = instrs[index++];
+ if (!ldarg1.IsLdarg() || ldarg1.GetParameterIndex() != 1)
+ continue;
+ if (!CheckUnboxAny(instrs[index++], ElementType.I4))
+ continue;
+ if (instrs[index++].OpCode.Code != code)
+ continue;
+ if (invert) {
+ var ldci4 = instrs[index++];
+ if (!ldci4.IsLdcI4() || ldci4.GetLdcI4Value() != 0)
+ continue;
+ if (instrs[index++].OpCode.Code != Code.Ceq)
+ continue;
+ }
+ if (!instrs[index++].IsStloc())
+ continue;
+
+ return method;
+ }
+ }
+
+ return null;
+ }
+
+ static bool CheckCompareMethodSig(MethodDef method) {
+ if (method == null || !method.IsStatic)
+ return false;
+ var sig = method.MethodSig;
+ if (sig == null || sig.GetParamCount() != 3)
+ return false;
+ if (sig.RetType.GetElementType() != ElementType.Boolean)
+ return false;
+ if (sig.Params[0].GetElementType() != ElementType.Object)
+ return false;
+ if (sig.Params[1].GetElementType() != ElementType.Object)
+ return false;
+ var arg2 = sig.Params[2] as ValueTypeSig;
+ if (arg2 == null || arg2.TypeDef == null || !arg2.TypeDef.IsEnum)
+ return false;
+
+ return true;
+ }
+
+ MethodDef FindCompareEq(TypeDef type) {
+ foreach (var method in type.Methods) {
+ if (!CheckCompareEqMethodSig(method))
+ continue;
+ if (method.Body == null)
+ continue;
+ var instrs = method.Body.Instructions;
+ for (int i = 0; i < instrs.Count - 5; i++) {
+ var ldarg0 = instrs[i];
+ if (!ldarg0.IsLdarg() || ldarg0.GetParameterIndex() != 0)
+ continue;
+ if (!CheckUnboxAny(instrs[i + 1], ElementType.I4))
+ continue;
+ var ldarg1 = instrs[i + 2];
+ if (!ldarg1.IsLdarg() || ldarg1.GetParameterIndex() != 1)
+ continue;
+ if (!CheckUnboxAny(instrs[i + 3], ElementType.I4))
+ continue;
+ if (instrs[i + 4].OpCode.Code != Code.Ceq)
+ continue;
+ if (!instrs[i + 5].IsStloc())
+ continue;
+
+ return method;
+ }
+ }
+
+ return null;
+ }
+
+ static bool CheckCompareEqMethodSig(MethodDef method) {
+ return method != null &&
+ method.IsStatic &&
+ method.MethodSig.GetParamCount() == 2 &&
+ method.MethodSig.RetType.GetElementType() == ElementType.Boolean &&
+ method.MethodSig.Params[0].GetElementType() == ElementType.Object &&
+ method.MethodSig.Params[1].GetElementType() == ElementType.Object;
+ }
+
+ MethodDef FindCompareEqz(TypeDef type) {
+ foreach (var method in type.Methods) {
+ if (!CheckCompareEqzMethodSig(method))
+ continue;
+ if (method.Body == null)
+ continue;
+ var instrs = method.Body.Instructions;
+ for (int i = 0; i < instrs.Count - 4; i++) {
+ var ldarg0 = instrs[i];
+ if (!ldarg0.IsLdarg() || ldarg0.GetParameterIndex() != 0)
+ continue;
+ if (!CheckUnboxAny(instrs[i + 1], ElementType.I4))
+ continue;
+ var ldci4 = instrs[i + 2];
+ if (!ldci4.IsLdcI4() || ldci4.GetLdcI4Value() != 0)
+ continue;
+ if (instrs[i + 3].OpCode.Code != Code.Ceq)
+ continue;
+ if (!instrs[i + 4].IsStloc())
+ continue;
+
+ return method;
+ }
+ }
+
+ return null;
+ }
+
+ static bool CheckCompareEqzMethodSig(MethodDef method) {
+ return method != null &&
+ method.IsStatic &&
+ method.MethodSig.GetParamCount() == 1 &&
+ method.MethodSig.RetType.GetElementType() == ElementType.Boolean &&
+ method.MethodSig.Params[0].GetElementType() == ElementType.Object;
+ }
+
+ public bool FindArithmeticMethods() {
+ foreach (var type in module.Types) {
+ if (type.BaseType == null || type.BaseType.FullName != "System.Object")
+ continue;
+ if (type.Methods.Count != 15)
+ continue;
+ ArithmeticSubOvfUn = FindArithmeticSubOvfUn(type);
+ if (ArithmeticSubOvfUn == null)
+ continue;
+ ArithmeticMulOvfUn = FindArithmeticMulOvfUn(type);
+ ArithmeticRemUn = FindArithmeticRemUn(type);
+ ArithmeticRem = FindArithmeticRem(type);
+ ArithmeticDivUn = FindArithmeticDivUn(type);
+ ArithmeticDiv = FindArithmeticDiv(type);
+ ArithmeticMul = FindArithmeticMul(type);
+ ArithmeticMulOvf = FindArithmeticMulOvf(type);
+ ArithmeticSub = FindArithmeticSub(type);
+ ArithmeticSubOvf = FindArithmeticSubOvf(type);
+ ArithmeticAddOvfUn = FindArithmeticAddOvfUn(type);
+ ArithmeticAddOvf = FindArithmeticAddOvf(type);
+ ArithmeticAdd = FindArithmeticAdd(type);
+
+ if (ArithmeticSubOvfUn != null && ArithmeticMulOvfUn != null &&
+ ArithmeticRemUn != null && ArithmeticRem != null &&
+ ArithmeticDivUn != null && ArithmeticDiv != null &&
+ ArithmeticMul != null && ArithmeticMulOvf != null &&
+ ArithmeticSub != null && ArithmeticSubOvf != null &&
+ ArithmeticAddOvfUn != null && ArithmeticAddOvf != null &&
+ ArithmeticAdd != null)
+ return true;
+ }
+
+ return false;
+ }
+
+ MethodDef FindArithmeticSubOvfUn(TypeDef type) {
+ return FindArithmeticOpUn(type, Code.Sub_Ovf_Un);
+ }
+
+ MethodDef FindArithmeticMulOvfUn(TypeDef type) {
+ return FindArithmeticOpUn(type, Code.Mul_Ovf_Un);
+ }
+
+ MethodDef FindArithmeticAddOvfUn(TypeDef type) {
+ return FindArithmeticOpUn(type, Code.Add_Ovf_Un);
+ }
+
+ MethodDef FindArithmeticOpUn(TypeDef type, Code code) {
+ foreach (var method in type.Methods) {
+ if (!CheckArithmeticUnMethodSig(method))
+ continue;
+ if (method.Body == null)
+ continue;
+ var instrs = method.Body.Instructions;
+ for (int i = 0; i < instrs.Count - 8; i++) {
+ var ldarg0 = instrs[i];
+ if (!ldarg0.IsLdarg() || ldarg0.GetParameterIndex() != 0)
+ continue;
+ if (!CheckCallvirt(instrs[i + 1], "System.Int32", "()"))
+ continue;
+ if (instrs[i + 2].OpCode.Code != Code.Conv_Ovf_U4)
+ continue;
+ var ldarg1 = instrs[i + 3];
+ if (!ldarg1.IsLdarg() || ldarg1.GetParameterIndex() != 1)
+ continue;
+ if (!CheckCallvirt(instrs[i + 4], "System.Int32", "()"))
+ continue;
+ if (instrs[i + 5].OpCode.Code != Code.Conv_Ovf_U4)
+ continue;
+ if (instrs[i + 6].OpCode.Code != code)
+ continue;
+ if (!CheckBox(instrs[i + 7], ElementType.U4))
+ continue;
+ if (!instrs[i + 8].IsStloc())
+ continue;
+
+ return method;
+ }
+ }
+
+ return null;
+ }
+
+ static bool CheckArithmeticUnMethodSig(MethodDef method) {
+ return method != null &&
+ method.IsStatic &&
+ method.MethodSig.GetParamCount() == 2 &&
+ method.MethodSig.RetType.GetElementType() == ElementType.Object &&
+ method.MethodSig.Params[0].GetElementType() == ElementType.Class &&
+ method.MethodSig.Params[1].GetElementType() == ElementType.Class;
+ }
+
+ MethodDef FindArithmeticRemUn(TypeDef type) {
+ return FindArithmeticDivOrRemUn(type, Code.Rem_Un);
+ }
+
+ MethodDef FindArithmeticDivUn(TypeDef type) {
+ return FindArithmeticDivOrRemUn(type, Code.Div_Un);
+ }
+
+ MethodDef FindArithmeticDivOrRemUn(TypeDef type, Code code) {
+ foreach (var method in type.Methods) {
+ if (!CheckArithmeticUnMethodSig(method))
+ continue;
+ if (method.Body == null)
+ continue;
+ var instrs = method.Body.Instructions;
+ for (int i = 0; i < instrs.Count - 7; i++) {
+ var ldarg0 = instrs[i];
+ if (!ldarg0.IsLdarg() || ldarg0.GetParameterIndex() != 0)
+ continue;
+ if (!CheckCallvirt(instrs[i + 1], "System.Int32", "()"))
+ continue;
+ var ldarg1 = instrs[i + 2];
+ if (!ldarg1.IsLdarg() || ldarg1.GetParameterIndex() != 1)
+ continue;
+ if (!CheckCallvirt(instrs[i + 3], "System.Int32", "()"))
+ continue;
+ if (instrs[i + 4].OpCode.Code != code)
+ continue;
+ if (!CheckBox(instrs[i + 5], ElementType.U4))
+ continue;
+ if (!instrs[i + 6].IsStloc())
+ continue;
+
+ return method;
+ }
+ }
+
+ return null;
+ }
+
+ MethodDef FindArithmeticRem(TypeDef type) {
+ return FindArithmeticOther(type, Code.Rem);
+ }
+
+ MethodDef FindArithmeticDiv(TypeDef type) {
+ return FindArithmeticOther(type, Code.Div);
+ }
+
+ MethodDef FindArithmeticMul(TypeDef type) {
+ return FindArithmeticOther(type, Code.Mul);
+ }
+
+ MethodDef FindArithmeticMulOvf(TypeDef type) {
+ return FindArithmeticOther(type, Code.Mul_Ovf);
+ }
+
+ MethodDef FindArithmeticSub(TypeDef type) {
+ return FindArithmeticOther(type, Code.Sub);
+ }
+
+ MethodDef FindArithmeticSubOvf(TypeDef type) {
+ return FindArithmeticOther(type, Code.Sub_Ovf);
+ }
+
+ MethodDef FindArithmeticAdd(TypeDef type) {
+ return FindArithmeticOther(type, Code.Add);
+ }
+
+ MethodDef FindArithmeticAddOvf(TypeDef type) {
+ return FindArithmeticOther(type, Code.Add_Ovf);
+ }
+
+ MethodDef FindArithmeticOther(TypeDef type, Code code) {
+ foreach (var method in type.Methods) {
+ if (!CheckArithmeticOtherMethodSig(method))
+ continue;
+ if (method.Body == null)
+ continue;
+ var instrs = method.Body.Instructions;
+ for (int i = 0; i < instrs.Count - 6; i++) {
+ var ldarg0 = instrs[i];
+ if (!ldarg0.IsLdarg() || ldarg0.GetParameterIndex() != 0)
+ continue;
+ if (!CheckUnboxAny(instrs[i + 1], ElementType.I4))
+ continue;
+ var ldarg1 = instrs[i + 2];
+ if (!ldarg1.IsLdarg() || ldarg1.GetParameterIndex() != 1)
+ continue;
+ if (!CheckUnboxAny(instrs[i + 3], ElementType.I4))
+ continue;
+ if (instrs[i + 4].OpCode.Code != code)
+ continue;
+ if (!CheckBox(instrs[i + 5], ElementType.I4))
+ continue;
+
+ return method;
+ }
+ }
+
+ return null;
+ }
+
+ static bool CheckArithmeticOtherMethodSig(MethodDef method) {
+ return method != null &&
+ method.IsStatic &&
+ method.MethodSig.GetParamCount() == 2 &&
+ method.MethodSig.RetType.GetElementType() == ElementType.Object &&
+ method.MethodSig.Params[0].GetElementType() == ElementType.Object &&
+ method.MethodSig.Params[1].GetElementType() == ElementType.Object;
+ }
+
+ public bool FindUnaryOpsMethods() {
+ UnaryNot = FindUnaryOpMethod(Code.Not);
+ UnaryNeg = FindUnaryOpMethod(Code.Neg);
+ return UnaryNot != null && UnaryNeg != null;
+ }
+
+ MethodDef FindUnaryOpMethod(Code code) {
+ foreach (var type in module.Types) {
+ if (type.BaseType != VmHandlerBaseType)
+ continue;
+ if (type.Methods.Count != 4)
+ continue;
+ foreach (var method in type.Methods) {
+ if (!method.HasBody || !method.IsStatic)
+ continue;
+ if (!DotNetUtils.IsMethod(method, "System.Object", "(System.Object)"))
+ continue;
+ if (CountThrows(method) != 1)
+ continue;
+ var instrs = method.Body.Instructions;
+ for (int i = 0; i < instrs.Count - 4; i++) {
+ var ldarg = instrs[i];
+ if (!ldarg.IsLdarg() || ldarg.GetParameterIndex() != 0)
+ continue;
+ if (!CheckUnboxAny(instrs[i + 1], ElementType.I4))
+ continue;
+ if (instrs[i + 2].OpCode.Code != code)
+ continue;
+ if (!CheckBox(instrs[i + 3], ElementType.I4))
+ continue;
+ if (!instrs[i + 4].IsStloc())
+ continue;
+
+ return method;
+ }
+ }
+ }
+ return null;
+ }
+
+ static int CountThrows(MethodDef method) {
+ if (method == null || method.Body == null)
+ return 0;
+ int count = 0;
+ foreach (var instr in method.Body.Instructions) {
+ if (instr.OpCode.Code == Code.Throw)
+ count++;
+ }
+ return count;
+ }
+
+ public bool FindArgsLocals() {
+ var vmState = FindVmState();
+ if (vmState == null)
+ return false;
+
+ var ctor = vmState.FindMethod(".ctor");
+ return FindArgsLocals(ctor, 1, out ArgsGet, out ArgsSet) &&
+ FindArgsLocals(ctor, 2, out LocalsGet, out LocalsSet);
+ }
+
+ TypeDef FindVmState() {
+ if (VmHandlerBaseType == null)
+ return null;
+ foreach (var method in VmHandlerBaseType.Methods) {
+ if (method.IsStatic || !method.IsAbstract)
+ continue;
+ if (method.Parameters.Count != 2)
+ continue;
+ var arg1 = method.Parameters[1].Type.TryGetTypeDef();
+ if (arg1 == null)
+ continue;
+
+ return arg1;
+ }
+ return null;
+ }
+
+ static bool FindArgsLocals(MethodDef ctor, int arg, out MethodDef getter, out MethodDef setter) {
+ getter = null;
+ setter = null;
+ if (ctor == null || !ctor.HasBody)
+ return false;
+
+ setter = FindSetter(ctor, arg);
+ if (setter == null)
+ return false;
+
+ var propField = GetPropField(setter);
+ if (propField == null)
+ return false;
+
+ getter = FindGetter(ctor.DeclaringType, propField);
+ return getter != null;
+ }
+
+ static MethodDef FindSetter(MethodDef ctor, int arg) {
+ if (ctor == null || !ctor.HasBody)
+ return null;
+
+ var instrs = ctor.Body.Instructions;
+ for (int i = 0; i < instrs.Count - 1; i++) {
+ var ldarg = instrs[i];
+ if (!ldarg.IsLdarg() || ldarg.GetParameterIndex() != arg)
+ continue;
+ var call = instrs[i + 1];
+ if (call.OpCode.Code != Code.Call)
+ continue;
+ var method = call.Operand as MethodDef;
+ if (method == null)
+ continue;
+ if (method.DeclaringType != ctor.DeclaringType)
+ continue;
+
+ return method;
+ }
+
+ return null;
+ }
+
+ static FieldDef GetPropField(MethodDef method) {
+ if (method == null || !method.HasBody)
+ return null;
+
+ foreach (var instr in method.Body.Instructions) {
+ if (instr.OpCode.Code != Code.Stfld)
+ continue;
+ var field = instr.Operand as FieldDef;
+ if (field == null || field.DeclaringType != method.DeclaringType)
+ continue;
+
+ return field;
+ }
+
+ return null;
+ }
+
+ static MethodDef FindGetter(TypeDef type, FieldDef propField) {
+ foreach (var method in type.Methods) {
+ if (method.IsStatic || !method.HasBody)
+ continue;
+ foreach (var instr in method.Body.Instructions) {
+ if (instr.OpCode.Code != Code.Ldfld)
+ continue;
+ if (instr.Operand != propField)
+ continue;
+
+ return method;
+ }
+ }
+
+ return null;
+ }
+
+ static bool CheckCallvirt(Instruction instr, string returnType, string parameters) {
+ if (instr.OpCode.Code != Code.Callvirt)
+ return false;
+ return DotNetUtils.IsMethod(instr.Operand as IMethod, returnType, parameters);
+ }
+
+ bool CheckUnboxAny(Instruction instr, ElementType expectedType) {
+ if (instr == null || instr.OpCode.Code != Code.Unbox_Any)
+ return false;
+ var typeSig = module.CorLibTypes.GetCorLibTypeSig(instr.Operand as ITypeDefOrRef);
+ return typeSig.GetElementType() == expectedType;
+ }
+
+ bool CheckBox(Instruction instr, ElementType expectedType) {
+ if (instr == null || instr.OpCode.Code != Code.Box)
+ return false;
+ var typeSig = module.CorLibTypes.GetCorLibTypeSig(instr.Operand as ITypeDefOrRef);
+ return typeSig.GetElementType() == expectedType;
+ }
+
+ static int CountVirtual(TypeDef type) {
+ int count = 0;
+ foreach (var method in type.Methods) {
+ if (method.IsVirtual)
+ count++;
+ }
+ return count;
+ }
+ }
+}
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmResources.Designer.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmResources.Designer.cs
new file mode 100644
index 00000000..6153040b
--- /dev/null
+++ b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmResources.Designer.cs
@@ -0,0 +1,93 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.18052
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class CsvmResources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal CsvmResources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("de4dot.code.deobfuscators.Agile_NET.vm.v2.CsvmResources", typeof(CsvmResources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Byte[].
+ ///
+ internal static byte[] CSVM1_v2 {
+ get {
+ object obj = ResourceManager.GetObject("CSVM1_v2", resourceCulture);
+ return ((byte[])(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Byte[].
+ ///
+ internal static byte[] CSVM2_v2 {
+ get {
+ object obj = ResourceManager.GetObject("CSVM2_v2", resourceCulture);
+ return ((byte[])(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Byte[].
+ ///
+ internal static byte[] CSVM3_v2 {
+ get {
+ object obj = ResourceManager.GetObject("CSVM3_v2", resourceCulture);
+ return ((byte[])(obj));
+ }
+ }
+ }
+}
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmResources.resx b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmResources.resx
new file mode 100644
index 00000000..254aef83
--- /dev/null
+++ b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmResources.resx
@@ -0,0 +1,130 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+
+ CSVM1_v2.bin;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ CSVM2_v2.bin;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ CSVM3_v2.bin;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmToCilMethodConverter.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmToCilMethodConverter.cs
new file mode 100644
index 00000000..3cc2f2f6
--- /dev/null
+++ b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmToCilMethodConverter.cs
@@ -0,0 +1,64 @@
+/*
+ Copyright (C) 2011-2013 de4dot@gmail.com
+
+ This file is part of de4dot.
+
+ de4dot is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ de4dot is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with de4dot. If not, see .
+*/
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using dnlib.DotNet;
+using dnlib.DotNet.Emit;
+
+namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
+ class CsvmToCilMethodConverter : CsvmToCilMethodConverterBase {
+ VmOpCodeHandlerDetector opCodeDetector;
+
+ public CsvmToCilMethodConverter(IDeobfuscatorContext deobfuscatorContext, ModuleDefMD module, VmOpCodeHandlerDetector opCodeDetector)
+ : base(deobfuscatorContext, module) {
+ this.opCodeDetector = opCodeDetector;
+ }
+
+ protected override List ReadInstructions(MethodDef cilMethod, CsvmMethodData csvmMethod) {
+ var reader = new BinaryReader(new MemoryStream(csvmMethod.Instructions));
+ var instrs = new List();
+ var handlerInfoReader = new OpCodeHandlerInfoReader(module);
+
+ int numVmInstrs = reader.ReadInt32();
+ var vmInstrs = new ushort[numVmInstrs];
+ for (int i = 0; i < numVmInstrs; i++)
+ vmInstrs[i] = reader.ReadUInt16();
+
+ uint offset = 0;
+ for (int vmInstrIndex = 0; vmInstrIndex < numVmInstrs; vmInstrIndex++) {
+ var composite = opCodeDetector.Handlers[vmInstrs[vmInstrIndex]];
+ var handlerInfos = composite.OpCodeHandlerInfos;
+ if (handlerInfos.Count == 0)
+ handlerInfos = new List() { new OpCodeHandlerInfo(HandlerTypeCode.Nop, null) };
+ for (int hi = 0; hi < handlerInfos.Count; hi++) {
+ var instr = handlerInfoReader.Read(handlerInfos[hi].TypeCode, reader);
+ instr.Offset = offset;
+ offset += (uint)GetInstructionSize(instr);
+ SetCilToVmIndex(instr, vmInstrIndex);
+ if (hi == 0)
+ SetVmIndexToCil(instr, vmInstrIndex);
+ instrs.Add(instr);
+ }
+ }
+ return instrs;
+ }
+ }
+}
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/HandlerTypeCode.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v2/HandlerTypeCode.cs
new file mode 100644
index 00000000..d679c54d
--- /dev/null
+++ b/de4dot.code/deobfuscators/Agile_NET/vm/v2/HandlerTypeCode.cs
@@ -0,0 +1,102 @@
+/*
+ Copyright (C) 2011-2013 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 .
+*/
+
+namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
+ // These constants are hard coded. Don't change the values (i.e., only append if more are needed)
+ enum HandlerTypeCode {
+ Add,
+ Add_Ovf,
+ Add_Ovf_Un,
+ And,
+ Beq,
+ Bge,
+ Bge_Un,
+ Bgt,
+ Bgt_Un,
+ Ble,
+ Ble_Un,
+ Blt,
+ Blt_Un,
+ Bne_Un,
+ Box,
+ Br,
+ Brfalse,
+ Brtrue,
+ Call,
+ Callvirt,
+ Castclass,
+ Ceq,
+ Cgt,
+ Cgt_Un,
+ Clt,
+ Clt_Un,
+ Conv,
+ Div,
+ Div_Un,
+ Dup,
+ Endfinally,
+ Initobj,
+ Isinst,
+ Ldarg,
+ Ldarga,
+ Ldc,
+ Ldelem,
+ Ldelema,
+ Ldfld_Ldsfld,
+ Ldflda_Ldsflda,
+ Ldftn,
+ Ldlen,
+ Ldloc,
+ Ldloca,
+ Ldobj,
+ Ldstr,
+ Ldtoken,
+ Ldvirtftn,
+ Leave,
+ Mul,
+ Mul_Ovf,
+ Mul_Ovf_Un,
+ Neg,
+ Newarr,
+ Newobj,
+ Nop,
+ Not,
+ Or,
+ Pop,
+ Rem,
+ Rem_Un,
+ Ret,
+ Rethrow,
+ Shl,
+ Shr,
+ Shr_Un,
+ Starg,
+ Stelem,
+ Stfld_Stsfld,
+ Stloc,
+ Stobj,
+ Sub,
+ Sub_Ovf,
+ Sub_Ovf_Un,
+ Switch,
+ Throw,
+ Unbox_Any,
+ Xor,
+ }
+}
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/MethodFinder.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v2/MethodFinder.cs
new file mode 100644
index 00000000..ca206830
--- /dev/null
+++ b/de4dot.code/deobfuscators/Agile_NET/vm/v2/MethodFinder.cs
@@ -0,0 +1,109 @@
+/*
+ Copyright (C) 2011-2013 de4dot@gmail.com
+
+ This file is part of de4dot.
+
+ de4dot is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ de4dot is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with de4dot. If not, see .
+*/
+
+using System.Collections.Generic;
+
+namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
+ class MethodFinder {
+ readonly IList handlerInfos;
+ readonly PrimitiveHandlerMethod handlerMethod;
+
+ class SigState {
+ public readonly MethodSigInfo SigInfo;
+
+ public SigState(PrimitiveHandlerMethod handlerMethod) {
+ this.SigInfo = handlerMethod.Sig;
+ }
+ }
+
+ public MethodFinder(IList handlerInfos, PrimitiveHandlerMethod handlerMethod) {
+ this.handlerInfos = handlerInfos;
+ this.handlerMethod = handlerMethod;
+ }
+
+ public OpCodeHandler FindHandler() {
+ var handler = FindHandler(new SigState(handlerMethod));
+ if (handler == null)
+ return null;
+
+ return new OpCodeHandler(handler, handlerMethod.Method.DeclaringType, handlerMethod);
+ }
+
+ OpCodeHandlerInfo FindHandler(SigState execSigState) {
+ foreach (var handler in handlerInfos) {
+ if (Matches(handler.ExecSig, execSigState))
+ return handler;
+ }
+ return null;
+ }
+
+ struct MatchInfo {
+ public int HandlerIndex;
+ public int SigIndex;
+
+ public MatchInfo(int handlerIndex, int sigIndex) {
+ this.HandlerIndex = handlerIndex;
+ this.SigIndex = sigIndex;
+ }
+ }
+
+ Dictionary sigIndexToHandlerIndex = new Dictionary();
+ Dictionary handlerIndexToSigIndex = new Dictionary();
+ Stack stack = new Stack();
+ bool Matches(MethodSigInfo handlerSig, SigState sigState) {
+ stack.Clear();
+ sigIndexToHandlerIndex.Clear();
+ handlerIndexToSigIndex.Clear();
+ var handlerInfos = handlerSig.BlockInfos;
+ var sigInfos = sigState.SigInfo.BlockInfos;
+
+ stack.Push(new MatchInfo(0, 0));
+ while (stack.Count > 0) {
+ var info = stack.Pop();
+
+ int handlerIndex, sigIndex;
+ bool hasVisitedHandler = handlerIndexToSigIndex.TryGetValue(info.HandlerIndex, out sigIndex);
+ bool hasVisitedSig = sigIndexToHandlerIndex.TryGetValue(info.SigIndex, out handlerIndex);
+ if (hasVisitedHandler != hasVisitedSig)
+ return false;
+ if (hasVisitedHandler) {
+ if (handlerIndex != info.HandlerIndex || sigIndex != info.SigIndex)
+ return false;
+ continue;
+ }
+ handlerIndexToSigIndex[info.HandlerIndex] = info.SigIndex;
+ sigIndexToHandlerIndex[info.SigIndex] = info.HandlerIndex;
+
+ var handlerBlock = handlerInfos[info.HandlerIndex];
+ var sigBlock = sigInfos[info.SigIndex];
+
+ if (!handlerBlock.Equals(sigBlock))
+ return false;
+
+ for (int i = 0; i < handlerBlock.Targets.Count; i++) {
+ int handlerTargetIndex = handlerBlock.Targets[i];
+ int sigTargetIndex = sigBlock.Targets[i];
+ stack.Push(new MatchInfo(handlerTargetIndex, sigTargetIndex));
+ }
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/MethodSigInfoCreator.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v2/MethodSigInfoCreator.cs
new file mode 100644
index 00000000..c311e0a9
--- /dev/null
+++ b/de4dot.code/deobfuscators/Agile_NET/vm/v2/MethodSigInfoCreator.cs
@@ -0,0 +1,737 @@
+/*
+ Copyright (C) 2011-2013 de4dot@gmail.com
+
+ This file is part of de4dot.
+
+ de4dot is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ de4dot is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with de4dot. If not, see .
+*/
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Security.Cryptography;
+using dnlib.DotNet;
+using dnlib.DotNet.Emit;
+using dnlib.DotNet.MD;
+using de4dot.blocks;
+
+namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
+ class MethodSigInfo {
+ readonly List blockInfos;
+
+ public List BlockInfos {
+ get { return blockInfos; }
+ }
+
+ public MethodSigInfo() {
+ this.blockInfos = new List();
+ }
+
+ public MethodSigInfo(IEnumerable blockInfos) {
+ this.blockInfos = new List(blockInfos);
+ }
+ }
+
+ class BlockInfo : IEquatable {
+ readonly List targets;
+
+ public byte[] Hash { get; set; }
+ public List Targets {
+ get { return targets; }
+ }
+
+ public BlockInfo() {
+ this.targets = new List();
+ }
+
+ public BlockInfo(byte[] hash, IEnumerable targets) {
+ this.Hash = hash;
+ this.targets = new List(targets);
+ }
+
+ public override string ToString() {
+ if (Hash == null)
+ return "";
+ return BitConverter.ToString(Hash).Replace("-", string.Empty);
+ }
+
+ public bool Equals(BlockInfo other) {
+ return Equals(Hash, other.Hash) &&
+ Targets.Count == other.Targets.Count;
+ }
+
+ bool Equals(byte[] a, byte[] b) {
+ if (a == b)
+ return true;
+ if (a == null || b == null)
+ return false;
+ if (a.Length != b.Length)
+ return false;
+ for (int i = 0; i < a.Length; i++) {
+ if (a[i] != b[i])
+ return false;
+ }
+ return true;
+ }
+ }
+
+ class MethodSigInfoCreator {
+ MethodSigInfo methodSigInfo;
+ Blocks blocks;
+ IList allBlocks;
+ Dictionary blockToInfo;
+ Dictionary