Merge branch 'master' into confuser
This commit is contained in:
commit
08ca871406
|
@ -30,17 +30,17 @@ namespace AssemblyData {
|
||||||
List<string> assemblySearchPaths = new List<string>();
|
List<string> assemblySearchPaths = new List<string>();
|
||||||
|
|
||||||
public AssemblyResolver() {
|
public AssemblyResolver() {
|
||||||
AppDomain.CurrentDomain.AssemblyResolve += assemblyResolve;
|
AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolve;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addAssemblySearchPath(string path) {
|
void AddAssemblySearchPath(string path) {
|
||||||
if (assemblySearchPathsDict.ContainsKey(path))
|
if (assemblySearchPathsDict.ContainsKey(path))
|
||||||
return;
|
return;
|
||||||
assemblySearchPathsDict[path] = true;
|
assemblySearchPathsDict[path] = true;
|
||||||
assemblySearchPaths.Add(path);
|
assemblySearchPaths.Add(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Assembly get(string assemblyFullName) {
|
Assembly Get(string assemblyFullName) {
|
||||||
var asmName = new AssemblyName(assemblyFullName);
|
var asmName = new AssemblyName(assemblyFullName);
|
||||||
|
|
||||||
Assembly assembly;
|
Assembly assembly;
|
||||||
|
@ -53,8 +53,8 @@ namespace AssemblyData {
|
||||||
}
|
}
|
||||||
|
|
||||||
static string[] assemblyExtensions = new string[] { ".dll", ".exe" };
|
static string[] assemblyExtensions = new string[] { ".dll", ".exe" };
|
||||||
Assembly assemblyResolve(object sender, ResolveEventArgs args) {
|
Assembly AssemblyResolve(object sender, ResolveEventArgs args) {
|
||||||
var assembly = get(args.Name);
|
var assembly = Get(args.Name);
|
||||||
if (assembly != null)
|
if (assembly != null)
|
||||||
return assembly;
|
return assembly;
|
||||||
|
|
||||||
|
@ -65,8 +65,8 @@ namespace AssemblyData {
|
||||||
var filename = Path.Combine(path, asmName.Name + ext);
|
var filename = Path.Combine(path, asmName.Name + ext);
|
||||||
if (!new FileInfo(filename).Exists)
|
if (!new FileInfo(filename).Exists)
|
||||||
continue;
|
continue;
|
||||||
addConfigFile(filename + ".config");
|
AddConfigFile(filename + ".config");
|
||||||
return addAssembly(Assembly.LoadFile(filename));
|
return AddAssembly(Assembly.LoadFile(filename));
|
||||||
}
|
}
|
||||||
catch (IOException) {
|
catch (IOException) {
|
||||||
}
|
}
|
||||||
|
@ -86,12 +86,12 @@ namespace AssemblyData {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Assembly load(string filename) {
|
public Assembly Load(string filename) {
|
||||||
addConfigFile(filename + ".config");
|
AddConfigFile(filename + ".config");
|
||||||
return addAssembly(loadFile(filename));
|
return AddAssembly(LoadFile(filename));
|
||||||
}
|
}
|
||||||
|
|
||||||
Assembly loadFile(string filename) {
|
Assembly LoadFile(string filename) {
|
||||||
try {
|
try {
|
||||||
return Assembly.LoadFrom(filename);
|
return Assembly.LoadFrom(filename);
|
||||||
}
|
}
|
||||||
|
@ -101,16 +101,16 @@ namespace AssemblyData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Assembly addAssembly(Assembly assembly) {
|
Assembly AddAssembly(Assembly assembly) {
|
||||||
var asmName = assembly.GetName();
|
var asmName = assembly.GetName();
|
||||||
assemblies[asmName.FullName] = assembly;
|
assemblies[asmName.FullName] = assembly;
|
||||||
assemblies[asmName.Name] = assembly;
|
assemblies[asmName.Name] = assembly;
|
||||||
return assembly;
|
return assembly;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addConfigFile(string configFilename) {
|
void AddConfigFile(string configFilename) {
|
||||||
var dirName = Utils.getDirName(Utils.getFullPath(configFilename));
|
var dirName = Utils.GetDirName(Utils.GetFullPath(configFilename));
|
||||||
addAssemblySearchPath(dirName);
|
AddAssemblySearchPath(dirName);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
using (var xmlStream = new FileStream(configFilename, FileMode.Open, FileAccess.Read, FileShare.Read)) {
|
using (var xmlStream = new FileStream(configFilename, FileMode.Open, FileAccess.Read, FileShare.Read)) {
|
||||||
|
@ -124,7 +124,7 @@ namespace AssemblyData {
|
||||||
if (string.IsNullOrEmpty(privatePath))
|
if (string.IsNullOrEmpty(privatePath))
|
||||||
continue;
|
continue;
|
||||||
foreach (var path in privatePath.Split(';'))
|
foreach (var path in privatePath.Split(';'))
|
||||||
addAssemblySearchPath(Path.Combine(dirName, path));
|
AddAssemblySearchPath(Path.Combine(dirName, path));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,19 +26,19 @@ using AssemblyData;
|
||||||
|
|
||||||
namespace AssemblyServer {
|
namespace AssemblyServer {
|
||||||
public static class Start {
|
public static class Start {
|
||||||
public static int main(string[] args) {
|
public static int Main2(string[] args) {
|
||||||
if (args.Length != 2)
|
if (args.Length != 2)
|
||||||
Environment.Exit(1);
|
Environment.Exit(1);
|
||||||
var channelName = args[0];
|
var channelName = args[0];
|
||||||
var uri = args[1];
|
var uri = args[1];
|
||||||
|
|
||||||
var service = new AssemblyService();
|
var service = new AssemblyService();
|
||||||
startServer(service, channelName, uri);
|
StartServer(service, channelName, uri);
|
||||||
service.waitExit();
|
service.WaitExit();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void startServer(AssemblyService service, string name, string uri) {
|
static void StartServer(AssemblyService service, string name, string uri) {
|
||||||
var props = new Hashtable();
|
var props = new Hashtable();
|
||||||
props["portName"] = name;
|
props["portName"] = name;
|
||||||
var provider = new BinaryServerFormatterSinkProvider();
|
var provider = new BinaryServerFormatterSinkProvider();
|
||||||
|
|
|
@ -33,14 +33,14 @@ namespace AssemblyData {
|
||||||
AssemblyResolver assemblyResolver = new AssemblyResolver();
|
AssemblyResolver assemblyResolver = new AssemblyResolver();
|
||||||
bool installCompileMethodCalled = false;
|
bool installCompileMethodCalled = false;
|
||||||
|
|
||||||
public void doNothing() {
|
public void DoNothing() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void exit() {
|
public void Exit() {
|
||||||
exitEvent.Set();
|
exitEvent.Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void waitExit() {
|
public void WaitExit() {
|
||||||
exitEvent.WaitOne();
|
exitEvent.WaitOne();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,28 +48,28 @@ namespace AssemblyData {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkStringDecrypter() {
|
void CheckStringDecrypter() {
|
||||||
if (stringDecrypter == null)
|
if (stringDecrypter == null)
|
||||||
throw new ApplicationException("setStringDecrypterType() hasn't been called yet.");
|
throw new ApplicationException("setStringDecrypterType() hasn't been called yet.");
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkAssembly() {
|
void CheckAssembly() {
|
||||||
if (assembly == null)
|
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) {
|
public void LoadAssembly(string filename) {
|
||||||
if (assembly != null)
|
if (assembly != null)
|
||||||
throw new ApplicationException("Only one assembly can be explicitly loaded");
|
throw new ApplicationException("Only one assembly can be explicitly loaded");
|
||||||
try {
|
try {
|
||||||
assembly = assemblyResolver.load(filename);
|
assembly = assemblyResolver.Load(filename);
|
||||||
}
|
}
|
||||||
catch (BadImageFormatException) {
|
catch (BadImageFormatException) {
|
||||||
throw new ApplicationException(string.Format("Could not load assembly {0}. Maybe it's 32-bit or 64-bit only?", filename));
|
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) {
|
public void SetStringDecrypterType(StringDecrypterType type) {
|
||||||
if (stringDecrypter != null)
|
if (stringDecrypter != null)
|
||||||
throw new ApplicationException("StringDecrypterType already set");
|
throw new ApplicationException("StringDecrypterType already set");
|
||||||
|
|
||||||
|
@ -87,25 +87,25 @@ namespace AssemblyData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int defineStringDecrypter(int methodToken) {
|
public int DefineStringDecrypter(int methodToken) {
|
||||||
checkStringDecrypter();
|
CheckStringDecrypter();
|
||||||
var methodInfo = findMethod(methodToken);
|
var methodInfo = FindMethod(methodToken);
|
||||||
if (methodInfo == null)
|
if (methodInfo == null)
|
||||||
throw new ApplicationException(string.Format("Could not find method {0:X8}", methodToken));
|
throw new ApplicationException(string.Format("Could not find method {0:X8}", methodToken));
|
||||||
if (methodInfo.ReturnType != typeof(string) && methodInfo.ReturnType != typeof(object))
|
if (methodInfo.ReturnType != typeof(string) && methodInfo.ReturnType != typeof(object))
|
||||||
throw new ApplicationException(string.Format("Method return type must be string or object: {0}", methodInfo));
|
throw new ApplicationException(string.Format("Method return type must be string or object: {0}", methodInfo));
|
||||||
return stringDecrypter.defineStringDecrypter(methodInfo);
|
return stringDecrypter.DefineStringDecrypter(methodInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public object[] decryptStrings(int stringDecrypterMethod, object[] args, int callerToken) {
|
public object[] DecryptStrings(int stringDecrypterMethod, object[] args, int callerToken) {
|
||||||
checkStringDecrypter();
|
CheckStringDecrypter();
|
||||||
var caller = getCaller(callerToken);
|
var caller = GetCaller(callerToken);
|
||||||
foreach (var arg in args)
|
foreach (var arg in args)
|
||||||
SimpleData.unpack((object[])arg);
|
SimpleData.Unpack((object[])arg);
|
||||||
return SimpleData.pack(stringDecrypter.decryptStrings(stringDecrypterMethod, args, caller));
|
return SimpleData.Pack(stringDecrypter.DecryptStrings(stringDecrypterMethod, args, caller));
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodBase getCaller(int callerToken) {
|
MethodBase GetCaller(int callerToken) {
|
||||||
try {
|
try {
|
||||||
return assembly.GetModules()[0].ResolveMethod(callerToken);
|
return assembly.GetModules()[0].ResolveMethod(callerToken);
|
||||||
}
|
}
|
||||||
|
@ -114,8 +114,8 @@ namespace AssemblyData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodInfo findMethod(int methodToken) {
|
MethodInfo FindMethod(int methodToken) {
|
||||||
checkAssembly();
|
CheckAssembly();
|
||||||
|
|
||||||
foreach (var module in assembly.GetModules()) {
|
foreach (var module in assembly.GetModules()) {
|
||||||
var method = module.ResolveMethod(methodToken) as MethodInfo;
|
var method = module.ResolveMethod(methodToken) as MethodInfo;
|
||||||
|
@ -126,28 +126,28 @@ namespace AssemblyData {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void installCompileMethod(DecryptMethodsInfo decryptMethodsInfo) {
|
public void InstallCompileMethod(DecryptMethodsInfo decryptMethodsInfo) {
|
||||||
if (installCompileMethodCalled)
|
if (installCompileMethodCalled)
|
||||||
throw new ApplicationException("installCompileMethod() has already been called");
|
throw new ApplicationException("installCompileMethod() has already been called");
|
||||||
installCompileMethodCalled = true;
|
installCompileMethodCalled = true;
|
||||||
DynamicMethodsDecrypter.Instance.DecryptMethodsInfo = decryptMethodsInfo;
|
DynamicMethodsDecrypter.Instance.DecryptMethodsInfo = decryptMethodsInfo;
|
||||||
DynamicMethodsDecrypter.Instance.installCompileMethod();
|
DynamicMethodsDecrypter.Instance.InstallCompileMethod();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadObfuscator(string filename) {
|
public void LoadObfuscator(string filename) {
|
||||||
loadAssembly(filename);
|
LoadAssembly(filename);
|
||||||
DynamicMethodsDecrypter.Instance.Module = assembly.ManifestModule;
|
DynamicMethodsDecrypter.Instance.Module = assembly.ManifestModule;
|
||||||
DynamicMethodsDecrypter.Instance.loadObfuscator();
|
DynamicMethodsDecrypter.Instance.LoadObfuscator();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool canDecryptMethods() {
|
public bool CanDecryptMethods() {
|
||||||
checkAssembly();
|
CheckAssembly();
|
||||||
return DynamicMethodsDecrypter.Instance.canDecryptMethods();
|
return DynamicMethodsDecrypter.Instance.CanDecryptMethods();
|
||||||
}
|
}
|
||||||
|
|
||||||
public DumpedMethods decryptMethods() {
|
public DumpedMethods DecryptMethods() {
|
||||||
checkAssembly();
|
CheckAssembly();
|
||||||
return DynamicMethodsDecrypter.Instance.decryptMethods();
|
return DynamicMethodsDecrypter.Instance.DecryptMethods();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,12 +27,12 @@ namespace AssemblyData {
|
||||||
delegate string DecryptString(object[] args);
|
delegate string DecryptString(object[] args);
|
||||||
List<DecryptString> stringDecryptMethods = new List<DecryptString>();
|
List<DecryptString> stringDecryptMethods = new List<DecryptString>();
|
||||||
|
|
||||||
public int defineStringDecrypter(MethodInfo method) {
|
public int DefineStringDecrypter(MethodInfo method) {
|
||||||
stringDecryptMethods.Add(buildDynamicMethod(method));
|
stringDecryptMethods.Add(BuildDynamicMethod(method));
|
||||||
return stringDecryptMethods.Count - 1;
|
return stringDecryptMethods.Count - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public object[] decryptStrings(int stringDecrypterMethod, object[] args, MethodBase caller) {
|
public object[] DecryptStrings(int stringDecrypterMethod, object[] args, MethodBase caller) {
|
||||||
if (stringDecrypterMethod > stringDecryptMethods.Count)
|
if (stringDecrypterMethod > stringDecryptMethods.Count)
|
||||||
throw new ApplicationException("Invalid string decrypter method");
|
throw new ApplicationException("Invalid string decrypter method");
|
||||||
|
|
||||||
|
@ -43,9 +43,9 @@ namespace AssemblyData {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
DecryptString buildDynamicMethod(MethodInfo method) {
|
DecryptString BuildDynamicMethod(MethodInfo method) {
|
||||||
var dm = new DynamicMethod("", typeof(string), new Type[] { typeof(object[]) }, typeof(DelegateStringDecrypter), true);
|
var dm = new DynamicMethod("", typeof(string), new Type[] { typeof(object[]) }, typeof(DelegateStringDecrypter), true);
|
||||||
Utils.addCallStringDecrypterMethodInstructions(method, dm.GetILGenerator());
|
Utils.AddCallStringDecrypterMethodInstructions(method, dm.GetILGenerator());
|
||||||
return (DecryptString)dm.CreateDelegate(typeof(DecryptString));
|
return (DecryptString)dm.CreateDelegate(typeof(DecryptString));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,26 +36,26 @@ namespace AssemblyData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int defineStringDecrypter(MethodInfo method) {
|
public int DefineStringDecrypter(MethodInfo method) {
|
||||||
decryptInfos.Add(new DecryptInfo(method));
|
decryptInfos.Add(new DecryptInfo(method));
|
||||||
return decryptInfos.Count - 1;
|
return decryptInfos.Count - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public object[] decryptStrings(int stringDecrypterMethod, object[] args, MethodBase caller) {
|
public object[] DecryptStrings(int stringDecrypterMethod, object[] args, MethodBase caller) {
|
||||||
var decryptInfo = decryptInfos[stringDecrypterMethod];
|
var decryptInfo = decryptInfos[stringDecrypterMethod];
|
||||||
if (decryptInfo.decryptString == null)
|
if (decryptInfo.decryptString == null)
|
||||||
decryptInfo.decryptString = createDecryptString(decryptInfo.method);
|
decryptInfo.decryptString = CreateDecryptString(decryptInfo.method);
|
||||||
|
|
||||||
methodsRewriter.setCaller(decryptInfo.decryptString, caller);
|
methodsRewriter.SetCaller(decryptInfo.decryptString, caller);
|
||||||
var result = new object[args.Length];
|
var result = new object[args.Length];
|
||||||
for (int i = 0; i < args.Length; i++)
|
for (int i = 0; i < args.Length; i++)
|
||||||
result[i] = decryptInfo.decryptString((object[])args[i]);
|
result[i] = decryptInfo.decryptString((object[])args[i]);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
RewrittenMethod createDecryptString(MethodInfo method) {
|
RewrittenMethod CreateDecryptString(MethodInfo method) {
|
||||||
methodsRewriter.createMethod(method);
|
methodsRewriter.CreateMethod(method);
|
||||||
return methodsRewriter.createDelegate(method);
|
return methodsRewriter.CreateDelegate(method);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,18 +28,18 @@ namespace AssemblyData {
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IAssemblyService {
|
public interface IAssemblyService {
|
||||||
void doNothing();
|
void DoNothing();
|
||||||
void exit();
|
void Exit();
|
||||||
|
|
||||||
void loadAssembly(string filename);
|
void LoadAssembly(string filename);
|
||||||
|
|
||||||
void setStringDecrypterType(StringDecrypterType type);
|
void SetStringDecrypterType(StringDecrypterType type);
|
||||||
int defineStringDecrypter(int methodToken);
|
int DefineStringDecrypter(int methodToken);
|
||||||
object[] decryptStrings(int stringDecrypterMethod, object[] args, int callerToken);
|
object[] DecryptStrings(int stringDecrypterMethod, object[] args, int callerToken);
|
||||||
|
|
||||||
void installCompileMethod(DecryptMethodsInfo decryptMethodsInfo);
|
void InstallCompileMethod(DecryptMethodsInfo decryptMethodsInfo);
|
||||||
void loadObfuscator(string filename);
|
void LoadObfuscator(string filename);
|
||||||
bool canDecryptMethods();
|
bool CanDecryptMethods();
|
||||||
DumpedMethods decryptMethods();
|
DumpedMethods DecryptMethods();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ using System.Reflection;
|
||||||
|
|
||||||
namespace AssemblyData {
|
namespace AssemblyData {
|
||||||
interface IStringDecrypter {
|
interface IStringDecrypter {
|
||||||
int defineStringDecrypter(MethodInfo method);
|
int DefineStringDecrypter(MethodInfo method);
|
||||||
object[] decryptStrings(int stringDecrypterMethod, object[] args, MethodBase caller);
|
object[] DecryptStrings(int stringDecrypterMethod, object[] args, MethodBase caller);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
[assembly: AssemblyVersion("2.0.2.3405")]
|
[assembly: AssemblyVersion("2.0.3.3405")]
|
||||||
[assembly: AssemblyFileVersion("2.0.2.3405")]
|
[assembly: AssemblyFileVersion("2.0.3.3405")]
|
||||||
|
|
|
@ -51,7 +51,7 @@ namespace AssemblyData {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class SimpleData {
|
public static class SimpleData {
|
||||||
public static object[] pack(object[] args) {
|
public static object[] Pack(object[] args) {
|
||||||
for (int i = 0; i < args.Length; i++) {
|
for (int i = 0; i < args.Length; i++) {
|
||||||
var s = args[i] as string;
|
var s = args[i] as string;
|
||||||
if (s != null)
|
if (s != null)
|
||||||
|
@ -60,7 +60,7 @@ namespace AssemblyData {
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static object[] unpack(object[] args) {
|
public static object[] Unpack(object[] args) {
|
||||||
for (int i = 0; i < args.Length; i++) {
|
for (int i = 0; i < args.Length; i++) {
|
||||||
var s = args[i] as MyString;
|
var s = args[i] as MyString;
|
||||||
if (s != null)
|
if (s != null)
|
||||||
|
|
|
@ -68,11 +68,11 @@ namespace AssemblyData {
|
||||||
static class Utils {
|
static class Utils {
|
||||||
static Random random = new Random();
|
static Random random = new Random();
|
||||||
|
|
||||||
public static uint getRandomUint() {
|
public static uint GetRandomUint() {
|
||||||
return (uint)(random.NextDouble() * uint.MaxValue);
|
return (uint)(random.NextDouble() * uint.MaxValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Type getDelegateType(Type returnType, Type[] args) {
|
public static Type GetDelegateType(Type returnType, Type[] args) {
|
||||||
Type[] types;
|
Type[] types;
|
||||||
if (returnType == typeof(void)) {
|
if (returnType == typeof(void)) {
|
||||||
types = args;
|
types = args;
|
||||||
|
@ -133,7 +133,7 @@ namespace AssemblyData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string randomName(int min, int max) {
|
public static string RandomName(int min, int max) {
|
||||||
int numChars = random.Next(min, max + 1);
|
int numChars = random.Next(min, max + 1);
|
||||||
var sb = new StringBuilder(numChars);
|
var sb = new StringBuilder(numChars);
|
||||||
int numLower = 0;
|
int numLower = 0;
|
||||||
|
@ -153,7 +153,7 @@ namespace AssemblyData {
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void addCallStringDecrypterMethodInstructions(MethodInfo method, ILGenerator ilg) {
|
public static void AddCallStringDecrypterMethodInstructions(MethodInfo method, ILGenerator ilg) {
|
||||||
var args = method.GetParameters();
|
var args = method.GetParameters();
|
||||||
for (int i = 0; i < args.Length; i++) {
|
for (int i = 0; i < args.Length; i++) {
|
||||||
var arg = args[i].ParameterType;
|
var arg = args[i].ParameterType;
|
||||||
|
@ -171,7 +171,7 @@ namespace AssemblyData {
|
||||||
ilg.Emit(OpCodes.Ret);
|
ilg.Emit(OpCodes.Ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string getFullPath(string path) {
|
public static string GetFullPath(string path) {
|
||||||
try {
|
try {
|
||||||
return Path.GetFullPath(path);
|
return Path.GetFullPath(path);
|
||||||
}
|
}
|
||||||
|
@ -180,7 +180,7 @@ namespace AssemblyData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string getDirName(string name) {
|
public static string GetDirName(string name) {
|
||||||
return Path.GetDirectoryName(name);
|
return Path.GetDirectoryName(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,10 +35,10 @@ namespace AssemblyData.methodsrewriter {
|
||||||
|
|
||||||
public AssemblyResolver(string asmName) {
|
public AssemblyResolver(string asmName) {
|
||||||
assembly = Assembly.Load(new AssemblyName(asmName));
|
assembly = Assembly.Load(new AssemblyName(asmName));
|
||||||
initTypes();
|
InitTypes();
|
||||||
}
|
}
|
||||||
|
|
||||||
void initTypes() {
|
void InitTypes() {
|
||||||
foreach (var type in assembly.GetTypes()) {
|
foreach (var type in assembly.GetTypes()) {
|
||||||
string key = (type.Namespace ?? "") + "." + type.Name;
|
string key = (type.Namespace ?? "") + "." + type.Name;
|
||||||
List<TypeResolver> list;
|
List<TypeResolver> list;
|
||||||
|
@ -48,7 +48,7 @@ namespace AssemblyData.methodsrewriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeResolver getTypeResolver(ITypeDefOrRef typeRef) {
|
TypeResolver GetTypeResolver(ITypeDefOrRef typeRef) {
|
||||||
if (typeRef == null)
|
if (typeRef == null)
|
||||||
return null;
|
return null;
|
||||||
var scopeType = typeRef.ScopeType;
|
var scopeType = typeRef.ScopeType;
|
||||||
|
@ -65,30 +65,30 @@ namespace AssemblyData.methodsrewriter {
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var resolver in list) {
|
foreach (var resolver in list) {
|
||||||
if (ResolverUtils.compareTypes(resolver.type, scopeType))
|
if (ResolverUtils.CompareTypes(resolver.type, scopeType))
|
||||||
return resolver;
|
return resolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FieldInfo resolve(IField fieldRef) {
|
public FieldInfo Resolve(IField fieldRef) {
|
||||||
var resolver = getTypeResolver(fieldRef.DeclaringType);
|
var resolver = GetTypeResolver(fieldRef.DeclaringType);
|
||||||
if (resolver != null)
|
if (resolver != null)
|
||||||
return resolver.resolve(fieldRef);
|
return resolver.Resolve(fieldRef);
|
||||||
return resolveGlobalField(fieldRef);
|
return ResolveGlobalField(fieldRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
FieldInfo resolveGlobalField(IField fieldRef) {
|
FieldInfo ResolveGlobalField(IField fieldRef) {
|
||||||
initGlobalFields();
|
InitGlobalFields();
|
||||||
foreach (var globalField in globalFields) {
|
foreach (var globalField in globalFields) {
|
||||||
if (ResolverUtils.compareFields(globalField, fieldRef))
|
if (ResolverUtils.CompareFields(globalField, fieldRef))
|
||||||
return globalField;
|
return globalField;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initGlobalFields() {
|
void InitGlobalFields() {
|
||||||
if (globalFields != null)
|
if (globalFields != null)
|
||||||
return;
|
return;
|
||||||
globalFields = new List<FieldInfo>();
|
globalFields = new List<FieldInfo>();
|
||||||
|
@ -100,23 +100,23 @@ namespace AssemblyData.methodsrewriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodBase resolve(IMethod methodRef) {
|
public MethodBase Resolve(IMethod methodRef) {
|
||||||
var resolver = getTypeResolver(methodRef.DeclaringType);
|
var resolver = GetTypeResolver(methodRef.DeclaringType);
|
||||||
if (resolver != null)
|
if (resolver != null)
|
||||||
return resolver.resolve(methodRef);
|
return resolver.Resolve(methodRef);
|
||||||
return resolveGlobalMethod(methodRef);
|
return ResolveGlobalMethod(methodRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodBase resolveGlobalMethod(IMethod methodRef) {
|
MethodBase ResolveGlobalMethod(IMethod methodRef) {
|
||||||
initGlobalMethods();
|
InitGlobalMethods();
|
||||||
foreach (var globalMethod in globalMethods) {
|
foreach (var globalMethod in globalMethods) {
|
||||||
if (ResolverUtils.compareMethods(globalMethod, methodRef))
|
if (ResolverUtils.CompareMethods(globalMethod, methodRef))
|
||||||
return globalMethod;
|
return globalMethod;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initGlobalMethods() {
|
void InitGlobalMethods() {
|
||||||
if (globalMethods != null)
|
if (globalMethods != null)
|
||||||
return;
|
return;
|
||||||
globalMethods = new List<MethodBase>();
|
globalMethods = new List<MethodBase>();
|
||||||
|
@ -128,8 +128,8 @@ namespace AssemblyData.methodsrewriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type resolve(ITypeDefOrRef typeRef) {
|
public Type Resolve(ITypeDefOrRef typeRef) {
|
||||||
var resolver = getTypeResolver(typeRef);
|
var resolver = GetTypeResolver(typeRef);
|
||||||
if (resolver != null)
|
if (resolver != null)
|
||||||
return resolver.type;
|
return resolver.type;
|
||||||
|
|
||||||
|
|
|
@ -81,14 +81,14 @@ namespace AssemblyData.methodsrewriter {
|
||||||
this.methodName = methodName;
|
this.methodName = methodName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMethodInfo(MMethod methodInfo) {
|
public void SetMethodInfo(MMethod methodInfo) {
|
||||||
this.methodInfo = methodInfo;
|
this.methodInfo = methodInfo;
|
||||||
methodReturnType = ResolverUtils.getReturnType(methodInfo.methodBase);
|
methodReturnType = ResolverUtils.GetReturnType(methodInfo.methodBase);
|
||||||
methodParameters = getMethodParameterTypes(methodInfo.methodBase);
|
methodParameters = GetMethodParameterTypes(methodInfo.methodBase);
|
||||||
delegateType = Utils.getDelegateType(methodReturnType, methodParameters);
|
delegateType = Utils.GetDelegateType(methodReturnType, methodParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Delegate generate(IList<Instruction> allInstructions, IList<ExceptionHandler> allExceptionHandlers) {
|
public Delegate Generate(IList<Instruction> allInstructions, IList<ExceptionHandler> allExceptionHandlers) {
|
||||||
this.allInstructions = allInstructions;
|
this.allInstructions = allInstructions;
|
||||||
this.allExceptionHandlers = allExceptionHandlers;
|
this.allExceptionHandlers = allExceptionHandlers;
|
||||||
|
|
||||||
|
@ -96,37 +96,37 @@ namespace AssemblyData.methodsrewriter {
|
||||||
var lastInstr = allInstructions[allInstructions.Count - 1];
|
var lastInstr = allInstructions[allInstructions.Count - 1];
|
||||||
ilg = dm.GetILGenerator((int)lastInstr.Offset + lastInstr.GetSize());
|
ilg = dm.GetILGenerator((int)lastInstr.Offset + lastInstr.GetSize());
|
||||||
|
|
||||||
initInstrToIndex();
|
InitInstrToIndex();
|
||||||
initLocals();
|
InitLocals();
|
||||||
initLabels();
|
InitLabels();
|
||||||
|
|
||||||
exceptionHandlersStack = new Stack<ExceptionHandler>();
|
exceptionHandlersStack = new Stack<ExceptionHandler>();
|
||||||
for (int i = 0; i < allInstructions.Count; i++) {
|
for (int i = 0; i < allInstructions.Count; i++) {
|
||||||
updateExceptionHandlers(i);
|
UpdateExceptionHandlers(i);
|
||||||
var instr = allInstructions[i];
|
var instr = allInstructions[i];
|
||||||
ilg.MarkLabel(labels[i]);
|
ilg.MarkLabel(labels[i]);
|
||||||
if (instr.Operand is Operand)
|
if (instr.Operand is Operand)
|
||||||
writeSpecialInstr(instr, (Operand)instr.Operand);
|
WriteSpecialInstr(instr, (Operand)instr.Operand);
|
||||||
else
|
else
|
||||||
writeInstr(instr);
|
WriteInstr(instr);
|
||||||
}
|
}
|
||||||
updateExceptionHandlers(-1);
|
UpdateExceptionHandlers(-1);
|
||||||
|
|
||||||
return dm.CreateDelegate(delegateType);
|
return dm.CreateDelegate(delegateType);
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction getExceptionInstruction(int instructionIndex) {
|
Instruction GetExceptionInstruction(int instructionIndex) {
|
||||||
return instructionIndex < 0 ? null : allInstructions[instructionIndex];
|
return instructionIndex < 0 ? null : allInstructions[instructionIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateExceptionHandlers(int instructionIndex) {
|
void UpdateExceptionHandlers(int instructionIndex) {
|
||||||
var instr = getExceptionInstruction(instructionIndex);
|
var instr = GetExceptionInstruction(instructionIndex);
|
||||||
updateExceptionHandlers(instr);
|
UpdateExceptionHandlers(instr);
|
||||||
if (addTryStart(instr))
|
if (AddTryStart(instr))
|
||||||
updateExceptionHandlers(instr);
|
UpdateExceptionHandlers(instr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateExceptionHandlers(Instruction instr) {
|
void UpdateExceptionHandlers(Instruction instr) {
|
||||||
while (exceptionHandlersStack.Count > 0) {
|
while (exceptionHandlersStack.Count > 0) {
|
||||||
var ex = exceptionHandlersStack.Peek();
|
var ex = exceptionHandlersStack.Peek();
|
||||||
if (ex.TryEnd == instr) {
|
if (ex.TryEnd == instr) {
|
||||||
|
@ -137,11 +137,11 @@ namespace AssemblyData.methodsrewriter {
|
||||||
if (ex.HandlerType == ExceptionHandlerType.Finally)
|
if (ex.HandlerType == ExceptionHandlerType.Finally)
|
||||||
ilg.BeginFinallyBlock();
|
ilg.BeginFinallyBlock();
|
||||||
else
|
else
|
||||||
ilg.BeginCatchBlock(Resolver.getRtType(ex.CatchType));
|
ilg.BeginCatchBlock(Resolver.GetRtType(ex.CatchType));
|
||||||
}
|
}
|
||||||
if (ex.HandlerEnd == instr) {
|
if (ex.HandlerEnd == instr) {
|
||||||
exceptionHandlersStack.Pop();
|
exceptionHandlersStack.Pop();
|
||||||
if (exceptionHandlersStack.Count == 0 || !isSameTryBlock(ex, exceptionHandlersStack.Peek()))
|
if (exceptionHandlersStack.Count == 0 || !IsSameTryBlock(ex, exceptionHandlersStack.Peek()))
|
||||||
ilg.EndExceptionBlock();
|
ilg.EndExceptionBlock();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -149,7 +149,7 @@ namespace AssemblyData.methodsrewriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool addTryStart(Instruction instr) {
|
bool AddTryStart(Instruction instr) {
|
||||||
var list = new List<ExceptionHandler>();
|
var list = new List<ExceptionHandler>();
|
||||||
foreach (var ex in allExceptionHandlers) {
|
foreach (var ex in allExceptionHandlers) {
|
||||||
if (ex.TryStart == instr)
|
if (ex.TryStart == instr)
|
||||||
|
@ -158,7 +158,7 @@ namespace AssemblyData.methodsrewriter {
|
||||||
list.Reverse();
|
list.Reverse();
|
||||||
|
|
||||||
foreach (var ex in list) {
|
foreach (var ex in list) {
|
||||||
if (exceptionHandlersStack.Count == 0 || !isSameTryBlock(ex, exceptionHandlersStack.Peek()))
|
if (exceptionHandlersStack.Count == 0 || !IsSameTryBlock(ex, exceptionHandlersStack.Peek()))
|
||||||
ilg.BeginExceptionBlock();
|
ilg.BeginExceptionBlock();
|
||||||
exceptionHandlersStack.Push(ex);
|
exceptionHandlersStack.Push(ex);
|
||||||
}
|
}
|
||||||
|
@ -166,33 +166,33 @@ namespace AssemblyData.methodsrewriter {
|
||||||
return list.Count > 0;
|
return list.Count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isSameTryBlock(ExceptionHandler ex1, ExceptionHandler ex2) {
|
static bool IsSameTryBlock(ExceptionHandler ex1, ExceptionHandler ex2) {
|
||||||
return ex1.TryStart == ex2.TryStart && ex1.TryEnd == ex2.TryEnd;
|
return ex1.TryStart == ex2.TryStart && ex1.TryEnd == ex2.TryEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initInstrToIndex() {
|
void InitInstrToIndex() {
|
||||||
instrToIndex = new Dictionary<Instruction, int>(allInstructions.Count);
|
instrToIndex = new Dictionary<Instruction, int>(allInstructions.Count);
|
||||||
for (int i = 0; i < allInstructions.Count; i++)
|
for (int i = 0; i < allInstructions.Count; i++)
|
||||||
instrToIndex[allInstructions[i]] = i;
|
instrToIndex[allInstructions[i]] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initLocals() {
|
void InitLocals() {
|
||||||
locals = new List<LocalBuilder>();
|
locals = new List<LocalBuilder>();
|
||||||
foreach (var local in methodInfo.methodDef.Body.Variables)
|
foreach (var local in methodInfo.methodDef.Body.Variables)
|
||||||
locals.Add(ilg.DeclareLocal(Resolver.getRtType(local.Type), local.Type.RemoveModifiers().IsPinned));
|
locals.Add(ilg.DeclareLocal(Resolver.GetRtType(local.Type), local.Type.RemoveModifiers().IsPinned));
|
||||||
tempObjLocal = ilg.DeclareLocal(typeof(object));
|
tempObjLocal = ilg.DeclareLocal(typeof(object));
|
||||||
tempObjArrayLocal = ilg.DeclareLocal(typeof(object[]));
|
tempObjArrayLocal = ilg.DeclareLocal(typeof(object[]));
|
||||||
}
|
}
|
||||||
|
|
||||||
void initLabels() {
|
void InitLabels() {
|
||||||
labels = new List<Label>(allInstructions.Count);
|
labels = new List<Label>(allInstructions.Count);
|
||||||
for (int i = 0; i < allInstructions.Count; i++)
|
for (int i = 0; i < allInstructions.Count; i++)
|
||||||
labels.Add(ilg.DefineLabel());
|
labels.Add(ilg.DefineLabel());
|
||||||
}
|
}
|
||||||
|
|
||||||
Type[] getMethodParameterTypes(MethodBase method) {
|
Type[] GetMethodParameterTypes(MethodBase method) {
|
||||||
var list = new List<Type>();
|
var list = new List<Type>();
|
||||||
if (ResolverUtils.hasThis(method))
|
if (ResolverUtils.HasThis(method))
|
||||||
list.Add(method.DeclaringType);
|
list.Add(method.DeclaringType);
|
||||||
|
|
||||||
foreach (var param in method.GetParameters())
|
foreach (var param in method.GetParameters())
|
||||||
|
@ -204,19 +204,19 @@ namespace AssemblyData.methodsrewriter {
|
||||||
return list.ToArray();
|
return list.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeSpecialInstr(Instruction instr, Operand operand) {
|
void WriteSpecialInstr(Instruction instr, Operand operand) {
|
||||||
BindingFlags flags;
|
BindingFlags flags;
|
||||||
switch (operand.type) {
|
switch (operand.type) {
|
||||||
case Operand.Type.ThisArg:
|
case Operand.Type.ThisArg:
|
||||||
ilg.Emit(convertOpCode(instr.OpCode), (short)thisArgIndex);
|
ilg.Emit(ConvertOpCode(instr.OpCode), (short)thisArgIndex);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Operand.Type.TempObj:
|
case Operand.Type.TempObj:
|
||||||
ilg.Emit(convertOpCode(instr.OpCode), tempObjLocal);
|
ilg.Emit(ConvertOpCode(instr.OpCode), tempObjLocal);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Operand.Type.TempObjArray:
|
case Operand.Type.TempObjArray:
|
||||||
ilg.Emit(convertOpCode(instr.OpCode), tempObjArrayLocal);
|
ilg.Emit(ConvertOpCode(instr.OpCode), tempObjArrayLocal);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Operand.Type.OurMethod:
|
case Operand.Type.OurMethod:
|
||||||
|
@ -225,19 +225,19 @@ namespace AssemblyData.methodsrewriter {
|
||||||
var ourMethod = methodsRewriter.GetType().GetMethod(methodName, flags);
|
var ourMethod = methodsRewriter.GetType().GetMethod(methodName, flags);
|
||||||
if (ourMethod == null)
|
if (ourMethod == null)
|
||||||
throw new ApplicationException(string.Format("Could not find method {0}", methodName));
|
throw new ApplicationException(string.Format("Could not find method {0}", methodName));
|
||||||
ilg.Emit(convertOpCode(instr.OpCode), ourMethod);
|
ilg.Emit(ConvertOpCode(instr.OpCode), ourMethod);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Operand.Type.NewMethod:
|
case Operand.Type.NewMethod:
|
||||||
var methodBase = (MethodBase)operand.data;
|
var methodBase = (MethodBase)operand.data;
|
||||||
var delegateType = methodsRewriter.getDelegateType(methodBase);
|
var delegateType = methodsRewriter.GetDelegateType(methodBase);
|
||||||
flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance;
|
flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance;
|
||||||
var invokeMethod = delegateType.GetMethod("Invoke", flags);
|
var invokeMethod = delegateType.GetMethod("Invoke", flags);
|
||||||
ilg.Emit(convertOpCode(instr.OpCode), invokeMethod);
|
ilg.Emit(ConvertOpCode(instr.OpCode), invokeMethod);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Operand.Type.ReflectionType:
|
case Operand.Type.ReflectionType:
|
||||||
ilg.Emit(convertOpCode(instr.OpCode), (Type)operand.data);
|
ilg.Emit(ConvertOpCode(instr.OpCode), (Type)operand.data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -245,19 +245,19 @@ namespace AssemblyData.methodsrewriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Label getLabel(Instruction target) {
|
Label GetLabel(Instruction target) {
|
||||||
return labels[instrToIndex[target]];
|
return labels[instrToIndex[target]];
|
||||||
}
|
}
|
||||||
|
|
||||||
Label[] getLabels(Instruction[] targets) {
|
Label[] GetLabels(Instruction[] targets) {
|
||||||
var labels = new Label[targets.Length];
|
var labels = new Label[targets.Length];
|
||||||
for (int i = 0; i < labels.Length; i++)
|
for (int i = 0; i < labels.Length; i++)
|
||||||
labels[i] = getLabel(targets[i]);
|
labels[i] = GetLabel(targets[i]);
|
||||||
return labels;
|
return labels;
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeInstr(Instruction instr) {
|
void WriteInstr(Instruction instr) {
|
||||||
var opcode = convertOpCode(instr.OpCode);
|
var opcode = ConvertOpCode(instr.OpCode);
|
||||||
switch (instr.OpCode.OperandType) {
|
switch (instr.OpCode.OperandType) {
|
||||||
case OperandType.InlineNone:
|
case OperandType.InlineNone:
|
||||||
ilg.Emit(opcode);
|
ilg.Emit(opcode);
|
||||||
|
@ -265,11 +265,11 @@ namespace AssemblyData.methodsrewriter {
|
||||||
|
|
||||||
case OperandType.InlineBrTarget:
|
case OperandType.InlineBrTarget:
|
||||||
case OperandType.ShortInlineBrTarget:
|
case OperandType.ShortInlineBrTarget:
|
||||||
ilg.Emit(opcode, getLabel((Instruction)instr.Operand));
|
ilg.Emit(opcode, GetLabel((Instruction)instr.Operand));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OperandType.InlineSwitch:
|
case OperandType.InlineSwitch:
|
||||||
ilg.Emit(opcode, getLabels((Instruction[])instr.Operand));
|
ilg.Emit(opcode, GetLabels((Instruction[])instr.Operand));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OperandType.ShortInlineI:
|
case OperandType.ShortInlineI:
|
||||||
|
@ -303,7 +303,7 @@ namespace AssemblyData.methodsrewriter {
|
||||||
case OperandType.InlineType:
|
case OperandType.InlineType:
|
||||||
case OperandType.InlineMethod:
|
case OperandType.InlineMethod:
|
||||||
case OperandType.InlineField:
|
case OperandType.InlineField:
|
||||||
var obj = Resolver.getRtObject((ITokenOperand)instr.Operand);
|
var obj = Resolver.GetRtObject((ITokenOperand)instr.Operand);
|
||||||
if (obj is ConstructorInfo)
|
if (obj is ConstructorInfo)
|
||||||
ilg.Emit(opcode, (ConstructorInfo)obj);
|
ilg.Emit(opcode, (ConstructorInfo)obj);
|
||||||
else if (obj is MethodInfo)
|
else if (obj is MethodInfo)
|
||||||
|
@ -330,7 +330,7 @@ namespace AssemblyData.methodsrewriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ROpCode convertOpCode(OpCode opcode) {
|
ROpCode ConvertOpCode(OpCode opcode) {
|
||||||
ROpCode ropcode;
|
ROpCode ropcode;
|
||||||
if (dnlibToReflection.TryGetValue(opcode, out ropcode))
|
if (dnlibToReflection.TryGetValue(opcode, out ropcode))
|
||||||
return ropcode;
|
return ropcode;
|
||||||
|
|
|
@ -22,6 +22,6 @@ using System.Reflection;
|
||||||
|
|
||||||
namespace AssemblyData.methodsrewriter {
|
namespace AssemblyData.methodsrewriter {
|
||||||
interface IMethodsRewriter {
|
interface IMethodsRewriter {
|
||||||
Type getDelegateType(MethodBase methodBase);
|
Type GetDelegateType(MethodBase methodBase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ namespace AssemblyData.methodsrewriter {
|
||||||
this.methodDef = methodDef;
|
this.methodDef = methodDef;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool hasInstructions() {
|
public bool HasInstructions() {
|
||||||
return methodDef.Body != null && methodDef.Body.Instructions.Count != 0;
|
return methodDef.Body != null && methodDef.Body.Instructions.Count != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,10 +36,10 @@ namespace AssemblyData.methodsrewriter {
|
||||||
public MModule(Module module, ModuleDefMD moduleDef) {
|
public MModule(Module module, ModuleDefMD moduleDef) {
|
||||||
this.module = module;
|
this.module = module;
|
||||||
this.moduleDef = moduleDef;
|
this.moduleDef = moduleDef;
|
||||||
initTokenToType();
|
InitTokenToType();
|
||||||
}
|
}
|
||||||
|
|
||||||
void initTokenToType() {
|
void InitTokenToType() {
|
||||||
moduleType = moduleDef.Types[0];
|
moduleType = moduleDef.Types[0];
|
||||||
foreach (var typeDef in moduleDef.GetTypes()) {
|
foreach (var typeDef in moduleDef.GetTypes()) {
|
||||||
int token = (int)typeDef.MDToken.Raw;
|
int token = (int)typeDef.MDToken.Raw;
|
||||||
|
@ -49,27 +49,27 @@ namespace AssemblyData.methodsrewriter {
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
tokenToType[token] = null;
|
tokenToType[token] = null;
|
||||||
typeRefToType.add(typeDef, null);
|
typeRefToType.Add(typeDef, null);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
var mtype = new MType(type, typeDef);
|
var mtype = new MType(type, typeDef);
|
||||||
tokenToType[token] = mtype;
|
tokenToType[token] = mtype;
|
||||||
typeRefToType.add(typeDef, mtype);
|
typeRefToType.Add(typeDef, mtype);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public MType getType(IType typeRef) {
|
public MType GetType(IType typeRef) {
|
||||||
return typeRefToType.find(typeRef);
|
return typeRefToType.Find(typeRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MMethod getMethod(IMethod methodRef) {
|
public MMethod GetMethod(IMethod methodRef) {
|
||||||
var type = getType(methodRef.DeclaringType);
|
var type = GetType(methodRef.DeclaringType);
|
||||||
if (type != null)
|
if (type != null)
|
||||||
return type.getMethod(methodRef);
|
return type.GetMethod(methodRef);
|
||||||
if (!new SigComparer().Equals(moduleType, methodRef.DeclaringType))
|
if (!new SigComparer().Equals(moduleType, methodRef.DeclaringType))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
initGlobalMethods();
|
InitGlobalMethods();
|
||||||
foreach (var method in tokenToGlobalMethod.Values) {
|
foreach (var method in tokenToGlobalMethod.Values) {
|
||||||
if (new SigComparer().Equals(methodRef, method.methodDef))
|
if (new SigComparer().Equals(methodRef, method.methodDef))
|
||||||
return method;
|
return method;
|
||||||
|
@ -78,14 +78,14 @@ namespace AssemblyData.methodsrewriter {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MField getField(IField fieldRef) {
|
public MField GetField(IField fieldRef) {
|
||||||
var type = getType(fieldRef.DeclaringType);
|
var type = GetType(fieldRef.DeclaringType);
|
||||||
if (type != null)
|
if (type != null)
|
||||||
return type.getField(fieldRef);
|
return type.GetField(fieldRef);
|
||||||
if (!new SigComparer().Equals(moduleType, fieldRef.DeclaringType))
|
if (!new SigComparer().Equals(moduleType, fieldRef.DeclaringType))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
initGlobalFields();
|
InitGlobalFields();
|
||||||
foreach (var field in tokenToGlobalField.Values) {
|
foreach (var field in tokenToGlobalField.Values) {
|
||||||
if (new SigComparer().Equals(fieldRef, field.fieldDef))
|
if (new SigComparer().Equals(fieldRef, field.fieldDef))
|
||||||
return field;
|
return field;
|
||||||
|
@ -94,21 +94,21 @@ namespace AssemblyData.methodsrewriter {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MMethod getMethod(MethodBase method) {
|
public MMethod GetMethod(MethodBase method) {
|
||||||
if (method.Module != module)
|
if (method.Module != module)
|
||||||
throw new ApplicationException("Not our module");
|
throw new ApplicationException("Not our module");
|
||||||
if (method.DeclaringType == null)
|
if (method.DeclaringType == null)
|
||||||
return getGlobalMethod(method);
|
return GetGlobalMethod(method);
|
||||||
var type = tokenToType[method.DeclaringType.MetadataToken];
|
var type = tokenToType[method.DeclaringType.MetadataToken];
|
||||||
return type.getMethod(method.MetadataToken);
|
return type.GetMethod(method.MetadataToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MMethod getGlobalMethod(MethodBase method) {
|
public MMethod GetGlobalMethod(MethodBase method) {
|
||||||
initGlobalMethods();
|
InitGlobalMethods();
|
||||||
return tokenToGlobalMethod[method.MetadataToken];
|
return tokenToGlobalMethod[method.MetadataToken];
|
||||||
}
|
}
|
||||||
|
|
||||||
void initGlobalMethods() {
|
void InitGlobalMethods() {
|
||||||
if (tokenToGlobalMethod != null)
|
if (tokenToGlobalMethod != null)
|
||||||
return;
|
return;
|
||||||
tokenToGlobalMethod = new Dictionary<int, MMethod>();
|
tokenToGlobalMethod = new Dictionary<int, MMethod>();
|
||||||
|
@ -125,7 +125,7 @@ namespace AssemblyData.methodsrewriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void initGlobalFields() {
|
void InitGlobalFields() {
|
||||||
if (tokenToGlobalField != null)
|
if (tokenToGlobalField != null)
|
||||||
return;
|
return;
|
||||||
tokenToGlobalField = new Dictionary<int, MField>();
|
tokenToGlobalField = new Dictionary<int, MField>();
|
||||||
|
|
|
@ -37,27 +37,27 @@ namespace AssemblyData.methodsrewriter {
|
||||||
this.typeDef = typeDef;
|
this.typeDef = typeDef;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MMethod getMethod(IMethod methodRef) {
|
public MMethod GetMethod(IMethod methodRef) {
|
||||||
initMethods();
|
InitMethods();
|
||||||
return methodRefToMethod.find(methodRef);
|
return methodRefToMethod.Find(methodRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MField getField(IField fieldRef) {
|
public MField GetField(IField fieldRef) {
|
||||||
initFields();
|
InitFields();
|
||||||
return fieldRefToField.find(fieldRef);
|
return fieldRefToField.Find(fieldRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MMethod getMethod(int token) {
|
public MMethod GetMethod(int token) {
|
||||||
initMethods();
|
InitMethods();
|
||||||
return tokenToMethod[token];
|
return tokenToMethod[token];
|
||||||
}
|
}
|
||||||
|
|
||||||
public MField getField(int token) {
|
public MField GetField(int token) {
|
||||||
initFields();
|
InitFields();
|
||||||
return tokenToField[token];
|
return tokenToField[token];
|
||||||
}
|
}
|
||||||
|
|
||||||
void initMethods() {
|
void InitMethods() {
|
||||||
if (tokenToMethod != null)
|
if (tokenToMethod != null)
|
||||||
return;
|
return;
|
||||||
tokenToMethod = new Dictionary<int, MMethod>(typeDef.Methods.Count);
|
tokenToMethod = new Dictionary<int, MMethod>(typeDef.Methods.Count);
|
||||||
|
@ -65,17 +65,17 @@ namespace AssemblyData.methodsrewriter {
|
||||||
|
|
||||||
var tmpTokenToMethod = new Dictionary<int, MethodBase>();
|
var tmpTokenToMethod = new Dictionary<int, MethodBase>();
|
||||||
var flags = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
|
var flags = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
|
||||||
foreach (var m in ResolverUtils.getMethodBases(type, flags))
|
foreach (var m in ResolverUtils.GetMethodBases(type, flags))
|
||||||
tmpTokenToMethod[m.MetadataToken] = m;
|
tmpTokenToMethod[m.MetadataToken] = m;
|
||||||
foreach (var m in typeDef.Methods) {
|
foreach (var m in typeDef.Methods) {
|
||||||
var token = (int)m.MDToken.Raw;
|
var token = (int)m.MDToken.Raw;
|
||||||
var method = new MMethod(tmpTokenToMethod[token], m);
|
var method = new MMethod(tmpTokenToMethod[token], m);
|
||||||
tokenToMethod[token] = method;
|
tokenToMethod[token] = method;
|
||||||
methodRefToMethod.add(method.methodDef, method);
|
methodRefToMethod.Add(method.methodDef, method);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void initFields() {
|
void InitFields() {
|
||||||
if (tokenToField != null)
|
if (tokenToField != null)
|
||||||
return;
|
return;
|
||||||
tokenToField = new Dictionary<int, MField>(typeDef.Fields.Count);
|
tokenToField = new Dictionary<int, MField>(typeDef.Fields.Count);
|
||||||
|
@ -89,7 +89,7 @@ namespace AssemblyData.methodsrewriter {
|
||||||
var token = (int)f.MDToken.Raw;
|
var token = (int)f.MDToken.Raw;
|
||||||
var field = new MField(tmpTokenToField[token], f);
|
var field = new MField(tmpTokenToField[token], f);
|
||||||
tokenToField[token] = field;
|
tokenToField[token] = field;
|
||||||
fieldRefToField.add(field.fieldDef, field);
|
fieldRefToField.Add(field.fieldDef, field);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,16 +62,16 @@ namespace AssemblyData.methodsrewriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodBase getNext() {
|
public MethodBase GetNext() {
|
||||||
return methods[next++ % methods.Count];
|
return methods[next++ % methods.Count];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodBase getMethod(Module module) {
|
public MethodBase GetMethod(Module module) {
|
||||||
MethodsModule methodsModule;
|
MethodsModule methodsModule;
|
||||||
if (!moduleToMethods.TryGetValue(module, out methodsModule))
|
if (!moduleToMethods.TryGetValue(module, out methodsModule))
|
||||||
moduleToMethods[module] = methodsModule = new MethodsModule(module);
|
moduleToMethods[module] = methodsModule = new MethodsModule(module);
|
||||||
return methodsModule.getNext();
|
return methodsModule.GetNext();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,20 +112,20 @@ namespace AssemblyData.methodsrewriter {
|
||||||
this.rewrittenMethodName = rewrittenMethodName;
|
this.rewrittenMethodName = rewrittenMethodName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isRewrittenMethod(string name) {
|
public bool IsRewrittenMethod(string name) {
|
||||||
return name == rewrittenMethodName;
|
return name == rewrittenMethodName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isDelegateMethod(string name) {
|
public bool IsDelegateMethod(string name) {
|
||||||
return name == delegateMethodName;
|
return name == delegateMethodName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type getDelegateType(MethodBase methodBase) {
|
public Type GetDelegateType(MethodBase methodBase) {
|
||||||
return realMethodToNewMethod[methodBase].delegateType;
|
return realMethodToNewMethod[methodBase].delegateType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RewrittenMethod createDelegate(MethodBase realMethod) {
|
public RewrittenMethod CreateDelegate(MethodBase realMethod) {
|
||||||
var newMethodInfo = realMethodToNewMethod[realMethod];
|
var newMethodInfo = realMethodToNewMethod[realMethod];
|
||||||
if (newMethodInfo.rewrittenMethod != null)
|
if (newMethodInfo.rewrittenMethod != null)
|
||||||
return newMethodInfo.rewrittenMethod;
|
return newMethodInfo.rewrittenMethod;
|
||||||
|
@ -135,7 +135,7 @@ namespace AssemblyData.methodsrewriter {
|
||||||
|
|
||||||
ilg.Emit(ROpCodes.Ldarg_0);
|
ilg.Emit(ROpCodes.Ldarg_0);
|
||||||
ilg.Emit(ROpCodes.Ldc_I4, newMethodInfo.delegateIndex);
|
ilg.Emit(ROpCodes.Ldc_I4, newMethodInfo.delegateIndex);
|
||||||
ilg.Emit(ROpCodes.Call, GetType().GetMethod("rtGetDelegateInstance", BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Instance));
|
ilg.Emit(ROpCodes.Call, GetType().GetMethod("RtGetDelegateInstance", BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Instance));
|
||||||
ilg.Emit(ROpCodes.Castclass, newMethodInfo.delegateType);
|
ilg.Emit(ROpCodes.Castclass, newMethodInfo.delegateType);
|
||||||
|
|
||||||
var args = newMethodInfo.oldMethod.GetParameters();
|
var args = newMethodInfo.oldMethod.GetParameters();
|
||||||
|
@ -156,7 +156,7 @@ namespace AssemblyData.methodsrewriter {
|
||||||
var flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance;
|
var flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance;
|
||||||
var invokeMethod = newMethodInfo.delegateType.GetMethod("Invoke", flags);
|
var invokeMethod = newMethodInfo.delegateType.GetMethod("Invoke", flags);
|
||||||
ilg.Emit(ROpCodes.Call, invokeMethod);
|
ilg.Emit(ROpCodes.Call, invokeMethod);
|
||||||
if (ResolverUtils.getReturnType(newMethodInfo.oldMethod) == typeof(void))
|
if (ResolverUtils.GetReturnType(newMethodInfo.oldMethod) == typeof(void))
|
||||||
ilg.Emit(ROpCodes.Ldnull);
|
ilg.Emit(ROpCodes.Ldnull);
|
||||||
ilg.Emit(ROpCodes.Ret);
|
ilg.Emit(ROpCodes.Ret);
|
||||||
|
|
||||||
|
@ -164,50 +164,50 @@ namespace AssemblyData.methodsrewriter {
|
||||||
return newMethodInfo.rewrittenMethod;
|
return newMethodInfo.rewrittenMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCaller(RewrittenMethod rewrittenMethod, MethodBase caller) {
|
public void SetCaller(RewrittenMethod rewrittenMethod, MethodBase caller) {
|
||||||
if (caller == null)
|
if (caller == null)
|
||||||
return;
|
return;
|
||||||
var newMethodInfo = getNewMethodInfo(rewrittenMethod.Method.Name);
|
var newMethodInfo = GetNewMethodInfo(rewrittenMethod.Method.Name);
|
||||||
newStackMethodDict[newMethodInfo] = caller;
|
newStackMethodDict[newMethodInfo] = caller;
|
||||||
}
|
}
|
||||||
|
|
||||||
string getDelegateMethodName(MethodBase method) {
|
string GetDelegateMethodName(MethodBase method) {
|
||||||
string name = null;
|
string name = null;
|
||||||
do {
|
do {
|
||||||
name = string.Format(" {0} {1:X8} DMN {2:X8} ", method.Name, method.MetadataToken, Utils.getRandomUint());
|
name = string.Format(" {0} {1:X8} DMN {2:X8} ", method.Name, method.MetadataToken, Utils.GetRandomUint());
|
||||||
} while (delegateNameToNewMethodInfo.ContainsKey(name));
|
} while (delegateNameToNewMethodInfo.ContainsKey(name));
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createMethod(MethodBase realMethod) {
|
public void CreateMethod(MethodBase realMethod) {
|
||||||
if (realMethodToNewMethod.ContainsKey(realMethod))
|
if (realMethodToNewMethod.ContainsKey(realMethod))
|
||||||
return;
|
return;
|
||||||
var newMethodInfo = new NewMethodInfo(realMethod, newMethodInfos.Count, getDelegateMethodName(realMethod), getDelegateMethodName(realMethod));
|
var newMethodInfo = new NewMethodInfo(realMethod, newMethodInfos.Count, GetDelegateMethodName(realMethod), GetDelegateMethodName(realMethod));
|
||||||
newMethodInfos.Add(newMethodInfo);
|
newMethodInfos.Add(newMethodInfo);
|
||||||
delegateNameToNewMethodInfo[newMethodInfo.delegateMethodName] = newMethodInfo;
|
delegateNameToNewMethodInfo[newMethodInfo.delegateMethodName] = newMethodInfo;
|
||||||
delegateNameToNewMethodInfo[newMethodInfo.rewrittenMethodName] = newMethodInfo;
|
delegateNameToNewMethodInfo[newMethodInfo.rewrittenMethodName] = newMethodInfo;
|
||||||
realMethodToNewMethod[realMethod] = newMethodInfo;
|
realMethodToNewMethod[realMethod] = newMethodInfo;
|
||||||
|
|
||||||
var moduleInfo = Resolver.loadAssembly(realMethod.Module);
|
var moduleInfo = Resolver.LoadAssembly(realMethod.Module);
|
||||||
var methodInfo = moduleInfo.getMethod(realMethod);
|
var methodInfo = moduleInfo.GetMethod(realMethod);
|
||||||
if (!methodInfo.hasInstructions())
|
if (!methodInfo.HasInstructions())
|
||||||
throw new ApplicationException(string.Format("Method {0} ({1:X8}) has no body", methodInfo.methodDef, methodInfo.methodDef.MDToken.Raw));
|
throw new ApplicationException(string.Format("Method {0} ({1:X8}) has no body", methodInfo.methodDef, methodInfo.methodDef.MDToken.Raw));
|
||||||
|
|
||||||
var codeGenerator = new CodeGenerator(this, newMethodInfo.delegateMethodName);
|
var codeGenerator = new CodeGenerator(this, newMethodInfo.delegateMethodName);
|
||||||
codeGenerator.setMethodInfo(methodInfo);
|
codeGenerator.SetMethodInfo(methodInfo);
|
||||||
newMethodInfo.delegateType = codeGenerator.DelegateType;
|
newMethodInfo.delegateType = codeGenerator.DelegateType;
|
||||||
|
|
||||||
var blocks = new Blocks(methodInfo.methodDef);
|
var blocks = new Blocks(methodInfo.methodDef);
|
||||||
foreach (var block in blocks.MethodBlocks.getAllBlocks())
|
foreach (var block in blocks.MethodBlocks.GetAllBlocks())
|
||||||
update(block, newMethodInfo);
|
Update(block, newMethodInfo);
|
||||||
|
|
||||||
IList<Instruction> allInstructions;
|
IList<Instruction> allInstructions;
|
||||||
IList<ExceptionHandler> allExceptionHandlers;
|
IList<ExceptionHandler> allExceptionHandlers;
|
||||||
blocks.getCode(out allInstructions, out allExceptionHandlers);
|
blocks.GetCode(out allInstructions, out allExceptionHandlers);
|
||||||
newMethodInfo.delegateInstance = codeGenerator.generate(allInstructions, allExceptionHandlers);
|
newMethodInfo.delegateInstance = codeGenerator.Generate(allInstructions, allExceptionHandlers);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Instruction create(OpCode opcode, object operand) {
|
static Instruction Create(OpCode opcode, object operand) {
|
||||||
return new Instruction {
|
return new Instruction {
|
||||||
OpCode = opcode,
|
OpCode = opcode,
|
||||||
Operand = operand,
|
Operand = operand,
|
||||||
|
@ -215,17 +215,17 @@ namespace AssemblyData.methodsrewriter {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inserts ldarg THIS, and returns number of instructions inserted at 'i'
|
// Inserts ldarg THIS, and returns number of instructions inserted at 'i'
|
||||||
int insertLoadThis(Block block, int i) {
|
int InsertLoadThis(Block block, int i) {
|
||||||
block.insert(i, create(OpCodes.Ldarg, new Operand(Operand.Type.ThisArg)));
|
block.Insert(i, Create(OpCodes.Ldarg, new Operand(Operand.Type.ThisArg)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int insertCallOurMethod(Block block, int i, string methodName) {
|
int InsertCallOurMethod(Block block, int i, string methodName) {
|
||||||
block.insert(i, create(OpCodes.Call, new Operand(Operand.Type.OurMethod, methodName)));
|
block.Insert(i, Create(OpCodes.Call, new Operand(Operand.Type.OurMethod, methodName)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void update(Block block, NewMethodInfo currentMethodInfo) {
|
void Update(Block block, NewMethodInfo currentMethodInfo) {
|
||||||
var instrs = block.Instructions;
|
var instrs = block.Instructions;
|
||||||
for (int i = 0; i < instrs.Count; i++) {
|
for (int i = 0; i < instrs.Count; i++) {
|
||||||
var instr = instrs[i];
|
var instr = instrs[i];
|
||||||
|
@ -233,14 +233,14 @@ namespace AssemblyData.methodsrewriter {
|
||||||
var ctor = (IMethod)instr.Operand;
|
var ctor = (IMethod)instr.Operand;
|
||||||
var ctorTypeFullName = ctor.DeclaringType.FullName;
|
var ctorTypeFullName = ctor.DeclaringType.FullName;
|
||||||
if (ctorTypeFullName == "System.Diagnostics.StackTrace") {
|
if (ctorTypeFullName == "System.Diagnostics.StackTrace") {
|
||||||
insertLoadThis(block, i + 1);
|
InsertLoadThis(block, i + 1);
|
||||||
insertCallOurMethod(block, i + 2, "static_rtFixStackTrace");
|
InsertCallOurMethod(block, i + 2, "static_RtFixStackTrace");
|
||||||
i += 2;
|
i += 2;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (ctorTypeFullName == "System.Diagnostics.StackFrame") {
|
else if (ctorTypeFullName == "System.Diagnostics.StackFrame") {
|
||||||
insertLoadThis(block, i + 1);
|
InsertLoadThis(block, i + 1);
|
||||||
insertCallOurMethod(block, i + 2, "static_rtFixStackFrame");
|
InsertCallOurMethod(block, i + 2, "static_RtFixStackFrame");
|
||||||
i += 2;
|
i += 2;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -251,67 +251,67 @@ namespace AssemblyData.methodsrewriter {
|
||||||
if (calledMethod.DeclaringType.DefinitionAssembly.IsCorLib()) {
|
if (calledMethod.DeclaringType.DefinitionAssembly.IsCorLib()) {
|
||||||
var calledMethodFullName = calledMethod.FullName;
|
var calledMethodFullName = calledMethod.FullName;
|
||||||
if (calledMethodFullName == "System.Reflection.Assembly System.Reflection.Assembly::GetAssembly(System.Type)") {
|
if (calledMethodFullName == "System.Reflection.Assembly System.Reflection.Assembly::GetAssembly(System.Type)") {
|
||||||
block.replace(i, 1, OpCodes.Nop.ToInstruction());
|
block.Replace(i, 1, OpCodes.Nop.ToInstruction());
|
||||||
insertLoadThis(block, i + 1);
|
InsertLoadThis(block, i + 1);
|
||||||
insertCallOurMethod(block, i + 2, "static_rtGetAssembly_TypeArg");
|
InsertCallOurMethod(block, i + 2, "static_RtGetAssembly_TypeArg");
|
||||||
i += 2;
|
i += 2;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (calledMethodFullName == "System.Reflection.Assembly System.Reflection.Assembly::GetCallingAssembly()" ||
|
else if (calledMethodFullName == "System.Reflection.Assembly System.Reflection.Assembly::GetCallingAssembly()" ||
|
||||||
calledMethodFullName == "System.Reflection.Assembly System.Reflection.Assembly::GetEntryAssembly()" ||
|
calledMethodFullName == "System.Reflection.Assembly System.Reflection.Assembly::GetEntryAssembly()" ||
|
||||||
calledMethodFullName == "System.Reflection.Assembly System.Reflection.Assembly::GetExecutingAssembly()") {
|
calledMethodFullName == "System.Reflection.Assembly System.Reflection.Assembly::GetExecutingAssembly()") {
|
||||||
block.replace(i, 1, OpCodes.Nop.ToInstruction());
|
block.Replace(i, 1, OpCodes.Nop.ToInstruction());
|
||||||
insertLoadThis(block, i + 1);
|
InsertLoadThis(block, i + 1);
|
||||||
block.insert(i + 2, OpCodes.Ldc_I4.ToInstruction(currentMethodInfo.delegateIndex));
|
block.Insert(i + 2, OpCodes.Ldc_I4.ToInstruction(currentMethodInfo.delegateIndex));
|
||||||
insertCallOurMethod(block, i + 3, "rtGetAssembly");
|
InsertCallOurMethod(block, i + 3, "RtGetAssembly");
|
||||||
i += 3;
|
i += 3;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var method = Resolver.getMethod((IMethod)instr.Operand);
|
var method = Resolver.GetMethod((IMethod)instr.Operand);
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
createMethod(method.methodBase);
|
CreateMethod(method.methodBase);
|
||||||
var newMethodInfo = realMethodToNewMethod[method.methodBase];
|
var newMethodInfo = realMethodToNewMethod[method.methodBase];
|
||||||
|
|
||||||
block.replace(i, 1, OpCodes.Nop.ToInstruction());
|
block.Replace(i, 1, OpCodes.Nop.ToInstruction());
|
||||||
int n = i + 1;
|
int n = i + 1;
|
||||||
|
|
||||||
// Pop all pushed args to a temp array
|
// Pop all pushed args to a temp array
|
||||||
var mparams = getParameters(method.methodDef);
|
var mparams = GetParameters(method.methodDef);
|
||||||
if (mparams.Count > 0) {
|
if (mparams.Count > 0) {
|
||||||
block.insert(n++, OpCodes.Ldc_I4.ToInstruction(mparams.Count));
|
block.Insert(n++, OpCodes.Ldc_I4.ToInstruction(mparams.Count));
|
||||||
var objectType = method.methodDef.DeclaringType.Module.CorLibTypes.Object;
|
var objectType = method.methodDef.DeclaringType.Module.CorLibTypes.Object;
|
||||||
block.insert(n++, OpCodes.Newarr.ToInstruction(objectType));
|
block.Insert(n++, OpCodes.Newarr.ToInstruction(objectType));
|
||||||
block.insert(n++, create(OpCodes.Stloc, new Operand(Operand.Type.TempObjArray)));
|
block.Insert(n++, Create(OpCodes.Stloc, new Operand(Operand.Type.TempObjArray)));
|
||||||
|
|
||||||
for (int j = mparams.Count - 1; j >= 0; j--) {
|
for (int j = mparams.Count - 1; j >= 0; j--) {
|
||||||
var argType = mparams[j];
|
var argType = mparams[j];
|
||||||
if (argType.RemovePinnedAndModifiers().IsValueType)
|
if (argType.RemovePinnedAndModifiers().IsValueType)
|
||||||
block.insert(n++, OpCodes.Box.ToInstruction(((TypeDefOrRefSig)argType).TypeDefOrRef));
|
block.Insert(n++, OpCodes.Box.ToInstruction(((TypeDefOrRefSig)argType).TypeDefOrRef));
|
||||||
block.insert(n++, create(OpCodes.Stloc, new Operand(Operand.Type.TempObj)));
|
block.Insert(n++, Create(OpCodes.Stloc, new Operand(Operand.Type.TempObj)));
|
||||||
block.insert(n++, create(OpCodes.Ldloc, new Operand(Operand.Type.TempObjArray)));
|
block.Insert(n++, Create(OpCodes.Ldloc, new Operand(Operand.Type.TempObjArray)));
|
||||||
block.insert(n++, OpCodes.Ldc_I4.ToInstruction(j));
|
block.Insert(n++, OpCodes.Ldc_I4.ToInstruction(j));
|
||||||
block.insert(n++, create(OpCodes.Ldloc, new Operand(Operand.Type.TempObj)));
|
block.Insert(n++, Create(OpCodes.Ldloc, new Operand(Operand.Type.TempObj)));
|
||||||
block.insert(n++, OpCodes.Stelem_Ref.ToInstruction());
|
block.Insert(n++, OpCodes.Stelem_Ref.ToInstruction());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push delegate instance
|
// Push delegate instance
|
||||||
insertLoadThis(block, n++);
|
InsertLoadThis(block, n++);
|
||||||
block.insert(n++, OpCodes.Ldc_I4.ToInstruction(newMethodInfo.delegateIndex));
|
block.Insert(n++, OpCodes.Ldc_I4.ToInstruction(newMethodInfo.delegateIndex));
|
||||||
insertCallOurMethod(block, n++, "rtGetDelegateInstance");
|
InsertCallOurMethod(block, n++, "RtGetDelegateInstance");
|
||||||
block.insert(n++, create(OpCodes.Castclass, new Operand(Operand.Type.ReflectionType, newMethodInfo.delegateType)));
|
block.Insert(n++, Create(OpCodes.Castclass, new Operand(Operand.Type.ReflectionType, newMethodInfo.delegateType)));
|
||||||
|
|
||||||
// Push all popped args
|
// Push all popped args
|
||||||
if (mparams.Count > 0) {
|
if (mparams.Count > 0) {
|
||||||
for (int j = 0; j < mparams.Count; j++) {
|
for (int j = 0; j < mparams.Count; j++) {
|
||||||
block.insert(n++, create(OpCodes.Ldloc, new Operand(Operand.Type.TempObjArray)));
|
block.Insert(n++, Create(OpCodes.Ldloc, new Operand(Operand.Type.TempObjArray)));
|
||||||
block.insert(n++, OpCodes.Ldc_I4.ToInstruction(j));
|
block.Insert(n++, OpCodes.Ldc_I4.ToInstruction(j));
|
||||||
block.insert(n++, OpCodes.Ldelem_Ref.ToInstruction());
|
block.Insert(n++, OpCodes.Ldelem_Ref.ToInstruction());
|
||||||
var argType = mparams[j];
|
var argType = mparams[j];
|
||||||
if (argType.RemovePinnedAndModifiers().IsValueType)
|
if (argType.RemovePinnedAndModifiers().IsValueType)
|
||||||
block.insert(n++, OpCodes.Unbox_Any.ToInstruction(((TypeDefOrRefSig)argType).TypeDefOrRef));
|
block.Insert(n++, OpCodes.Unbox_Any.ToInstruction(((TypeDefOrRefSig)argType).TypeDefOrRef));
|
||||||
else {
|
else {
|
||||||
// Don't cast it to its correct type. This will sometimes cause
|
// Don't cast it to its correct type. This will sometimes cause
|
||||||
// an exception in some EF obfuscated assembly since we'll be
|
// an exception in some EF obfuscated assembly since we'll be
|
||||||
|
@ -322,8 +322,8 @@ namespace AssemblyData.methodsrewriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
insertLoadThis(block, n++);
|
InsertLoadThis(block, n++);
|
||||||
block.insert(n++, create(OpCodes.Call, new Operand(Operand.Type.NewMethod, method.methodBase)));
|
block.Insert(n++, Create(OpCodes.Call, new Operand(Operand.Type.NewMethod, method.methodBase)));
|
||||||
i = n - 1;
|
i = n - 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -331,48 +331,48 @@ namespace AssemblyData.methodsrewriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static IList<TypeSig> getParameters(MethodDef method) {
|
static IList<TypeSig> GetParameters(MethodDef method) {
|
||||||
var list = new List<TypeSig>(method.Parameters.Count);
|
var list = new List<TypeSig>(method.Parameters.Count);
|
||||||
for (int i = 0; i < method.Parameters.Count; i++)
|
for (int i = 0; i < method.Parameters.Count; i++)
|
||||||
list.Add(method.Parameters[i].Type);
|
list.Add(method.Parameters[i].Type);
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
static FieldInfo getStackTraceStackFramesField() {
|
static FieldInfo GgetStackTraceStackFramesField() {
|
||||||
var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
|
var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
|
||||||
return ResolverUtils.getFieldThrow(typeof(StackTrace), typeof(StackFrame[]), flags, "Could not find StackTrace's frames (StackFrame[]) field");
|
return ResolverUtils.GetFieldThrow(typeof(StackTrace), typeof(StackFrame[]), flags, "Could not find StackTrace's frames (StackFrame[]) field");
|
||||||
}
|
}
|
||||||
|
|
||||||
static FieldInfo getStackFrameMethodField() {
|
static FieldInfo GetStackFrameMethodField() {
|
||||||
var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
|
var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
|
||||||
return ResolverUtils.getFieldThrow(typeof(StackFrame), typeof(MethodBase), flags, "Could not find StackFrame's method (MethodBase) field");
|
return ResolverUtils.GetFieldThrow(typeof(StackFrame), typeof(MethodBase), flags, "Could not find StackFrame's method (MethodBase) field");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void writeMethodBase(StackFrame frame, MethodBase method) {
|
static void WriteMethodBase(StackFrame frame, MethodBase method) {
|
||||||
var methodField = getStackFrameMethodField();
|
var methodField = GetStackFrameMethodField();
|
||||||
methodField.SetValue(frame, method);
|
methodField.SetValue(frame, method);
|
||||||
if (frame.GetMethod() != method)
|
if (frame.GetMethod() != method)
|
||||||
throw new ApplicationException(string.Format("Could not set new method: {0}", method));
|
throw new ApplicationException(string.Format("Could not set new method: {0}", method));
|
||||||
}
|
}
|
||||||
|
|
||||||
NewMethodInfo getNewMethodInfo(string name) {
|
NewMethodInfo GetNewMethodInfo(string name) {
|
||||||
NewMethodInfo info;
|
NewMethodInfo info;
|
||||||
delegateNameToNewMethodInfo.TryGetValue(name, out info);
|
delegateNameToNewMethodInfo.TryGetValue(name, out info);
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called after the StackTrace ctor has been called.
|
// Called after the StackTrace ctor has been called.
|
||||||
static StackTrace static_rtFixStackTrace(StackTrace stackTrace, MethodsRewriter self) {
|
static StackTrace static_RtFixStackTrace(StackTrace stackTrace, MethodsRewriter self) {
|
||||||
return self.rtFixStackTrace(stackTrace);
|
return self.RtFixStackTrace(stackTrace);
|
||||||
}
|
}
|
||||||
|
|
||||||
StackTrace rtFixStackTrace(StackTrace stackTrace) {
|
StackTrace RtFixStackTrace(StackTrace stackTrace) {
|
||||||
var framesField = getStackTraceStackFramesField();
|
var framesField = GgetStackTraceStackFramesField();
|
||||||
var frames = (StackFrame[])framesField.GetValue(stackTrace);
|
var frames = (StackFrame[])framesField.GetValue(stackTrace);
|
||||||
|
|
||||||
var newFrames = new List<StackFrame>(frames.Length);
|
var newFrames = new List<StackFrame>(frames.Length);
|
||||||
foreach (var frame in frames) {
|
foreach (var frame in frames) {
|
||||||
fixStackFrame(frame);
|
FixStackFrame(frame);
|
||||||
newFrames.Add(frame);
|
newFrames.Add(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -380,52 +380,52 @@ namespace AssemblyData.methodsrewriter {
|
||||||
return stackTrace;
|
return stackTrace;
|
||||||
}
|
}
|
||||||
|
|
||||||
static StackFrame static_rtFixStackFrame(StackFrame stackFrame, MethodsRewriter self) {
|
static StackFrame static_RtFixStackFrame(StackFrame stackFrame, MethodsRewriter self) {
|
||||||
return self.rtFixStackFrame(stackFrame);
|
return self.RtFixStackFrame(stackFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
StackFrame rtFixStackFrame(StackFrame frame) {
|
StackFrame RtFixStackFrame(StackFrame frame) {
|
||||||
fixStackFrame(frame);
|
FixStackFrame(frame);
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fixStackFrame(StackFrame frame) {
|
void FixStackFrame(StackFrame frame) {
|
||||||
var method = frame.GetMethod();
|
var method = frame.GetMethod();
|
||||||
var info = getNewMethodInfo(method.Name);
|
var info = GetNewMethodInfo(method.Name);
|
||||||
if (info == null)
|
if (info == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
MethodBase stackMethod;
|
MethodBase stackMethod;
|
||||||
if (newStackMethodDict.TryGetValue(info, out stackMethod)) {
|
if (newStackMethodDict.TryGetValue(info, out stackMethod)) {
|
||||||
writeMethodBase(frame, stackMethod);
|
WriteMethodBase(frame, stackMethod);
|
||||||
}
|
}
|
||||||
else if (info.isRewrittenMethod(method.Name)) {
|
else if (info.IsRewrittenMethod(method.Name)) {
|
||||||
// Write random method from the same module
|
// Write random method from the same module
|
||||||
writeMethodBase(frame, methodsFinder.getMethod(info.oldMethod.Module));
|
WriteMethodBase(frame, methodsFinder.GetMethod(info.oldMethod.Module));
|
||||||
}
|
}
|
||||||
else if (info.isDelegateMethod(method.Name)) {
|
else if (info.IsDelegateMethod(method.Name)) {
|
||||||
// Write original method
|
// Write original method
|
||||||
writeMethodBase(frame, info.oldMethod);
|
WriteMethodBase(frame, info.oldMethod);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw new ApplicationException("BUG: Shouldn't be here");
|
throw new ApplicationException("BUG: Shouldn't be here");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called when the code calls GetCallingAssembly(), GetEntryAssembly(), or GetExecutingAssembly()
|
// Called when the code calls GetCallingAssembly(), GetEntryAssembly(), or GetExecutingAssembly()
|
||||||
Assembly rtGetAssembly(int delegateIndex) {
|
Assembly RtGetAssembly(int delegateIndex) {
|
||||||
return newMethodInfos[delegateIndex].oldMethod.Module.Assembly;
|
return newMethodInfos[delegateIndex].oldMethod.Module.Assembly;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called when the code calls GetAssembly(Type)
|
// Called when the code calls GetAssembly(Type)
|
||||||
static Assembly static_rtGetAssembly_TypeArg(Type type, MethodsRewriter self) {
|
static Assembly static_RtGetAssembly_TypeArg(Type type, MethodsRewriter self) {
|
||||||
return self.rtGetAssembly_TypeArg(type);
|
return self.RtGetAssembly_TypeArg(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
Assembly rtGetAssembly_TypeArg(Type type) {
|
Assembly RtGetAssembly_TypeArg(Type type) {
|
||||||
return Assembly.GetAssembly(type);
|
return Assembly.GetAssembly(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
Delegate rtGetDelegateInstance(int delegateIndex) {
|
Delegate RtGetDelegateInstance(int delegateIndex) {
|
||||||
return newMethodInfos[delegateIndex].delegateInstance;
|
return newMethodInfos[delegateIndex].delegateInstance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ namespace AssemblyData.methodsrewriter {
|
||||||
static Dictionary<string, AssemblyResolver> assemblyResolvers = new Dictionary<string, AssemblyResolver>(StringComparer.Ordinal);
|
static Dictionary<string, AssemblyResolver> assemblyResolvers = new Dictionary<string, AssemblyResolver>(StringComparer.Ordinal);
|
||||||
static Dictionary<Module, MModule> modules = new Dictionary<Module, MModule>();
|
static Dictionary<Module, MModule> modules = new Dictionary<Module, MModule>();
|
||||||
|
|
||||||
public static MModule loadAssembly(Module module) {
|
public static MModule LoadAssembly(Module module) {
|
||||||
MModule info;
|
MModule info;
|
||||||
if (modules.TryGetValue(module, out info))
|
if (modules.TryGetValue(module, out info))
|
||||||
return info;
|
return info;
|
||||||
|
@ -38,7 +38,7 @@ namespace AssemblyData.methodsrewriter {
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MModule getModule(ModuleDef moduleDef) {
|
static MModule GetModule(ModuleDef moduleDef) {
|
||||||
foreach (var mm in modules.Values) {
|
foreach (var mm in modules.Values) {
|
||||||
if (mm.moduleDef == moduleDef)
|
if (mm.moduleDef == moduleDef)
|
||||||
return mm;
|
return mm;
|
||||||
|
@ -46,7 +46,7 @@ namespace AssemblyData.methodsrewriter {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MModule getModule(AssemblyRef asmRef) {
|
static MModule GetModule(AssemblyRef asmRef) {
|
||||||
foreach (var mm in modules.Values) {
|
foreach (var mm in modules.Values) {
|
||||||
var asm = mm.moduleDef.Assembly;
|
var asm = mm.moduleDef.Assembly;
|
||||||
if (asm != null && asm.FullName == asmRef.FullName)
|
if (asm != null && asm.FullName == asmRef.FullName)
|
||||||
|
@ -55,83 +55,83 @@ namespace AssemblyData.methodsrewriter {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MModule getModule(IScope scope) {
|
public static MModule GetModule(IScope scope) {
|
||||||
if (scope.ScopeType == ScopeType.ModuleDef)
|
if (scope.ScopeType == ScopeType.ModuleDef)
|
||||||
return getModule((ModuleDef)scope);
|
return GetModule((ModuleDef)scope);
|
||||||
else if (scope.ScopeType == ScopeType.AssemblyRef)
|
else if (scope.ScopeType == ScopeType.AssemblyRef)
|
||||||
return getModule((AssemblyRef)scope);
|
return GetModule((AssemblyRef)scope);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MType getType(IType typeRef) {
|
public static MType GetType(IType typeRef) {
|
||||||
if (typeRef == null)
|
if (typeRef == null)
|
||||||
return null;
|
return null;
|
||||||
var module = getModule(typeRef.Scope);
|
var module = GetModule(typeRef.Scope);
|
||||||
if (module != null)
|
if (module != null)
|
||||||
return module.getType(typeRef);
|
return module.GetType(typeRef);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MMethod getMethod(IMethod methodRef) {
|
public static MMethod GetMethod(IMethod methodRef) {
|
||||||
if (methodRef == null)
|
if (methodRef == null)
|
||||||
return null;
|
return null;
|
||||||
var module = getModule(methodRef.DeclaringType.Scope);
|
var module = GetModule(methodRef.DeclaringType.Scope);
|
||||||
if (module != null)
|
if (module != null)
|
||||||
return module.getMethod(methodRef);
|
return module.GetMethod(methodRef);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MField getField(IField fieldRef) {
|
public static MField GetField(IField fieldRef) {
|
||||||
if (fieldRef == null)
|
if (fieldRef == null)
|
||||||
return null;
|
return null;
|
||||||
var module = getModule(fieldRef.DeclaringType.Scope);
|
var module = GetModule(fieldRef.DeclaringType.Scope);
|
||||||
if (module != null)
|
if (module != null)
|
||||||
return module.getField(fieldRef);
|
return module.GetField(fieldRef);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static object getRtObject(ITokenOperand memberRef) {
|
public static object GetRtObject(ITokenOperand memberRef) {
|
||||||
if (memberRef == null)
|
if (memberRef == null)
|
||||||
return null;
|
return null;
|
||||||
var tdr = memberRef as ITypeDefOrRef;
|
var tdr = memberRef as ITypeDefOrRef;
|
||||||
if (tdr != null)
|
if (tdr != null)
|
||||||
return getRtType(tdr);
|
return GetRtType(tdr);
|
||||||
var field = memberRef as IField;
|
var field = memberRef as IField;
|
||||||
if (field != null && field.FieldSig != null)
|
if (field != null && field.FieldSig != null)
|
||||||
return getRtField(field);
|
return GetRtField(field);
|
||||||
var method = memberRef as IMethod;
|
var method = memberRef as IMethod;
|
||||||
if (method != null && method.MethodSig != null)
|
if (method != null && method.MethodSig != null)
|
||||||
return getRtMethod(method);
|
return GetRtMethod(method);
|
||||||
|
|
||||||
throw new ApplicationException(string.Format("Unknown MemberRef: {0}", memberRef));
|
throw new ApplicationException(string.Format("Unknown MemberRef: {0}", memberRef));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Type getRtType(IType typeRef) {
|
public static Type GetRtType(IType typeRef) {
|
||||||
var mtype = getType(typeRef);
|
var mtype = GetType(typeRef);
|
||||||
if (mtype != null)
|
if (mtype != null)
|
||||||
return mtype.type;
|
return mtype.type;
|
||||||
|
|
||||||
return Resolver.resolve(typeRef);
|
return Resolver.Resolve(typeRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FieldInfo getRtField(IField fieldRef) {
|
public static FieldInfo GetRtField(IField fieldRef) {
|
||||||
var mfield = getField(fieldRef);
|
var mfield = GetField(fieldRef);
|
||||||
if (mfield != null)
|
if (mfield != null)
|
||||||
return mfield.fieldInfo;
|
return mfield.fieldInfo;
|
||||||
|
|
||||||
return Resolver.resolve(fieldRef);
|
return Resolver.Resolve(fieldRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MethodBase getRtMethod(IMethod methodRef) {
|
public static MethodBase GetRtMethod(IMethod methodRef) {
|
||||||
var mmethod = getMethod(methodRef);
|
var mmethod = GetMethod(methodRef);
|
||||||
if (mmethod != null)
|
if (mmethod != null)
|
||||||
return mmethod.methodBase;
|
return mmethod.methodBase;
|
||||||
|
|
||||||
return Resolver.resolve(methodRef);
|
return Resolver.Resolve(methodRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
static AssemblyResolver getAssemblyResolver(ITypeDefOrRef type) {
|
static AssemblyResolver GetAssemblyResolver(ITypeDefOrRef type) {
|
||||||
var asmName = type.DefinitionAssembly.FullName;
|
var asmName = type.DefinitionAssembly.FullName;
|
||||||
AssemblyResolver resolver;
|
AssemblyResolver resolver;
|
||||||
if (!assemblyResolvers.TryGetValue(asmName, out resolver))
|
if (!assemblyResolvers.TryGetValue(asmName, out resolver))
|
||||||
|
@ -139,38 +139,38 @@ namespace AssemblyData.methodsrewriter {
|
||||||
return resolver;
|
return resolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Type resolve(IType typeRef) {
|
static Type Resolve(IType typeRef) {
|
||||||
if (typeRef == null)
|
if (typeRef == null)
|
||||||
return null;
|
return null;
|
||||||
var scopeType = typeRef.ScopeType;
|
var scopeType = typeRef.ScopeType;
|
||||||
var resolver = getAssemblyResolver(scopeType);
|
var resolver = GetAssemblyResolver(scopeType);
|
||||||
var resolvedType = resolver.resolve(scopeType);
|
var resolvedType = resolver.Resolve(scopeType);
|
||||||
if (resolvedType != null)
|
if (resolvedType != null)
|
||||||
return fixType(typeRef, resolvedType);
|
return FixType(typeRef, resolvedType);
|
||||||
throw new ApplicationException(string.Format("Could not resolve type {0} ({1:X8}) in assembly {2}", typeRef, typeRef.MDToken.Raw, resolver));
|
throw new ApplicationException(string.Format("Could not resolve type {0} ({1:X8}) in assembly {2}", typeRef, typeRef.MDToken.Raw, resolver));
|
||||||
}
|
}
|
||||||
|
|
||||||
static FieldInfo resolve(IField fieldRef) {
|
static FieldInfo Resolve(IField fieldRef) {
|
||||||
if (fieldRef == null)
|
if (fieldRef == null)
|
||||||
return null;
|
return null;
|
||||||
var resolver = getAssemblyResolver(fieldRef.DeclaringType);
|
var resolver = GetAssemblyResolver(fieldRef.DeclaringType);
|
||||||
var fieldInfo = resolver.resolve(fieldRef);
|
var fieldInfo = resolver.Resolve(fieldRef);
|
||||||
if (fieldInfo != null)
|
if (fieldInfo != null)
|
||||||
return fieldInfo;
|
return fieldInfo;
|
||||||
throw new ApplicationException(string.Format("Could not resolve field {0} ({1:X8}) in assembly {2}", fieldRef, fieldRef.MDToken.Raw, resolver));
|
throw new ApplicationException(string.Format("Could not resolve field {0} ({1:X8}) in assembly {2}", fieldRef, fieldRef.MDToken.Raw, resolver));
|
||||||
}
|
}
|
||||||
|
|
||||||
static MethodBase resolve(IMethod methodRef) {
|
static MethodBase Resolve(IMethod methodRef) {
|
||||||
if (methodRef == null)
|
if (methodRef == null)
|
||||||
return null;
|
return null;
|
||||||
var resolver = getAssemblyResolver(methodRef.DeclaringType);
|
var resolver = GetAssemblyResolver(methodRef.DeclaringType);
|
||||||
var methodBase = resolver.resolve(methodRef);
|
var methodBase = resolver.Resolve(methodRef);
|
||||||
if (methodBase != null)
|
if (methodBase != null)
|
||||||
return methodBase;
|
return methodBase;
|
||||||
throw new ApplicationException(string.Format("Could not resolve method {0} ({1:X8}) in assembly {2}", methodRef, methodRef.MDToken.Raw, resolver));
|
throw new ApplicationException(string.Format("Could not resolve method {0} ({1:X8}) in assembly {2}", methodRef, methodRef.MDToken.Raw, resolver));
|
||||||
}
|
}
|
||||||
|
|
||||||
static Type fixType(IType typeRef, Type type) {
|
static Type FixType(IType typeRef, Type type) {
|
||||||
var sig = typeRef as TypeSig;
|
var sig = typeRef as TypeSig;
|
||||||
if (sig == null) {
|
if (sig == null) {
|
||||||
var ts = typeRef as TypeSpec;
|
var ts = typeRef as TypeSpec;
|
||||||
|
@ -203,7 +203,7 @@ namespace AssemblyData.methodsrewriter {
|
||||||
var arg = git.GenericArguments[i];
|
var arg = git.GenericArguments[i];
|
||||||
if (!(arg is GenericSig))
|
if (!(arg is GenericSig))
|
||||||
isGenericTypeDef = false;
|
isGenericTypeDef = false;
|
||||||
args[i] = Resolver.resolve(arg);
|
args[i] = Resolver.Resolve(arg);
|
||||||
}
|
}
|
||||||
if (!isGenericTypeDef)
|
if (!isGenericTypeDef)
|
||||||
type = type.MakeGenericType(args);
|
type = type.MakeGenericType(args);
|
||||||
|
|
|
@ -25,27 +25,27 @@ using de4dot.blocks;
|
||||||
|
|
||||||
namespace AssemblyData.methodsrewriter {
|
namespace AssemblyData.methodsrewriter {
|
||||||
static class ResolverUtils {
|
static class ResolverUtils {
|
||||||
public static bool compareTypes(Type a, IType b) {
|
public static bool CompareTypes(Type a, IType b) {
|
||||||
return new SigComparer().Equals(a, b);
|
return new SigComparer().Equals(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool compareFields(FieldInfo a, IField b) {
|
public static bool CompareFields(FieldInfo a, IField b) {
|
||||||
return new SigComparer().Equals(a, b);
|
return new SigComparer().Equals(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool hasThis(MethodBase method) {
|
public static bool HasThis(MethodBase method) {
|
||||||
return (method.CallingConvention & CallingConventions.HasThis) != 0;
|
return (method.CallingConvention & CallingConventions.HasThis) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool explicitThis(MethodBase method) {
|
public static bool ExplicitThis(MethodBase method) {
|
||||||
return (method.CallingConvention & CallingConventions.ExplicitThis) != 0;
|
return (method.CallingConvention & CallingConventions.ExplicitThis) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool compareMethods(MethodBase a, IMethod b) {
|
public static bool CompareMethods(MethodBase a, IMethod b) {
|
||||||
return new SigComparer().Equals(a, b);
|
return new SigComparer().Equals(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Type getReturnType(MethodBase methodBase) {
|
public static Type GetReturnType(MethodBase methodBase) {
|
||||||
var methodInfo = methodBase as MethodInfo;
|
var methodInfo = methodBase as MethodInfo;
|
||||||
if (methodInfo != null)
|
if (methodInfo != null)
|
||||||
return methodInfo.ReturnType;
|
return methodInfo.ReturnType;
|
||||||
|
@ -57,7 +57,7 @@ namespace AssemblyData.methodsrewriter {
|
||||||
throw new ApplicationException(string.Format("Could not figure out return type: {0} ({1:X8})", methodBase, methodBase.MetadataToken));
|
throw new ApplicationException(string.Format("Could not figure out return type: {0} ({1:X8})", methodBase, methodBase.MetadataToken));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Type[] getGenericArguments(MethodBase methodBase) {
|
public static Type[] GetGenericArguments(MethodBase methodBase) {
|
||||||
try {
|
try {
|
||||||
return methodBase.GetGenericArguments();
|
return methodBase.GetGenericArguments();
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ namespace AssemblyData.methodsrewriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<MethodBase> getMethodBases(Type type, BindingFlags flags) {
|
public static IEnumerable<MethodBase> GetMethodBases(Type type, BindingFlags flags) {
|
||||||
if (type.TypeInitializer != null)
|
if (type.TypeInitializer != null)
|
||||||
yield return type.TypeInitializer;
|
yield return type.TypeInitializer;
|
||||||
foreach (var ctor in type.GetConstructors(flags))
|
foreach (var ctor in type.GetConstructors(flags))
|
||||||
|
@ -96,7 +96,7 @@ namespace AssemblyData.methodsrewriter {
|
||||||
}
|
}
|
||||||
|
|
||||||
static Dictionary<CachedMemberInfo, FieldInfo> cachedFieldInfos = new Dictionary<CachedMemberInfo, FieldInfo>();
|
static Dictionary<CachedMemberInfo, FieldInfo> cachedFieldInfos = new Dictionary<CachedMemberInfo, FieldInfo>();
|
||||||
public static FieldInfo getField(Type type, Type fieldType, BindingFlags flags) {
|
public static FieldInfo GetField(Type type, Type fieldType, BindingFlags flags) {
|
||||||
var key = new CachedMemberInfo(type, fieldType);
|
var key = new CachedMemberInfo(type, fieldType);
|
||||||
FieldInfo fieldInfo;
|
FieldInfo fieldInfo;
|
||||||
if (cachedFieldInfos.TryGetValue(key, out fieldInfo))
|
if (cachedFieldInfos.TryGetValue(key, out fieldInfo))
|
||||||
|
@ -111,14 +111,14 @@ namespace AssemblyData.methodsrewriter {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FieldInfo getFieldThrow(Type type, Type fieldType, BindingFlags flags, string msg) {
|
public static FieldInfo GetFieldThrow(Type type, Type fieldType, BindingFlags flags, string msg) {
|
||||||
var info = getField(type, fieldType, flags);
|
var info = GetField(type, fieldType, flags);
|
||||||
if (info != null)
|
if (info != null)
|
||||||
return info;
|
return info;
|
||||||
throw new ApplicationException(msg);
|
throw new ApplicationException(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<FieldInfo> getFields(Type type, Type fieldType, BindingFlags flags) {
|
public static List<FieldInfo> GetFields(Type type, Type fieldType, BindingFlags flags) {
|
||||||
var list = new List<FieldInfo>();
|
var list = new List<FieldInfo>();
|
||||||
foreach (var field in type.GetFields(flags)) {
|
foreach (var field in type.GetFields(flags)) {
|
||||||
if (field.FieldType == fieldType)
|
if (field.FieldType == fieldType)
|
||||||
|
@ -127,7 +127,7 @@ namespace AssemblyData.methodsrewriter {
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Type makeInstanceType(Type type, ITypeDefOrRef typeRef) {
|
public static Type MakeInstanceType(Type type, ITypeDefOrRef typeRef) {
|
||||||
var ts = typeRef as TypeSpec;
|
var ts = typeRef as TypeSpec;
|
||||||
if (ts == null)
|
if (ts == null)
|
||||||
return type;
|
return type;
|
||||||
|
@ -140,7 +140,7 @@ namespace AssemblyData.methodsrewriter {
|
||||||
var arg = git.GenericArguments[i];
|
var arg = git.GenericArguments[i];
|
||||||
if (!(arg is GenericSig))
|
if (!(arg is GenericSig))
|
||||||
isTypeDef = false;
|
isTypeDef = false;
|
||||||
types[i] = Resolver.getRtType(arg);
|
types[i] = Resolver.GetRtType(arg);
|
||||||
}
|
}
|
||||||
if (isTypeDef)
|
if (isTypeDef)
|
||||||
return type;
|
return type;
|
||||||
|
|
|
@ -30,27 +30,27 @@ namespace AssemblyData.methodsrewriter {
|
||||||
Dictionary<string, List<FieldInfo>> fields;
|
Dictionary<string, List<FieldInfo>> fields;
|
||||||
|
|
||||||
public TypeInstanceResolver(Type type, ITypeDefOrRef typeRef) {
|
public TypeInstanceResolver(Type type, ITypeDefOrRef typeRef) {
|
||||||
this.type = ResolverUtils.makeInstanceType(type, typeRef);
|
this.type = ResolverUtils.MakeInstanceType(type, typeRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FieldInfo resolve(IField fieldRef) {
|
public FieldInfo Resolve(IField fieldRef) {
|
||||||
initFields();
|
InitFields();
|
||||||
|
|
||||||
List<FieldInfo> list;
|
List<FieldInfo> list;
|
||||||
if (!fields.TryGetValue(fieldRef.Name.String, out list))
|
if (!fields.TryGetValue(fieldRef.Name.String, out list))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
fieldRef = GenericArgsSubstitutor.create(fieldRef, fieldRef.DeclaringType.TryGetGenericInstSig());
|
fieldRef = GenericArgsSubstitutor.Create(fieldRef, fieldRef.DeclaringType.TryGetGenericInstSig());
|
||||||
|
|
||||||
foreach (var field in list) {
|
foreach (var field in list) {
|
||||||
if (ResolverUtils.compareFields(field, fieldRef))
|
if (ResolverUtils.CompareFields(field, fieldRef))
|
||||||
return field;
|
return field;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initFields() {
|
void InitFields() {
|
||||||
if (fields != null)
|
if (fields != null)
|
||||||
return;
|
return;
|
||||||
fields = new Dictionary<string, List<FieldInfo>>(StringComparer.Ordinal);
|
fields = new Dictionary<string, List<FieldInfo>>(StringComparer.Ordinal);
|
||||||
|
@ -64,30 +64,30 @@ namespace AssemblyData.methodsrewriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodBase resolve(IMethod methodRef) {
|
public MethodBase Resolve(IMethod methodRef) {
|
||||||
initMethods();
|
InitMethods();
|
||||||
|
|
||||||
List<MethodBase> list;
|
List<MethodBase> list;
|
||||||
if (!methods.TryGetValue(methodRef.Name.String, out list))
|
if (!methods.TryGetValue(methodRef.Name.String, out list))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
methodRef = GenericArgsSubstitutor.create(methodRef, methodRef.DeclaringType.TryGetGenericInstSig());
|
methodRef = GenericArgsSubstitutor.Create(methodRef, methodRef.DeclaringType.TryGetGenericInstSig());
|
||||||
|
|
||||||
foreach (var method in list) {
|
foreach (var method in list) {
|
||||||
if (ResolverUtils.compareMethods(method, methodRef))
|
if (ResolverUtils.CompareMethods(method, methodRef))
|
||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initMethods() {
|
void InitMethods() {
|
||||||
if (methods != null)
|
if (methods != null)
|
||||||
return;
|
return;
|
||||||
methods = new Dictionary<string, List<MethodBase>>(StringComparer.Ordinal);
|
methods = new Dictionary<string, List<MethodBase>>(StringComparer.Ordinal);
|
||||||
|
|
||||||
var flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
|
var flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
|
||||||
foreach (var method in ResolverUtils.getMethodBases(type, flags)) {
|
foreach (var method in ResolverUtils.GetMethodBases(type, flags)) {
|
||||||
List<MethodBase> list;
|
List<MethodBase> list;
|
||||||
if (!methods.TryGetValue(method.Name, out list))
|
if (!methods.TryGetValue(method.Name, out list))
|
||||||
methods[method.Name] = list = new List<MethodBase>();
|
methods[method.Name] = list = new List<MethodBase>();
|
||||||
|
|
|
@ -32,19 +32,19 @@ namespace AssemblyData.methodsrewriter {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeInstanceResolver getTypeInstance(ITypeDefOrRef typeRef) {
|
TypeInstanceResolver GetTypeInstance(ITypeDefOrRef typeRef) {
|
||||||
TypeInstanceResolver instance;
|
TypeInstanceResolver instance;
|
||||||
if (!typeRefToInstance.TryGetValue(typeRef, out instance))
|
if (!typeRefToInstance.TryGetValue(typeRef, out instance))
|
||||||
typeRefToInstance[typeRef] = instance = new TypeInstanceResolver(type, typeRef);
|
typeRefToInstance[typeRef] = instance = new TypeInstanceResolver(type, typeRef);
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FieldInfo resolve(IField fieldRef) {
|
public FieldInfo Resolve(IField fieldRef) {
|
||||||
return getTypeInstance(fieldRef.DeclaringType).resolve(fieldRef);
|
return GetTypeInstance(fieldRef.DeclaringType).Resolve(fieldRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodBase resolve(IMethod methodRef) {
|
public MethodBase Resolve(IMethod methodRef) {
|
||||||
return getTypeInstance(methodRef.DeclaringType).resolve(methodRef);
|
return GetTypeInstance(methodRef.DeclaringType).Resolve(methodRef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
namespace AssemblyServer_CLR20_x64 {
|
namespace AssemblyServer_CLR20_x64 {
|
||||||
class Program {
|
class Program {
|
||||||
static int Main(string[] args) {
|
static int Main(string[] args) {
|
||||||
return AssemblyServer.Start.main(args);
|
return AssemblyServer.Start.Main2(args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
[assembly: AssemblyVersion("2.0.2.3405")]
|
[assembly: AssemblyVersion("2.0.3.3405")]
|
||||||
[assembly: AssemblyFileVersion("2.0.2.3405")]
|
[assembly: AssemblyFileVersion("2.0.3.3405")]
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
namespace AssemblyServer_CLR20 {
|
namespace AssemblyServer_CLR20 {
|
||||||
class Program {
|
class Program {
|
||||||
static int Main(string[] args) {
|
static int Main(string[] args) {
|
||||||
return AssemblyServer.Start.main(args);
|
return AssemblyServer.Start.Main2(args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
[assembly: AssemblyVersion("2.0.2.3405")]
|
[assembly: AssemblyVersion("2.0.3.3405")]
|
||||||
[assembly: AssemblyFileVersion("2.0.2.3405")]
|
[assembly: AssemblyFileVersion("2.0.3.3405")]
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
namespace AssemblyServer_CLR40_x64 {
|
namespace AssemblyServer_CLR40_x64 {
|
||||||
class Program {
|
class Program {
|
||||||
static int Main(string[] args) {
|
static int Main(string[] args) {
|
||||||
return AssemblyServer.Start.main(args);
|
return AssemblyServer.Start.Main2(args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
[assembly: AssemblyVersion("2.0.2.3405")]
|
[assembly: AssemblyVersion("2.0.3.3405")]
|
||||||
[assembly: AssemblyFileVersion("2.0.2.3405")]
|
[assembly: AssemblyFileVersion("2.0.3.3405")]
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
namespace AssemblyServer_CLR40 {
|
namespace AssemblyServer_CLR40 {
|
||||||
class Program {
|
class Program {
|
||||||
static int Main(string[] args) {
|
static int Main(string[] args) {
|
||||||
return AssemblyServer.Start.main(args);
|
return AssemblyServer.Start.Main2(args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
[assembly: AssemblyVersion("2.0.2.3405")]
|
[assembly: AssemblyVersion("2.0.3.3405")]
|
||||||
[assembly: AssemblyFileVersion("2.0.2.3405")]
|
[assembly: AssemblyFileVersion("2.0.3.3405")]
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
namespace AssemblyServer_x64 {
|
namespace AssemblyServer_x64 {
|
||||||
class Program {
|
class Program {
|
||||||
static int Main(string[] args) {
|
static int Main(string[] args) {
|
||||||
return AssemblyServer.Start.main(args);
|
return AssemblyServer.Start.Main2(args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
[assembly: AssemblyVersion("2.0.2.3405")]
|
[assembly: AssemblyVersion("2.0.3.3405")]
|
||||||
[assembly: AssemblyFileVersion("2.0.2.3405")]
|
[assembly: AssemblyFileVersion("2.0.3.3405")]
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
namespace AssemblyServer_x86 {
|
namespace AssemblyServer_x86 {
|
||||||
class Program {
|
class Program {
|
||||||
static int Main(string[] args) {
|
static int Main(string[] args) {
|
||||||
return AssemblyServer.Start.main(args);
|
return AssemblyServer.Start.Main2(args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
[assembly: AssemblyVersion("2.0.2.3405")]
|
[assembly: AssemblyVersion("2.0.3.3405")]
|
||||||
[assembly: AssemblyFileVersion("2.0.2.3405")]
|
[assembly: AssemblyFileVersion("2.0.3.3405")]
|
||||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
[assembly: AssemblyVersion("2.0.2.3405")]
|
[assembly: AssemblyVersion("2.0.3.3405")]
|
||||||
[assembly: AssemblyFileVersion("2.0.2.3405")]
|
[assembly: AssemblyFileVersion("2.0.3.3405")]
|
||||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
[assembly: AssemblyVersion("2.0.2.3405")]
|
[assembly: AssemblyVersion("2.0.3.3405")]
|
||||||
[assembly: AssemblyFileVersion("2.0.2.3405")]
|
[assembly: AssemblyFileVersion("2.0.3.3405")]
|
||||||
|
|
142
blocks/Block.cs
142
blocks/Block.cs
|
@ -52,7 +52,7 @@ namespace de4dot.blocks {
|
||||||
public Instr FirstInstr {
|
public Instr FirstInstr {
|
||||||
get {
|
get {
|
||||||
if (instructions.Count == 0)
|
if (instructions.Count == 0)
|
||||||
add(new Instr(OpCodes.Nop.ToInstruction()));
|
Add(new Instr(OpCodes.Nop.ToInstruction()));
|
||||||
return instructions[0];
|
return instructions[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,16 +60,16 @@ namespace de4dot.blocks {
|
||||||
public Instr LastInstr {
|
public Instr LastInstr {
|
||||||
get {
|
get {
|
||||||
if (instructions.Count == 0)
|
if (instructions.Count == 0)
|
||||||
add(new Instr(OpCodes.Nop.ToInstruction()));
|
Add(new Instr(OpCodes.Nop.ToInstruction()));
|
||||||
return instructions[instructions.Count - 1];
|
return instructions[instructions.Count - 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(Instr instr) {
|
public void Add(Instr instr) {
|
||||||
instructions.Add(instr);
|
instructions.Add(instr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void insert(int index, Instruction instr) {
|
public void Insert(int index, Instruction instr) {
|
||||||
instructions.Insert(index, new Instr(instr));
|
instructions.Insert(index, new Instr(instr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,8 +78,8 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If last instr is a br/br.s, removes it and replaces it with a fall through
|
// If last instr is a br/br.s, removes it and replaces it with a fall through
|
||||||
public void removeLastBr() {
|
public void RemoveLastBr() {
|
||||||
if (!LastInstr.isBr())
|
if (!LastInstr.IsBr())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (fallThrough != null || (LastInstr.Operand != null && (targets == null || targets.Count != 1)))
|
if (fallThrough != null || (LastInstr.Operand != null && (targets == null || targets.Count != 1)))
|
||||||
|
@ -89,111 +89,111 @@ namespace de4dot.blocks {
|
||||||
instructions.RemoveAt(instructions.Count - 1);
|
instructions.RemoveAt(instructions.Count - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void replace(int index, int num, Instruction instruction) {
|
public void Replace(int index, int num, Instruction instruction) {
|
||||||
if (num <= 0)
|
if (num <= 0)
|
||||||
throw new ArgumentOutOfRangeException("num");
|
throw new ArgumentOutOfRangeException("num");
|
||||||
remove(index, num);
|
Remove(index, num);
|
||||||
instructions.Insert(index, new Instr(instruction));
|
instructions.Insert(index, new Instr(instruction));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove(int index, int num) {
|
public void Remove(int index, int num) {
|
||||||
if (index + num > instructions.Count)
|
if (index + num > instructions.Count)
|
||||||
throw new ApplicationException("Overflow");
|
throw new ApplicationException("Overflow");
|
||||||
if (num > 0 && index + num == instructions.Count && LastInstr.isConditionalBranch())
|
if (num > 0 && index + num == instructions.Count && LastInstr.IsConditionalBranch())
|
||||||
disconnectFromFallThroughAndTargets();
|
DisconnectFromFallThroughAndTargets();
|
||||||
instructions.RemoveRange(index, num);
|
instructions.RemoveRange(index, num);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove(IEnumerable<int> indexes) {
|
public void Remove(IEnumerable<int> indexes) {
|
||||||
var instrsToDelete = new List<int>(Utils.unique(indexes));
|
var instrsToDelete = new List<int>(Utils.Unique(indexes));
|
||||||
instrsToDelete.Sort();
|
instrsToDelete.Sort();
|
||||||
instrsToDelete.Reverse();
|
instrsToDelete.Reverse();
|
||||||
foreach (var index in instrsToDelete)
|
foreach (var index in instrsToDelete)
|
||||||
remove(index, 1);
|
Remove(index, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace the last instructions with a branch to target
|
// Replace the last instructions with a branch to target
|
||||||
public void replaceLastInstrsWithBranch(int numInstrs, Block target) {
|
public void ReplaceLastInstrsWithBranch(int numInstrs, Block target) {
|
||||||
if (numInstrs < 0 || numInstrs > instructions.Count)
|
if (numInstrs < 0 || numInstrs > instructions.Count)
|
||||||
throw new ApplicationException("Invalid numInstrs to replace with branch");
|
throw new ApplicationException("Invalid numInstrs to replace with branch");
|
||||||
if (target == null)
|
if (target == null)
|
||||||
throw new ApplicationException("Invalid new target, it's null");
|
throw new ApplicationException("Invalid new target, it's null");
|
||||||
|
|
||||||
disconnectFromFallThroughAndTargets();
|
DisconnectFromFallThroughAndTargets();
|
||||||
if (numInstrs > 0)
|
if (numInstrs > 0)
|
||||||
instructions.RemoveRange(instructions.Count - numInstrs, numInstrs);
|
instructions.RemoveRange(instructions.Count - numInstrs, numInstrs);
|
||||||
fallThrough = target;
|
fallThrough = target;
|
||||||
target.sources.Add(this);
|
target.sources.Add(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void replaceLastNonBranchWithBranch(int numInstrs, Block target) {
|
public void ReplaceLastNonBranchWithBranch(int numInstrs, Block target) {
|
||||||
if (LastInstr.isBr())
|
if (LastInstr.IsBr())
|
||||||
numInstrs++;
|
numInstrs++;
|
||||||
replaceLastInstrsWithBranch(numInstrs, target);
|
ReplaceLastInstrsWithBranch(numInstrs, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void replaceBccWithBranch(bool isTaken) {
|
public void ReplaceBccWithBranch(bool isTaken) {
|
||||||
Block target = isTaken ? targets[0] : fallThrough;
|
Block target = isTaken ? targets[0] : fallThrough;
|
||||||
replaceLastInstrsWithBranch(1, target);
|
ReplaceLastInstrsWithBranch(1, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void replaceSwitchWithBranch(Block target) {
|
public void ReplaceSwitchWithBranch(Block target) {
|
||||||
if (LastInstr.OpCode.Code != Code.Switch)
|
if (LastInstr.OpCode.Code != Code.Switch)
|
||||||
throw new ApplicationException("Last instruction is not a switch");
|
throw new ApplicationException("Last instruction is not a switch");
|
||||||
replaceLastInstrsWithBranch(1, target);
|
ReplaceLastInstrsWithBranch(1, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNewFallThrough(Block newFallThrough) {
|
public void SetNewFallThrough(Block newFallThrough) {
|
||||||
disconnectFromFallThrough();
|
DisconnectFromFallThrough();
|
||||||
fallThrough = newFallThrough;
|
fallThrough = newFallThrough;
|
||||||
newFallThrough.sources.Add(this);
|
newFallThrough.sources.Add(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNewTarget(int index, Block newTarget) {
|
public void SetNewTarget(int index, Block newTarget) {
|
||||||
disconnectFromBlock(targets[index]);
|
DisconnectFromBlock(targets[index]);
|
||||||
targets[index] = newTarget;
|
targets[index] = newTarget;
|
||||||
newTarget.sources.Add(this);
|
newTarget.sources.Add(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeDeadBlock() {
|
public void RemoveDeadBlock() {
|
||||||
if (sources.Count != 0)
|
if (sources.Count != 0)
|
||||||
throw new ApplicationException("Trying to remove a non-dead block");
|
throw new ApplicationException("Trying to remove a non-dead block");
|
||||||
removeGuaranteedDeadBlock();
|
RemoveGuaranteedDeadBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes a block that has been guaranteed to be dead. This method won't verify
|
// Removes a block that has been guaranteed to be dead. This method won't verify
|
||||||
// that it really is dead.
|
// that it really is dead.
|
||||||
public void removeGuaranteedDeadBlock() {
|
public void RemoveGuaranteedDeadBlock() {
|
||||||
disconnectFromFallThroughAndTargets();
|
DisconnectFromFallThroughAndTargets();
|
||||||
Parent = null;
|
Parent = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
void disconnectFromFallThroughAndTargets() {
|
void DisconnectFromFallThroughAndTargets() {
|
||||||
disconnectFromFallThrough();
|
DisconnectFromFallThrough();
|
||||||
disconnectFromTargets();
|
DisconnectFromTargets();
|
||||||
}
|
}
|
||||||
|
|
||||||
void disconnectFromFallThrough() {
|
void DisconnectFromFallThrough() {
|
||||||
if (fallThrough != null) {
|
if (fallThrough != null) {
|
||||||
disconnectFromBlock(fallThrough);
|
DisconnectFromBlock(fallThrough);
|
||||||
fallThrough = null;
|
fallThrough = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void disconnectFromTargets() {
|
void DisconnectFromTargets() {
|
||||||
if (targets != null) {
|
if (targets != null) {
|
||||||
foreach (var target in targets)
|
foreach (var target in targets)
|
||||||
disconnectFromBlock(target);
|
DisconnectFromBlock(target);
|
||||||
targets = null;
|
targets = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void disconnectFromBlock(Block target) {
|
void DisconnectFromBlock(Block target) {
|
||||||
if (!target.sources.Remove(this))
|
if (!target.sources.Remove(this))
|
||||||
throw new ApplicationException("Could not remove the block from its target block");
|
throw new ApplicationException("Could not remove the block from its target block");
|
||||||
}
|
}
|
||||||
|
|
||||||
public int countTargets() {
|
public int CountTargets() {
|
||||||
int count = fallThrough != null ? 1 : 0;
|
int count = fallThrough != null ? 1 : 0;
|
||||||
if (targets != null)
|
if (targets != null)
|
||||||
count += targets.Count;
|
count += targets.Count;
|
||||||
|
@ -201,8 +201,8 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the target iff it has only ONE target. Else it returns null.
|
// Returns the target iff it has only ONE target. Else it returns null.
|
||||||
public Block getOnlyTarget() {
|
public Block GetOnlyTarget() {
|
||||||
if (countTargets() != 1)
|
if (CountTargets() != 1)
|
||||||
return null;
|
return null;
|
||||||
if (fallThrough != null)
|
if (fallThrough != null)
|
||||||
return fallThrough;
|
return fallThrough;
|
||||||
|
@ -210,7 +210,7 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns all targets. FallThrough (if not null) is always returned first!
|
// Returns all targets. FallThrough (if not null) is always returned first!
|
||||||
public IEnumerable<Block> getTargets() {
|
public IEnumerable<Block> GetTargets() {
|
||||||
if (fallThrough != null)
|
if (fallThrough != null)
|
||||||
yield return fallThrough;
|
yield return fallThrough;
|
||||||
if (targets != null) {
|
if (targets != null) {
|
||||||
|
@ -220,52 +220,52 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true iff other is the only block in Sources
|
// Returns true iff other is the only block in Sources
|
||||||
public bool isOnlySource(Block other) {
|
public bool IsOnlySource(Block other) {
|
||||||
return sources.Count == 1 && sources[0] == other;
|
return sources.Count == 1 && sources[0] == other;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if we can merge other with this
|
// Returns true if we can merge other with this
|
||||||
public bool canMerge(Block other) {
|
public bool CanMerge(Block other) {
|
||||||
return canAppend(other) && other.isOnlySource(this);
|
return CanAppend(other) && other.IsOnlySource(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge two blocks into one
|
// Merge two blocks into one
|
||||||
public void merge(Block other) {
|
public void Merge(Block other) {
|
||||||
if (!canMerge(other))
|
if (!CanMerge(other))
|
||||||
throw new ApplicationException("Can't merge the two blocks!");
|
throw new ApplicationException("Can't merge the two blocks!");
|
||||||
append(other);
|
Append(other);
|
||||||
other.disconnectFromFallThroughAndTargets();
|
other.DisconnectFromFallThroughAndTargets();
|
||||||
other.Parent = null;
|
other.Parent = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool canAppend(Block other) {
|
public bool CanAppend(Block other) {
|
||||||
if (other == null || other == this || getOnlyTarget() != other)
|
if (other == null || other == this || GetOnlyTarget() != other)
|
||||||
return false;
|
return false;
|
||||||
// If it's eg. a leave, then don't merge them since it clears the stack.
|
// If it's eg. a leave, then don't merge them since it clears the stack.
|
||||||
return LastInstr.isBr() || Instr.isFallThrough(LastInstr.OpCode);
|
return LastInstr.IsBr() || Instr.IsFallThrough(LastInstr.OpCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void append(Block other) {
|
public void Append(Block other) {
|
||||||
if (!canAppend(other))
|
if (!CanAppend(other))
|
||||||
throw new ApplicationException("Can't append the block!");
|
throw new ApplicationException("Can't append the block!");
|
||||||
|
|
||||||
removeLastBr(); // Get rid of last br/br.s if present
|
RemoveLastBr(); // Get rid of last br/br.s if present
|
||||||
|
|
||||||
var newInstructions = new List<Instr>(instructions.Count + other.instructions.Count);
|
var newInstructions = new List<Instr>(instructions.Count + other.instructions.Count);
|
||||||
addInstructions(newInstructions, instructions, false);
|
AddInstructions(newInstructions, instructions, false);
|
||||||
addInstructions(newInstructions, other.instructions, true);
|
AddInstructions(newInstructions, other.instructions, true);
|
||||||
instructions = newInstructions;
|
instructions = newInstructions;
|
||||||
|
|
||||||
disconnectFromFallThroughAndTargets();
|
DisconnectFromFallThroughAndTargets();
|
||||||
if (other.targets != null)
|
if (other.targets != null)
|
||||||
targets = new List<Block>(other.targets);
|
targets = new List<Block>(other.targets);
|
||||||
else
|
else
|
||||||
targets = null;
|
targets = null;
|
||||||
fallThrough = other.fallThrough;
|
fallThrough = other.fallThrough;
|
||||||
updateSources();
|
UpdateSources();
|
||||||
}
|
}
|
||||||
|
|
||||||
void addInstructions(IList<Instr> dest, IList<Instr> instrs, bool clone) {
|
void AddInstructions(IList<Instr> dest, IList<Instr> instrs, bool clone) {
|
||||||
for (int i = 0; i < instrs.Count; i++) {
|
for (int i = 0; i < instrs.Count; i++) {
|
||||||
var instr = instrs[i];
|
var instr = instrs[i];
|
||||||
if (instr.OpCode != OpCodes.Nop)
|
if (instr.OpCode != OpCodes.Nop)
|
||||||
|
@ -275,7 +275,7 @@ namespace de4dot.blocks {
|
||||||
|
|
||||||
// Update each target's Sources property. Must only be called if this isn't in the
|
// Update each target's Sources property. Must only be called if this isn't in the
|
||||||
// Sources list!
|
// Sources list!
|
||||||
public void updateSources() {
|
public void UpdateSources() {
|
||||||
if (fallThrough != null)
|
if (fallThrough != null)
|
||||||
fallThrough.sources.Add(this);
|
fallThrough.sources.Add(this);
|
||||||
if (targets != null) {
|
if (targets != null) {
|
||||||
|
@ -285,30 +285,30 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if it falls through
|
// Returns true if it falls through
|
||||||
public bool isFallThrough() {
|
public bool IsFallThrough() {
|
||||||
return targets == null && fallThrough != null;
|
return targets == null && fallThrough != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool canFlipConditionalBranch() {
|
public bool CanFlipConditionalBranch() {
|
||||||
return LastInstr.canFlipConditionalBranch();
|
return LastInstr.CanFlipConditionalBranch();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void flipConditionalBranch() {
|
public void FlipConditionalBranch() {
|
||||||
if (fallThrough == null || targets == null || targets.Count != 1)
|
if (fallThrough == null || targets == null || targets.Count != 1)
|
||||||
throw new ApplicationException("Invalid bcc block state");
|
throw new ApplicationException("Invalid bcc block state");
|
||||||
LastInstr.flipConditonalBranch();
|
LastInstr.FlipConditonalBranch();
|
||||||
var oldFallThrough = fallThrough;
|
var oldFallThrough = fallThrough;
|
||||||
fallThrough = targets[0];
|
fallThrough = targets[0];
|
||||||
targets[0] = oldFallThrough;
|
targets[0] = oldFallThrough;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if it's a conditional branch
|
// Returns true if it's a conditional branch
|
||||||
public bool isConditionalBranch() {
|
public bool IsConditionalBranch() {
|
||||||
return LastInstr.isConditionalBranch();
|
return LastInstr.IsConditionalBranch();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isNopBlock() {
|
public bool IsNopBlock() {
|
||||||
if (!isFallThrough())
|
if (!IsFallThrough())
|
||||||
return false;
|
return false;
|
||||||
foreach (var instr in instructions) {
|
foreach (var instr in instructions) {
|
||||||
if (instr.OpCode.Code != Code.Nop)
|
if (instr.OpCode.Code != Code.Nop)
|
||||||
|
|
|
@ -42,28 +42,28 @@ namespace de4dot.blocks {
|
||||||
|
|
||||||
public Blocks(MethodDef method) {
|
public Blocks(MethodDef method) {
|
||||||
this.method = method;
|
this.method = method;
|
||||||
updateBlocks();
|
UpdateBlocks();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateBlocks() {
|
public void UpdateBlocks() {
|
||||||
var body = method.Body;
|
var body = method.Body;
|
||||||
locals = body.Variables;
|
locals = body.Variables;
|
||||||
methodBlocks = new InstructionListParser(body.Instructions, body.ExceptionHandlers).parse();
|
methodBlocks = new InstructionListParser(body.Instructions, body.ExceptionHandlers).Parse();
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerable<ScopeBlock> getAllScopeBlocks(ScopeBlock scopeBlock) {
|
IEnumerable<ScopeBlock> GetAllScopeBlocks(ScopeBlock scopeBlock) {
|
||||||
var list = new List<ScopeBlock>();
|
var list = new List<ScopeBlock>();
|
||||||
list.Add(scopeBlock);
|
list.Add(scopeBlock);
|
||||||
list.AddRange(scopeBlock.getAllScopeBlocks());
|
list.AddRange(scopeBlock.GetAllScopeBlocks());
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int removeDeadBlocks() {
|
public int RemoveDeadBlocks() {
|
||||||
return new DeadBlocksRemover(methodBlocks).remove();
|
return new DeadBlocksRemover(methodBlocks).Remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void getCode(out IList<Instruction> allInstructions, out IList<ExceptionHandler> allExceptionHandlers) {
|
public void GetCode(out IList<Instruction> allInstructions, out IList<ExceptionHandler> allExceptionHandlers) {
|
||||||
new CodeGenerator(methodBlocks).getCode(out allInstructions, out allExceptionHandlers);
|
new CodeGenerator(methodBlocks).GetCode(out allInstructions, out allExceptionHandlers);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LocalVariableInfo {
|
struct LocalVariableInfo {
|
||||||
|
@ -75,12 +75,12 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int optimizeLocals() {
|
public int OptimizeLocals() {
|
||||||
if (locals.Count == 0)
|
if (locals.Count == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
var usedLocals = new Dictionary<Local, List<LocalVariableInfo>>();
|
var usedLocals = new Dictionary<Local, List<LocalVariableInfo>>();
|
||||||
foreach (var block in methodBlocks.getAllBlocks()) {
|
foreach (var block in methodBlocks.GetAllBlocks()) {
|
||||||
for (int i = 0; i < block.Instructions.Count; i++) {
|
for (int i = 0; i < block.Instructions.Count; i++) {
|
||||||
var instr = block.Instructions[i];
|
var instr = block.Instructions[i];
|
||||||
Local local;
|
Local local;
|
||||||
|
@ -97,7 +97,7 @@ namespace de4dot.blocks {
|
||||||
case Code.Stloc_1:
|
case Code.Stloc_1:
|
||||||
case Code.Stloc_2:
|
case Code.Stloc_2:
|
||||||
case Code.Stloc_3:
|
case Code.Stloc_3:
|
||||||
local = Instr.getLocalVar(locals, instr);
|
local = Instr.GetLocalVar(locals, instr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Code.Ldloca_S:
|
case Code.Ldloca_S:
|
||||||
|
@ -129,7 +129,7 @@ namespace de4dot.blocks {
|
||||||
newLocals.Add(local);
|
newLocals.Add(local);
|
||||||
newLocalsDict[local] = true;
|
newLocalsDict[local] = true;
|
||||||
foreach (var info in usedLocals[local])
|
foreach (var info in usedLocals[local])
|
||||||
info.block.Instructions[info.index] = new Instr(optimizeLocalInstr(info.block.Instructions[info.index], local, (uint)newIndex));
|
info.block.Instructions[info.index] = new Instr(OptimizeLocalInstr(info.block.Instructions[info.index], local, (uint)newIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
// We can't remove all locals. Locals that reference another assembly will
|
// We can't remove all locals. Locals that reference another assembly will
|
||||||
|
@ -162,7 +162,7 @@ namespace de4dot.blocks {
|
||||||
return numRemoved;
|
return numRemoved;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Instruction optimizeLocalInstr(Instr instr, Local local, uint newIndex) {
|
static Instruction OptimizeLocalInstr(Instr instr, Local local, uint newIndex) {
|
||||||
switch (instr.OpCode.Code) {
|
switch (instr.OpCode.Code) {
|
||||||
case Code.Ldloc:
|
case Code.Ldloc:
|
||||||
case Code.Ldloc_S:
|
case Code.Ldloc_S:
|
||||||
|
@ -211,11 +211,11 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void repartitionBlocks() {
|
public void RepartitionBlocks() {
|
||||||
mergeNopBlocks();
|
MergeNopBlocks();
|
||||||
foreach (var scopeBlock in getAllScopeBlocks(methodBlocks)) {
|
foreach (var scopeBlock in GetAllScopeBlocks(methodBlocks)) {
|
||||||
try {
|
try {
|
||||||
scopeBlock.repartitionBlocks();
|
scopeBlock.RepartitionBlocks();
|
||||||
}
|
}
|
||||||
catch (NullReferenceException) {
|
catch (NullReferenceException) {
|
||||||
//TODO: Send this message to the log
|
//TODO: Send this message to the log
|
||||||
|
@ -225,12 +225,12 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void mergeNopBlocks() {
|
void MergeNopBlocks() {
|
||||||
var allBlocks = methodBlocks.getAllBlocks();
|
var allBlocks = methodBlocks.GetAllBlocks();
|
||||||
|
|
||||||
var nopBlocks = new Dictionary<Block, bool>();
|
var nopBlocks = new Dictionary<Block, bool>();
|
||||||
foreach (var nopBlock in allBlocks) {
|
foreach (var nopBlock in allBlocks) {
|
||||||
if (nopBlock.isNopBlock())
|
if (nopBlock.IsNopBlock())
|
||||||
nopBlocks[nopBlock] = true;
|
nopBlocks[nopBlock] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,18 +243,18 @@ namespace de4dot.blocks {
|
||||||
foreach (var block in allBlocks) {
|
foreach (var block in allBlocks) {
|
||||||
Block nopBlockTarget;
|
Block nopBlockTarget;
|
||||||
|
|
||||||
nopBlockTarget = getNopBlockTarget(nopBlocks, block, block.FallThrough);
|
nopBlockTarget = GetNopBlockTarget(nopBlocks, block, block.FallThrough);
|
||||||
if (nopBlockTarget != null) {
|
if (nopBlockTarget != null) {
|
||||||
block.setNewFallThrough(nopBlockTarget);
|
block.SetNewFallThrough(nopBlockTarget);
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (block.Targets != null) {
|
if (block.Targets != null) {
|
||||||
for (int targetIndex = 0; targetIndex < block.Targets.Count; targetIndex++) {
|
for (int targetIndex = 0; targetIndex < block.Targets.Count; targetIndex++) {
|
||||||
nopBlockTarget = getNopBlockTarget(nopBlocks, block, block.Targets[targetIndex]);
|
nopBlockTarget = GetNopBlockTarget(nopBlocks, block, block.Targets[targetIndex]);
|
||||||
if (nopBlockTarget == null)
|
if (nopBlockTarget == null)
|
||||||
continue;
|
continue;
|
||||||
block.setNewTarget(targetIndex, nopBlockTarget);
|
block.SetNewTarget(targetIndex, nopBlockTarget);
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -265,10 +265,10 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var nopBlock in nopBlocks.Keys)
|
foreach (var nopBlock in nopBlocks.Keys)
|
||||||
nopBlock.Parent.removeDeadBlock(nopBlock);
|
nopBlock.Parent.RemoveDeadBlock(nopBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Block getNopBlockTarget(Dictionary<Block, bool> nopBlocks, Block source, Block nopBlock) {
|
static Block GetNopBlockTarget(Dictionary<Block, bool> nopBlocks, Block source, Block nopBlock) {
|
||||||
if (nopBlock == null || !nopBlocks.ContainsKey(nopBlock) || source == nopBlock.FallThrough)
|
if (nopBlock == null || !nopBlocks.ContainsKey(nopBlock) || source == nopBlock.FallThrough)
|
||||||
return null;
|
return null;
|
||||||
if (nopBlock.Parent.BaseBlocks[0] == nopBlock)
|
if (nopBlock.Parent.BaseBlocks[0] == nopBlock)
|
||||||
|
|
|
@ -34,7 +34,7 @@ namespace de4dot.blocks {
|
||||||
this.baseBlock = baseBlock;
|
this.baseBlock = baseBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool visited() {
|
public bool Visited() {
|
||||||
return dfsNumber >= 0;
|
return dfsNumber >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ namespace de4dot.blocks {
|
||||||
this.skipFirstBlock = skipFirstBlock;
|
this.skipFirstBlock = skipFirstBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<BaseBlock> sort() {
|
public List<BaseBlock> Sort() {
|
||||||
if (validBlocks.Count == 0)
|
if (validBlocks.Count == 0)
|
||||||
return new List<BaseBlock>();
|
return new List<BaseBlock>();
|
||||||
if (skipFirstBlock)
|
if (skipFirstBlock)
|
||||||
|
@ -77,14 +77,14 @@ namespace de4dot.blocks {
|
||||||
var finalList = new List<BaseBlock>(validBlocks.Count);
|
var finalList = new List<BaseBlock>(validBlocks.Count);
|
||||||
|
|
||||||
if (firstBlock is Block) {
|
if (firstBlock is Block) {
|
||||||
foreach (var target in getTargets(firstBlock)) {
|
foreach (var target in GetTargets(firstBlock)) {
|
||||||
visit(target);
|
Visit(target);
|
||||||
finalList.AddRange(sorted);
|
finalList.AddRange(sorted);
|
||||||
sorted.Clear();
|
sorted.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach (var bb in validBlocks) {
|
foreach (var bb in validBlocks) {
|
||||||
visit(bb);
|
Visit(bb);
|
||||||
finalList.AddRange(sorted);
|
finalList.AddRange(sorted);
|
||||||
sorted.Clear();
|
sorted.Clear();
|
||||||
}
|
}
|
||||||
|
@ -103,19 +103,19 @@ namespace de4dot.blocks {
|
||||||
return finalList;
|
return finalList;
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(BaseBlock bb) {
|
void Visit(BaseBlock bb) {
|
||||||
var info = getInfo(bb);
|
var info = GetInfo(bb);
|
||||||
if (info == null)
|
if (info == null)
|
||||||
return;
|
return;
|
||||||
if (info.baseBlock == firstBlock)
|
if (info.baseBlock == firstBlock)
|
||||||
return;
|
return;
|
||||||
if (info.visited())
|
if (info.Visited())
|
||||||
return;
|
return;
|
||||||
visit(info);
|
Visit(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockInfo getInfo(BaseBlock baseBlock) {
|
BlockInfo GetInfo(BaseBlock baseBlock) {
|
||||||
baseBlock = scopeBlock.toChild(baseBlock);
|
baseBlock = scopeBlock.ToChild(baseBlock);
|
||||||
if (baseBlock == null)
|
if (baseBlock == null)
|
||||||
return null;
|
return null;
|
||||||
BlockInfo info;
|
BlockInfo info;
|
||||||
|
@ -123,54 +123,54 @@ namespace de4dot.blocks {
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<BaseBlock> getTargets(BaseBlock baseBlock) {
|
List<BaseBlock> GetTargets(BaseBlock baseBlock) {
|
||||||
var list = new List<BaseBlock>();
|
var list = new List<BaseBlock>();
|
||||||
|
|
||||||
if (baseBlock is Block) {
|
if (baseBlock is Block) {
|
||||||
var block = (Block)baseBlock;
|
var block = (Block)baseBlock;
|
||||||
addTargets(list, block.getTargets());
|
AddTargets(list, block.GetTargets());
|
||||||
}
|
}
|
||||||
else if (baseBlock is TryBlock)
|
else if (baseBlock is TryBlock)
|
||||||
addTargets(list, (TryBlock)baseBlock);
|
AddTargets(list, (TryBlock)baseBlock);
|
||||||
else if (baseBlock is TryHandlerBlock)
|
else if (baseBlock is TryHandlerBlock)
|
||||||
addTargets(list, (TryHandlerBlock)baseBlock);
|
AddTargets(list, (TryHandlerBlock)baseBlock);
|
||||||
else
|
else
|
||||||
addTargets(list, (ScopeBlock)baseBlock);
|
AddTargets(list, (ScopeBlock)baseBlock);
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addTargets(List<BaseBlock> dest, TryBlock tryBlock) {
|
void AddTargets(List<BaseBlock> dest, TryBlock tryBlock) {
|
||||||
addTargets(dest, (ScopeBlock)tryBlock);
|
AddTargets(dest, (ScopeBlock)tryBlock);
|
||||||
foreach (var tryHandlerBlock in tryBlock.TryHandlerBlocks) {
|
foreach (var tryHandlerBlock in tryBlock.TryHandlerBlocks) {
|
||||||
dest.Add(tryHandlerBlock);
|
dest.Add(tryHandlerBlock);
|
||||||
addTargets(dest, tryHandlerBlock);
|
AddTargets(dest, tryHandlerBlock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void addTargets(List<BaseBlock> dest, TryHandlerBlock tryHandlerBlock) {
|
void AddTargets(List<BaseBlock> dest, TryHandlerBlock tryHandlerBlock) {
|
||||||
addTargets(dest, (ScopeBlock)tryHandlerBlock);
|
AddTargets(dest, (ScopeBlock)tryHandlerBlock);
|
||||||
|
|
||||||
dest.Add(tryHandlerBlock.FilterHandlerBlock);
|
dest.Add(tryHandlerBlock.FilterHandlerBlock);
|
||||||
addTargets(dest, tryHandlerBlock.FilterHandlerBlock);
|
AddTargets(dest, tryHandlerBlock.FilterHandlerBlock);
|
||||||
|
|
||||||
dest.Add(tryHandlerBlock.HandlerBlock);
|
dest.Add(tryHandlerBlock.HandlerBlock);
|
||||||
addTargets(dest, tryHandlerBlock.HandlerBlock);
|
AddTargets(dest, tryHandlerBlock.HandlerBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addTargets(List<BaseBlock> dest, ScopeBlock scopeBlock) {
|
void AddTargets(List<BaseBlock> dest, ScopeBlock scopeBlock) {
|
||||||
foreach (var block in scopeBlock.getAllBlocks())
|
foreach (var block in scopeBlock.GetAllBlocks())
|
||||||
addTargets(dest, block.getTargets());
|
AddTargets(dest, block.GetTargets());
|
||||||
}
|
}
|
||||||
|
|
||||||
void addTargets(List<BaseBlock> dest, IEnumerable<Block> source) {
|
void AddTargets(List<BaseBlock> dest, IEnumerable<Block> source) {
|
||||||
var list = new List<Block>(source);
|
var list = new List<Block>(source);
|
||||||
list.Reverse();
|
list.Reverse();
|
||||||
foreach (var block in list)
|
foreach (var block in list)
|
||||||
dest.Add(block);
|
dest.Add(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(BlockInfo info) {
|
void Visit(BlockInfo info) {
|
||||||
if (info.baseBlock == firstBlock)
|
if (info.baseBlock == firstBlock)
|
||||||
throw new ApplicationException("Can't visit firstBlock");
|
throw new ApplicationException("Can't visit firstBlock");
|
||||||
stack.Push(info);
|
stack.Push(info);
|
||||||
|
@ -179,15 +179,15 @@ namespace de4dot.blocks {
|
||||||
info.low = dfsNumber;
|
info.low = dfsNumber;
|
||||||
dfsNumber++;
|
dfsNumber++;
|
||||||
|
|
||||||
foreach (var tmp in getTargets(info.baseBlock)) {
|
foreach (var tmp in GetTargets(info.baseBlock)) {
|
||||||
var targetInfo = getInfo(tmp);
|
var targetInfo = GetInfo(tmp);
|
||||||
if (targetInfo == null)
|
if (targetInfo == null)
|
||||||
continue;
|
continue;
|
||||||
if (targetInfo.baseBlock == firstBlock)
|
if (targetInfo.baseBlock == firstBlock)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!targetInfo.visited()) {
|
if (!targetInfo.Visited()) {
|
||||||
visit(targetInfo);
|
Visit(targetInfo);
|
||||||
info.low = Math.Min(info.low, targetInfo.low);
|
info.low = Math.Min(info.low, targetInfo.low);
|
||||||
}
|
}
|
||||||
else if (targetInfo.onStack)
|
else if (targetInfo.onStack)
|
||||||
|
@ -206,8 +206,8 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
if (sccBlocks.Count > 1) {
|
if (sccBlocks.Count > 1) {
|
||||||
sccBlocks.Reverse();
|
sccBlocks.Reverse();
|
||||||
var result = new Sorter(scopeBlock, sccBlocks, true).sort();
|
var result = new Sorter(scopeBlock, sccBlocks, true).Sort();
|
||||||
sortLoopBlock(result);
|
SortLoopBlock(result);
|
||||||
sorted.InsertRange(0, result);
|
sorted.InsertRange(0, result);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -215,12 +215,12 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sortLoopBlock(List<BaseBlock> list) {
|
void SortLoopBlock(List<BaseBlock> list) {
|
||||||
// Some popular decompilers sometimes produce bad output unless the loop condition
|
// Some popular decompilers sometimes produce bad output unless the loop condition
|
||||||
// checker block is at the end of the loop. Eg., they may use a while loop when
|
// checker block is at the end of the loop. Eg., they may use a while loop when
|
||||||
// it's really a for/foreach loop.
|
// it's really a for/foreach loop.
|
||||||
|
|
||||||
var loopStart = getLoopStartBlock(list);
|
var loopStart = GetLoopStartBlock(list);
|
||||||
if (loopStart == null)
|
if (loopStart == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -229,7 +229,7 @@ namespace de4dot.blocks {
|
||||||
list.Add(loopStart);
|
list.Add(loopStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
Block getLoopStartBlock(List<BaseBlock> list) {
|
Block GetLoopStartBlock(List<BaseBlock> list) {
|
||||||
var loopBlocks = new Dictionary<Block, bool>(list.Count);
|
var loopBlocks = new Dictionary<Block, bool>(list.Count);
|
||||||
foreach (var bb in list) {
|
foreach (var bb in list) {
|
||||||
var block = bb as Block;
|
var block = bb as Block;
|
||||||
|
@ -268,9 +268,9 @@ namespace de4dot.blocks {
|
||||||
this.scopeBlock = scopeBlock;
|
this.scopeBlock = scopeBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<BaseBlock> sort() {
|
public List<BaseBlock> Sort() {
|
||||||
var sorted = new Sorter(scopeBlock, scopeBlock.BaseBlocks, false).sort();
|
var sorted = new Sorter(scopeBlock, scopeBlock.BaseBlocks, false).Sort();
|
||||||
return new ForwardScanOrder(scopeBlock, sorted).fix();
|
return new ForwardScanOrder(scopeBlock, sorted).Fix();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,11 +67,11 @@ namespace de4dot.blocks {
|
||||||
this.methodBlocks = methodBlocks;
|
this.methodBlocks = methodBlocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void getCode(out IList<Instruction> allInstructions, out IList<ExceptionHandler> allExceptionHandlers) {
|
public void GetCode(out IList<Instruction> allInstructions, out IList<ExceptionHandler> allExceptionHandlers) {
|
||||||
fixEmptyBlocks();
|
FixEmptyBlocks();
|
||||||
layOutBlocks();
|
LayOutBlocks();
|
||||||
sortExceptions();
|
SortExceptions();
|
||||||
layOutInstructions(out allInstructions, out allExceptionHandlers);
|
LayOutInstructions(out allInstructions, out allExceptionHandlers);
|
||||||
|
|
||||||
allInstructions.SimplifyBranches();
|
allInstructions.SimplifyBranches();
|
||||||
allInstructions.OptimizeBranches();
|
allInstructions.OptimizeBranches();
|
||||||
|
@ -87,7 +87,7 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void layOutInstructions(out IList<Instruction> allInstructions, out IList<ExceptionHandler> allExceptionHandlers) {
|
void LayOutInstructions(out IList<Instruction> allInstructions, out IList<ExceptionHandler> allExceptionHandlers) {
|
||||||
allInstructions = new List<Instruction>();
|
allInstructions = new List<Instruction>();
|
||||||
allExceptionHandlers = new List<ExceptionHandler>();
|
allExceptionHandlers = new List<ExceptionHandler>();
|
||||||
|
|
||||||
|
@ -103,20 +103,20 @@ namespace de4dot.blocks {
|
||||||
var targets = new List<Instr>();
|
var targets = new List<Instr>();
|
||||||
foreach (var target in block.Targets)
|
foreach (var target in block.Targets)
|
||||||
targets.Add(target.FirstInstr);
|
targets.Add(target.FirstInstr);
|
||||||
block.LastInstr.updateTargets(targets);
|
block.LastInstr.UpdateTargets(targets);
|
||||||
}
|
}
|
||||||
allInstructions.Add(block.LastInstr.Instruction);
|
allInstructions.Add(block.LastInstr.Instruction);
|
||||||
|
|
||||||
var next = i + 1 < blocks.Count ? blocks[i + 1] : null;
|
var next = i + 1 < blocks.Count ? blocks[i + 1] : null;
|
||||||
|
|
||||||
// If eg. ble next, then change it to bgt XYZ and fall through to next.
|
// If eg. ble next, then change it to bgt XYZ and fall through to next.
|
||||||
if (block.Targets != null && block.canFlipConditionalBranch() && block.Targets[0] == next) {
|
if (block.Targets != null && block.CanFlipConditionalBranch() && block.Targets[0] == next) {
|
||||||
block.flipConditionalBranch();
|
block.FlipConditionalBranch();
|
||||||
block.LastInstr.updateTargets(new List<Instr> { block.Targets[0].FirstInstr });
|
block.LastInstr.UpdateTargets(new List<Instr> { block.Targets[0].FirstInstr });
|
||||||
}
|
}
|
||||||
else if (block.FallThrough != null && block.FallThrough != next) {
|
else if (block.FallThrough != null && block.FallThrough != next) {
|
||||||
var instr = new Instr(OpCodes.Br.ToInstruction(block.FallThrough.FirstInstr.Instruction));
|
var instr = new Instr(OpCodes.Br.ToInstruction(block.FallThrough.FirstInstr.Instruction));
|
||||||
instr.updateTargets(new List<Instr> { block.FallThrough.FirstInstr });
|
instr.UpdateTargets(new List<Instr> { block.FallThrough.FirstInstr });
|
||||||
allInstructions.Add(instr.Instruction);
|
allInstructions.Add(instr.Instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,25 +126,25 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var ex in exceptions) {
|
foreach (var ex in exceptions) {
|
||||||
var tryStart = getBlockInfo(blockInfos, ex.tryStart).start;
|
var tryStart = GetBlockInfo(blockInfos, ex.tryStart).start;
|
||||||
var tryEnd = getBlockInfo(blockInfos, ex.tryEnd).end;
|
var tryEnd = GetBlockInfo(blockInfos, ex.tryEnd).end;
|
||||||
var filterStart = ex.filterStart == -1 ? -1 : getBlockInfo(blockInfos, ex.filterStart).start;
|
var filterStart = ex.filterStart == -1 ? -1 : GetBlockInfo(blockInfos, ex.filterStart).start;
|
||||||
var handlerStart = getBlockInfo(blockInfos, ex.handlerStart).start;
|
var handlerStart = GetBlockInfo(blockInfos, ex.handlerStart).start;
|
||||||
var handlerEnd = getBlockInfo(blockInfos, ex.handlerEnd).end;
|
var handlerEnd = GetBlockInfo(blockInfos, ex.handlerEnd).end;
|
||||||
|
|
||||||
var eh = new ExceptionHandler(ex.handlerType);
|
var eh = new ExceptionHandler(ex.handlerType);
|
||||||
eh.CatchType = ex.catchType;
|
eh.CatchType = ex.catchType;
|
||||||
eh.TryStart = getInstruction(allInstructions, tryStart);
|
eh.TryStart = GetInstruction(allInstructions, tryStart);
|
||||||
eh.TryEnd = getInstruction(allInstructions, tryEnd + 1);
|
eh.TryEnd = GetInstruction(allInstructions, tryEnd + 1);
|
||||||
eh.FilterStart = filterStart == -1 ? null : getInstruction(allInstructions, filterStart);
|
eh.FilterStart = filterStart == -1 ? null : GetInstruction(allInstructions, filterStart);
|
||||||
eh.HandlerStart = getInstruction(allInstructions, handlerStart);
|
eh.HandlerStart = GetInstruction(allInstructions, handlerStart);
|
||||||
eh.HandlerEnd = getInstruction(allInstructions, handlerEnd + 1);
|
eh.HandlerEnd = GetInstruction(allInstructions, handlerEnd + 1);
|
||||||
|
|
||||||
allExceptionHandlers.Add(eh);
|
allExceptionHandlers.Add(eh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static BlockInfo getBlockInfo(List<BlockInfo> blockInfos, int index) {
|
static BlockInfo GetBlockInfo(List<BlockInfo> blockInfos, int index) {
|
||||||
if (index >= blockInfos.Count)
|
if (index >= blockInfos.Count)
|
||||||
index = blockInfos.Count - 1;
|
index = blockInfos.Count - 1;
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
|
@ -152,13 +152,13 @@ namespace de4dot.blocks {
|
||||||
return blockInfos[index];
|
return blockInfos[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
static Instruction getInstruction(IList<Instruction> allInstructions, int i) {
|
static Instruction GetInstruction(IList<Instruction> allInstructions, int i) {
|
||||||
if (i < allInstructions.Count)
|
if (i < allInstructions.Count)
|
||||||
return allInstructions[i];
|
return allInstructions[i];
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sortExceptions() {
|
void SortExceptions() {
|
||||||
exceptions.Sort((a, b) => {
|
exceptions.Sort((a, b) => {
|
||||||
// Make sure nested try blocks are sorted before the outer try block.
|
// Make sure nested try blocks are sorted before the outer try block.
|
||||||
if (a.tryStart > b.tryStart) return -1; // a could be nested, but b is not
|
if (a.tryStart > b.tryStart) return -1; // a could be nested, but b is not
|
||||||
|
@ -184,8 +184,8 @@ namespace de4dot.blocks {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void fixEmptyBlocks() {
|
void FixEmptyBlocks() {
|
||||||
foreach (var block in methodBlocks.getAllBlocks()) {
|
foreach (var block in methodBlocks.GetAllBlocks()) {
|
||||||
if (block.Instructions.Count == 0) {
|
if (block.Instructions.Count == 0) {
|
||||||
block.Instructions.Add(new Instr(OpCodes.Nop.ToInstruction()));
|
block.Instructions.Add(new Instr(OpCodes.Nop.ToInstruction()));
|
||||||
}
|
}
|
||||||
|
@ -193,12 +193,12 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write all blocks to the blocks list
|
// Write all blocks to the blocks list
|
||||||
void layOutBlocks() {
|
void LayOutBlocks() {
|
||||||
if (methodBlocks.BaseBlocks.Count == 0)
|
if (methodBlocks.BaseBlocks.Count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
stateStack.Push(new BlockState(methodBlocks));
|
stateStack.Push(new BlockState(methodBlocks));
|
||||||
processBaseBlocks(methodBlocks.BaseBlocks, (block) => {
|
ProcessBaseBlocks(methodBlocks.BaseBlocks, (block) => {
|
||||||
return block.LastInstr.OpCode == OpCodes.Ret;
|
return block.LastInstr.OpCode == OpCodes.Ret;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -212,7 +212,7 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void processBaseBlocks(List<BaseBlock> lb, Func<Block, bool> placeLast) {
|
void ProcessBaseBlocks(List<BaseBlock> lb, Func<Block, bool> placeLast) {
|
||||||
var bbs = new List<BaseBlock>();
|
var bbs = new List<BaseBlock>();
|
||||||
int lastIndex = -1;
|
int lastIndex = -1;
|
||||||
for (int i = 0; i < lb.Count; i++) {
|
for (int i = 0; i < lb.Count; i++) {
|
||||||
|
@ -228,22 +228,22 @@ namespace de4dot.blocks {
|
||||||
bbs.Add(block);
|
bbs.Add(block);
|
||||||
}
|
}
|
||||||
foreach (var bb in bbs)
|
foreach (var bb in bbs)
|
||||||
doBaseBlock(bb);
|
DoBaseBlock(bb);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the BaseBlock's ScopeBlock. The return value is either current ScopeBlock,
|
// Returns the BaseBlock's ScopeBlock. The return value is either current ScopeBlock,
|
||||||
// the ScopeBlock one step below current (current one's child), or null.
|
// the ScopeBlock one step below current (current one's child), or null.
|
||||||
ScopeBlock getScopeBlock(BaseBlock bb) {
|
ScopeBlock GetScopeBlock(BaseBlock bb) {
|
||||||
BlockState current = stateStack.Peek();
|
BlockState current = stateStack.Peek();
|
||||||
|
|
||||||
if (current.scopeBlock.isOurBaseBlock(bb))
|
if (current.scopeBlock.IsOurBaseBlock(bb))
|
||||||
return current.scopeBlock;
|
return current.scopeBlock;
|
||||||
return (ScopeBlock)current.scopeBlock.toChild(bb);
|
return (ScopeBlock)current.scopeBlock.ToChild(bb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void doBaseBlock(BaseBlock bb) {
|
void DoBaseBlock(BaseBlock bb) {
|
||||||
BlockState current = stateStack.Peek();
|
BlockState current = stateStack.Peek();
|
||||||
ScopeBlock newOne = getScopeBlock(bb);
|
ScopeBlock newOne = GetScopeBlock(bb);
|
||||||
if (newOne == null)
|
if (newOne == null)
|
||||||
return; // Not a BaseBlock somewhere inside this ScopeBlock
|
return; // Not a BaseBlock somewhere inside this ScopeBlock
|
||||||
if (newOne != current.scopeBlock)
|
if (newOne != current.scopeBlock)
|
||||||
|
@ -257,13 +257,13 @@ namespace de4dot.blocks {
|
||||||
visited[bb] = true;
|
visited[bb] = true;
|
||||||
|
|
||||||
if (bb is Block)
|
if (bb is Block)
|
||||||
doBlock(bb as Block);
|
DoBlock(bb as Block);
|
||||||
else if (bb is TryBlock)
|
else if (bb is TryBlock)
|
||||||
doTryBlock(bb as TryBlock);
|
DoTryBlock(bb as TryBlock);
|
||||||
else if (bb is FilterHandlerBlock)
|
else if (bb is FilterHandlerBlock)
|
||||||
doFilterHandlerBlock(bb as FilterHandlerBlock);
|
DoFilterHandlerBlock(bb as FilterHandlerBlock);
|
||||||
else if (bb is HandlerBlock)
|
else if (bb is HandlerBlock)
|
||||||
doHandlerBlock(bb as HandlerBlock);
|
DoHandlerBlock(bb as HandlerBlock);
|
||||||
else if (bb is TryHandlerBlock) {
|
else if (bb is TryHandlerBlock) {
|
||||||
// The try handler block is usually after the try block, but sometimes it isn't...
|
// The try handler block is usually after the try block, but sometimes it isn't...
|
||||||
// Handle that case here.
|
// Handle that case here.
|
||||||
|
@ -274,14 +274,14 @@ namespace de4dot.blocks {
|
||||||
throw new ApplicationException("Invalid block found");
|
throw new ApplicationException("Invalid block found");
|
||||||
}
|
}
|
||||||
|
|
||||||
void doBlock(Block block) {
|
void DoBlock(Block block) {
|
||||||
blocks.Add(block);
|
blocks.Add(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
void doTryBlock(TryBlock tryBlock) {
|
void DoTryBlock(TryBlock tryBlock) {
|
||||||
var tryStart = blocks.Count;
|
var tryStart = blocks.Count;
|
||||||
stateStack.Push(new BlockState(tryBlock));
|
stateStack.Push(new BlockState(tryBlock));
|
||||||
processBaseBlocks(tryBlock.BaseBlocks, (block) => {
|
ProcessBaseBlocks(tryBlock.BaseBlocks, (block) => {
|
||||||
return block.LastInstr.OpCode == OpCodes.Leave ||
|
return block.LastInstr.OpCode == OpCodes.Leave ||
|
||||||
block.LastInstr.OpCode == OpCodes.Leave_S;
|
block.LastInstr.OpCode == OpCodes.Leave_S;
|
||||||
});
|
});
|
||||||
|
@ -298,10 +298,10 @@ namespace de4dot.blocks {
|
||||||
|
|
||||||
var filterStart = blocks.Count;
|
var filterStart = blocks.Count;
|
||||||
if (handlerBlock.FilterHandlerBlock.BaseBlocks != null)
|
if (handlerBlock.FilterHandlerBlock.BaseBlocks != null)
|
||||||
doBaseBlock(handlerBlock.FilterHandlerBlock);
|
DoBaseBlock(handlerBlock.FilterHandlerBlock);
|
||||||
|
|
||||||
var handlerStart = blocks.Count;
|
var handlerStart = blocks.Count;
|
||||||
doBaseBlock(handlerBlock.HandlerBlock);
|
DoBaseBlock(handlerBlock.HandlerBlock);
|
||||||
var handlerEnd = blocks.Count - 1;
|
var handlerEnd = blocks.Count - 1;
|
||||||
|
|
||||||
exceptions.Add(new ExceptionInfo(tryStart, tryEnd, filterStart, handlerStart, handlerEnd, handlerBlock.CatchType, handlerBlock.HandlerType));
|
exceptions.Add(new ExceptionInfo(tryStart, tryEnd, filterStart, handlerStart, handlerEnd, handlerBlock.CatchType, handlerBlock.HandlerType));
|
||||||
|
@ -310,17 +310,17 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void doFilterHandlerBlock(FilterHandlerBlock filterHandlerBlock) {
|
void DoFilterHandlerBlock(FilterHandlerBlock filterHandlerBlock) {
|
||||||
stateStack.Push(new BlockState(filterHandlerBlock));
|
stateStack.Push(new BlockState(filterHandlerBlock));
|
||||||
processBaseBlocks(filterHandlerBlock.BaseBlocks, (block) => {
|
ProcessBaseBlocks(filterHandlerBlock.BaseBlocks, (block) => {
|
||||||
return block.LastInstr.OpCode == OpCodes.Endfilter; // MUST end with endfilter!
|
return block.LastInstr.OpCode == OpCodes.Endfilter; // MUST end with endfilter!
|
||||||
});
|
});
|
||||||
stateStack.Pop();
|
stateStack.Pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void doHandlerBlock(HandlerBlock handlerBlock) {
|
void DoHandlerBlock(HandlerBlock handlerBlock) {
|
||||||
stateStack.Push(new BlockState(handlerBlock));
|
stateStack.Push(new BlockState(handlerBlock));
|
||||||
processBaseBlocks(handlerBlock.BaseBlocks, (block) => {
|
ProcessBaseBlocks(handlerBlock.BaseBlocks, (block) => {
|
||||||
return block.LastInstr.OpCode == OpCodes.Endfinally ||
|
return block.LastInstr.OpCode == OpCodes.Endfinally ||
|
||||||
block.LastInstr.OpCode == OpCodes.Leave ||
|
block.LastInstr.OpCode == OpCodes.Leave ||
|
||||||
block.LastInstr.OpCode == OpCodes.Leave_S;
|
block.LastInstr.OpCode == OpCodes.Leave_S;
|
||||||
|
|
|
@ -32,10 +32,10 @@ namespace de4dot.blocks {
|
||||||
this.methodBlocks = methodBlocks;
|
this.methodBlocks = methodBlocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int remove() {
|
public int Remove() {
|
||||||
addScopeBlock(methodBlocks);
|
AddScopeBlock(methodBlocks);
|
||||||
processAll();
|
ProcessAll();
|
||||||
return removeDeadBlocks();
|
return RemoveDeadBlocks();
|
||||||
}
|
}
|
||||||
|
|
||||||
class ScopeBlockInfo {
|
class ScopeBlockInfo {
|
||||||
|
@ -46,12 +46,12 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int removeDeadBlocks() {
|
int RemoveDeadBlocks() {
|
||||||
int numDeadBlocks = 0;
|
int numDeadBlocks = 0;
|
||||||
|
|
||||||
var infos = new Dictionary<ScopeBlock, ScopeBlockInfo>();
|
var infos = new Dictionary<ScopeBlock, ScopeBlockInfo>();
|
||||||
var deadBlocksDict = new Dictionary<BaseBlock, bool>();
|
var deadBlocksDict = new Dictionary<BaseBlock, bool>();
|
||||||
foreach (var baseBlock in findDeadBlocks()) {
|
foreach (var baseBlock in FindDeadBlocks()) {
|
||||||
deadBlocksDict[baseBlock] = true;
|
deadBlocksDict[baseBlock] = true;
|
||||||
ScopeBlock parent = baseBlock.Parent;
|
ScopeBlock parent = baseBlock.Parent;
|
||||||
ScopeBlockInfo info;
|
ScopeBlockInfo info;
|
||||||
|
@ -62,15 +62,15 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var info in infos.Values)
|
foreach (var info in infos.Values)
|
||||||
info.scopeBlock.removeAllDeadBlocks(info.deadBlocks, deadBlocksDict);
|
info.scopeBlock.RemoveAllDeadBlocks(info.deadBlocks, deadBlocksDict);
|
||||||
|
|
||||||
return numDeadBlocks;
|
return numDeadBlocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
IList<BaseBlock> findDeadBlocks() {
|
IList<BaseBlock> FindDeadBlocks() {
|
||||||
var deadBlocks = new List<BaseBlock>();
|
var deadBlocks = new List<BaseBlock>();
|
||||||
|
|
||||||
foreach (var bb in methodBlocks.getAllBaseBlocks()) {
|
foreach (var bb in methodBlocks.GetAllBaseBlocks()) {
|
||||||
if (!checkedBaseBlocks.ContainsKey(bb))
|
if (!checkedBaseBlocks.ContainsKey(bb))
|
||||||
deadBlocks.Add(bb);
|
deadBlocks.Add(bb);
|
||||||
}
|
}
|
||||||
|
@ -78,66 +78,66 @@ namespace de4dot.blocks {
|
||||||
return deadBlocks;
|
return deadBlocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addScopeBlock(ScopeBlock scopeBlock) {
|
void AddScopeBlock(ScopeBlock scopeBlock) {
|
||||||
scopeBlocksToCheck.Push(scopeBlock);
|
scopeBlocksToCheck.Push(scopeBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void processAll() {
|
void ProcessAll() {
|
||||||
bool didSomething;
|
bool didSomething;
|
||||||
do {
|
do {
|
||||||
didSomething = false;
|
didSomething = false;
|
||||||
while (baseBlocksToCheck.Count > 0) {
|
while (baseBlocksToCheck.Count > 0) {
|
||||||
processBaseBlock(baseBlocksToCheck.Pop());
|
ProcessBaseBlock(baseBlocksToCheck.Pop());
|
||||||
didSomething = true;
|
didSomething = true;
|
||||||
}
|
}
|
||||||
while (scopeBlocksToCheck.Count > 0) {
|
while (scopeBlocksToCheck.Count > 0) {
|
||||||
processScopeBlock(scopeBlocksToCheck.Pop());
|
ProcessScopeBlock(scopeBlocksToCheck.Pop());
|
||||||
didSomething = true;
|
didSomething = true;
|
||||||
}
|
}
|
||||||
} while (didSomething);
|
} while (didSomething);
|
||||||
}
|
}
|
||||||
|
|
||||||
void processBaseBlock(BaseBlock baseBlock) {
|
void ProcessBaseBlock(BaseBlock baseBlock) {
|
||||||
if (baseBlock == null || checkedBaseBlocks.ContainsKey(baseBlock))
|
if (baseBlock == null || checkedBaseBlocks.ContainsKey(baseBlock))
|
||||||
return;
|
return;
|
||||||
checkedBaseBlocks[baseBlock] = true;
|
checkedBaseBlocks[baseBlock] = true;
|
||||||
|
|
||||||
if (baseBlock is Block) {
|
if (baseBlock is Block) {
|
||||||
var block = (Block)baseBlock;
|
var block = (Block)baseBlock;
|
||||||
foreach (var block2 in block.getTargets())
|
foreach (var block2 in block.GetTargets())
|
||||||
addBaseBlock(block2);
|
AddBaseBlock(block2);
|
||||||
}
|
}
|
||||||
else if (baseBlock is ScopeBlock) {
|
else if (baseBlock is ScopeBlock) {
|
||||||
var scopeBlock = (ScopeBlock)baseBlock;
|
var scopeBlock = (ScopeBlock)baseBlock;
|
||||||
addScopeBlock(scopeBlock);
|
AddScopeBlock(scopeBlock);
|
||||||
if (scopeBlock.BaseBlocks != null && scopeBlock.BaseBlocks.Count > 0)
|
if (scopeBlock.BaseBlocks != null && scopeBlock.BaseBlocks.Count > 0)
|
||||||
addBaseBlock(scopeBlock.BaseBlocks[0]);
|
AddBaseBlock(scopeBlock.BaseBlocks[0]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw new ApplicationException(string.Format("Unknown BaseBlock type {0}", baseBlock.GetType()));
|
throw new ApplicationException(string.Format("Unknown BaseBlock type {0}", baseBlock.GetType()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a block to be processed later, including all its enclosing ScopeBlocks.
|
// Add a block to be processed later, including all its enclosing ScopeBlocks.
|
||||||
void addBaseBlock(BaseBlock baseBlock) {
|
void AddBaseBlock(BaseBlock baseBlock) {
|
||||||
for (BaseBlock bb = baseBlock; bb != null; bb = bb.Parent)
|
for (BaseBlock bb = baseBlock; bb != null; bb = bb.Parent)
|
||||||
baseBlocksToCheck.Push(bb);
|
baseBlocksToCheck.Push(bb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void processScopeBlock(ScopeBlock scopeBlock) {
|
void ProcessScopeBlock(ScopeBlock scopeBlock) {
|
||||||
if (scopeBlock == null || checkedScopeBlocks.ContainsKey(scopeBlock))
|
if (scopeBlock == null || checkedScopeBlocks.ContainsKey(scopeBlock))
|
||||||
return;
|
return;
|
||||||
checkedScopeBlocks[scopeBlock] = true;
|
checkedScopeBlocks[scopeBlock] = true;
|
||||||
addBaseBlock(scopeBlock);
|
AddBaseBlock(scopeBlock);
|
||||||
|
|
||||||
if (scopeBlock is TryBlock) {
|
if (scopeBlock is TryBlock) {
|
||||||
var tryBlock = (TryBlock)scopeBlock;
|
var tryBlock = (TryBlock)scopeBlock;
|
||||||
foreach (var handler in tryBlock.TryHandlerBlocks)
|
foreach (var handler in tryBlock.TryHandlerBlocks)
|
||||||
addScopeBlock(handler);
|
AddScopeBlock(handler);
|
||||||
}
|
}
|
||||||
else if (scopeBlock is TryHandlerBlock) {
|
else if (scopeBlock is TryHandlerBlock) {
|
||||||
var tryHandlerBlock = (TryHandlerBlock)scopeBlock;
|
var tryHandlerBlock = (TryHandlerBlock)scopeBlock;
|
||||||
addScopeBlock(tryHandlerBlock.FilterHandlerBlock);
|
AddScopeBlock(tryHandlerBlock.FilterHandlerBlock);
|
||||||
addScopeBlock(tryHandlerBlock.HandlerBlock);
|
AddScopeBlock(tryHandlerBlock.HandlerBlock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,18 +35,18 @@ namespace de4dot.blocks {
|
||||||
public class CallCounter {
|
public class CallCounter {
|
||||||
Dictionary<IMethod, int> calls = new Dictionary<IMethod, int>(MethodEqualityComparer.CompareDeclaringTypes);
|
Dictionary<IMethod, int> calls = new Dictionary<IMethod, int>(MethodEqualityComparer.CompareDeclaringTypes);
|
||||||
|
|
||||||
public void add(IMethod calledMethod) {
|
public void Add(IMethod calledMethod) {
|
||||||
int count;
|
int count;
|
||||||
calls.TryGetValue(calledMethod, out count);
|
calls.TryGetValue(calledMethod, out count);
|
||||||
calls[calledMethod] = count + 1;
|
calls[calledMethod] = count + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IMethod most() {
|
public IMethod Most() {
|
||||||
int numCalls;
|
int numCalls;
|
||||||
return most(out numCalls);
|
return Most(out numCalls);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IMethod most(out int numCalls) {
|
public IMethod Most(out int numCalls) {
|
||||||
IMethod method = null;
|
IMethod method = null;
|
||||||
int callCount = 0;
|
int callCount = 0;
|
||||||
foreach (var key in calls.Keys) {
|
foreach (var key in calls.Keys) {
|
||||||
|
@ -61,15 +61,15 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class DotNetUtils {
|
public static class DotNetUtils {
|
||||||
public static TypeDef getModuleType(ModuleDef module) {
|
public static TypeDef GetModuleType(ModuleDef module) {
|
||||||
return module.GlobalType;
|
return module.GlobalType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MethodDef getModuleTypeCctor(ModuleDef module) {
|
public static MethodDef GetModuleTypeCctor(ModuleDef module) {
|
||||||
return module.GlobalType.FindStaticConstructor();
|
return module.GlobalType.FindStaticConstructor();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool isEmpty(MethodDef method) {
|
public static bool IsEmpty(MethodDef method) {
|
||||||
if (method.Body == null)
|
if (method.Body == null)
|
||||||
return false;
|
return false;
|
||||||
foreach (var instr in method.Body.Instructions) {
|
foreach (var instr in method.Body.Instructions) {
|
||||||
|
@ -80,18 +80,18 @@ namespace de4dot.blocks {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool isEmptyObfuscated(MethodDef method) {
|
public static bool IsEmptyObfuscated(MethodDef method) {
|
||||||
if (method.Body == null)
|
if (method.Body == null)
|
||||||
return false;
|
return false;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
var instr = getInstruction(method.Body.Instructions, ref index);
|
var instr = GetInstruction(method.Body.Instructions, ref index);
|
||||||
if (instr == null || instr.OpCode.Code != Code.Ret)
|
if (instr == null || instr.OpCode.Code != Code.Ret)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FieldDef findFieldType(TypeDef typeDef, string typeName, bool isStatic) {
|
public static FieldDef FindFieldType(TypeDef typeDef, string typeName, bool isStatic) {
|
||||||
if (typeDef == null)
|
if (typeDef == null)
|
||||||
return null;
|
return null;
|
||||||
foreach (var field in typeDef.Fields) {
|
foreach (var field in typeDef.Fields) {
|
||||||
|
@ -101,11 +101,11 @@ namespace de4dot.blocks {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<MethodDef> findMethods(IEnumerable<MethodDef> methods, string returnType, string[] argsTypes) {
|
public static IEnumerable<MethodDef> FindMethods(IEnumerable<MethodDef> methods, string returnType, string[] argsTypes) {
|
||||||
return findMethods(methods, returnType, argsTypes, true);
|
return FindMethods(methods, returnType, argsTypes, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<MethodDef> findMethods(IEnumerable<MethodDef> methods, string returnType, string[] argsTypes, bool isStatic) {
|
public static IEnumerable<MethodDef> FindMethods(IEnumerable<MethodDef> methods, string returnType, string[] argsTypes, bool isStatic) {
|
||||||
foreach (var method in methods) {
|
foreach (var method in methods) {
|
||||||
var sig = method.MethodSig;
|
var sig = method.MethodSig;
|
||||||
if (sig == null || !method.HasBody || !sig.IsDefault)
|
if (sig == null || !method.HasBody || !sig.IsDefault)
|
||||||
|
@ -125,32 +125,32 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool isDelegate(IType type) {
|
public static bool IsDelegate(IType type) {
|
||||||
if (type == null)
|
if (type == null)
|
||||||
return false;
|
return false;
|
||||||
var fn = type.FullName;
|
var fn = type.FullName;
|
||||||
return fn == "System.Delegate" || fn == "System.MulticastDelegate";
|
return fn == "System.Delegate" || fn == "System.MulticastDelegate";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool derivesFromDelegate(TypeDef type) {
|
public static bool DerivesFromDelegate(TypeDef type) {
|
||||||
return type != null && isDelegate(type.BaseType);
|
return type != null && IsDelegate(type.BaseType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool isMethod(IMethod method, string returnType, string parameters) {
|
public static bool IsMethod(IMethod method, string returnType, string parameters) {
|
||||||
return method != null && method.FullName == returnType + " " + method.DeclaringType.FullName + "::" + method.Name + parameters;
|
return method != null && method.FullName == returnType + " " + method.DeclaringType.FullName + "::" + method.Name + parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string getDllName(string dll) {
|
public static string GetDllName(string dll) {
|
||||||
if (dll.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
|
if (dll.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
|
||||||
return dll.Substring(0, dll.Length - 4);
|
return dll.Substring(0, dll.Length - 4);
|
||||||
return dll;
|
return dll;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool hasPinvokeMethod(TypeDef type, string methodName) {
|
public static bool HasPinvokeMethod(TypeDef type, string methodName) {
|
||||||
return getPInvokeMethod(type, methodName) != null;
|
return GetPInvokeMethod(type, methodName) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MethodDef getPInvokeMethod(TypeDef type, string methodName) {
|
public static MethodDef GetPInvokeMethod(TypeDef type, string methodName) {
|
||||||
if (type == null)
|
if (type == null)
|
||||||
return null;
|
return null;
|
||||||
UTF8String mname = methodName;
|
UTF8String mname = methodName;
|
||||||
|
@ -163,69 +163,69 @@ namespace de4dot.blocks {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MethodDef getPInvokeMethod(TypeDef type, string dll, string funcName) {
|
public static MethodDef GetPInvokeMethod(TypeDef type, string dll, string funcName) {
|
||||||
foreach (var method in type.Methods) {
|
foreach (var method in type.Methods) {
|
||||||
if (isPinvokeMethod(method, dll, funcName))
|
if (IsPinvokeMethod(method, dll, funcName))
|
||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool isPinvokeMethod(MethodDef method, string dll, string funcName) {
|
public static bool IsPinvokeMethod(MethodDef method, string dll, string funcName) {
|
||||||
if (method == null)
|
if (method == null)
|
||||||
return false;
|
return false;
|
||||||
if (method.ImplMap == null || method.ImplMap.Name.String != funcName)
|
if (method.ImplMap == null || method.ImplMap.Name.String != funcName)
|
||||||
return false;
|
return false;
|
||||||
return getDllName(dll).Equals(getDllName(method.ImplMap.Module.Name.String), StringComparison.OrdinalIgnoreCase);
|
return GetDllName(dll).Equals(GetDllName(method.ImplMap.Module.Name.String), StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MethodDef getMethod(ModuleDefMD module, IMethod method) {
|
public static MethodDef GetMethod(ModuleDefMD module, IMethod method) {
|
||||||
if (method == null)
|
if (method == null)
|
||||||
return null;
|
return null;
|
||||||
return getMethod(module, method, method.DeclaringType);
|
return GetMethod(module, method, method.DeclaringType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MethodDef getMethod2(ModuleDefMD module, IMethod method) {
|
public static MethodDef GetMethod2(ModuleDefMD module, IMethod method) {
|
||||||
if (method == null)
|
if (method == null)
|
||||||
return null;
|
return null;
|
||||||
if (method is MethodDef)
|
if (method is MethodDef)
|
||||||
return (MethodDef)method;
|
return (MethodDef)method;
|
||||||
var git = method.DeclaringType.TryGetGenericInstSig();
|
var git = method.DeclaringType.TryGetGenericInstSig();
|
||||||
var dt = git == null ? method.DeclaringType : git.GenericType.TypeDefOrRef;
|
var dt = git == null ? method.DeclaringType : git.GenericType.TypeDefOrRef;
|
||||||
return getMethod(module, method, dt);
|
return GetMethod(module, method, dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
static MethodDef getMethod(ModuleDefMD module, IMethod method, ITypeDefOrRef declaringType) {
|
static MethodDef GetMethod(ModuleDefMD module, IMethod method, ITypeDefOrRef declaringType) {
|
||||||
if (method == null)
|
if (method == null)
|
||||||
return null;
|
return null;
|
||||||
if (method is MethodDef)
|
if (method is MethodDef)
|
||||||
return (MethodDef)method;
|
return (MethodDef)method;
|
||||||
return getMethod(getType(module, declaringType), method);
|
return GetMethod(GetType(module, declaringType), method);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MethodDef getMethod(TypeDef type, string returnType, string parameters) {
|
public static MethodDef GetMethod(TypeDef type, string returnType, string parameters) {
|
||||||
foreach (var method in type.Methods) {
|
foreach (var method in type.Methods) {
|
||||||
if (isMethod(method, returnType, parameters))
|
if (IsMethod(method, returnType, parameters))
|
||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MethodDef getMethod2(ModuleDef module, IMethod method) {
|
public static MethodDef GetMethod2(ModuleDef module, IMethod method) {
|
||||||
if (method == null)
|
if (method == null)
|
||||||
return null;
|
return null;
|
||||||
return getMethod(module, method, method.DeclaringType.ScopeType);
|
return GetMethod(module, method, method.DeclaringType.ScopeType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TypeDef getType(ModuleDef module, TypeSig type) {
|
public static TypeDef GetType(ModuleDef module, TypeSig type) {
|
||||||
type = type.RemovePinnedAndModifiers();
|
type = type.RemovePinnedAndModifiers();
|
||||||
var tdr = type as TypeDefOrRefSig;
|
var tdr = type as TypeDefOrRefSig;
|
||||||
if (tdr == null)
|
if (tdr == null)
|
||||||
return null;
|
return null;
|
||||||
return getType(module, tdr.TypeDefOrRef);
|
return GetType(module, tdr.TypeDefOrRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TypeDef getType(ModuleDef module, ITypeDefOrRef type) {
|
public static TypeDef GetType(ModuleDef module, ITypeDefOrRef type) {
|
||||||
var td = type as TypeDef;
|
var td = type as TypeDef;
|
||||||
if (td == null) {
|
if (td == null) {
|
||||||
var tr = type as TypeRef;
|
var tr = type as TypeRef;
|
||||||
|
@ -239,15 +239,15 @@ namespace de4dot.blocks {
|
||||||
return td != null && td.Module == module ? td : null;
|
return td != null && td.Module == module ? td : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MethodDef getMethod(ModuleDef module, IMethod method, ITypeDefOrRef declaringType) {
|
static MethodDef GetMethod(ModuleDef module, IMethod method, ITypeDefOrRef declaringType) {
|
||||||
if (method == null)
|
if (method == null)
|
||||||
return null;
|
return null;
|
||||||
if (method is MethodDef)
|
if (method is MethodDef)
|
||||||
return (MethodDef)method;
|
return (MethodDef)method;
|
||||||
return getMethod(getType(module, declaringType), method);
|
return GetMethod(GetType(module, declaringType), method);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MethodDef getMethod(TypeDef type, IMethod methodRef) {
|
public static MethodDef GetMethod(TypeDef type, IMethod methodRef) {
|
||||||
if (type == null || methodRef == null)
|
if (type == null || methodRef == null)
|
||||||
return null;
|
return null;
|
||||||
if (methodRef is MethodDef)
|
if (methodRef is MethodDef)
|
||||||
|
@ -255,7 +255,7 @@ namespace de4dot.blocks {
|
||||||
return type.FindMethod(methodRef.Name, methodRef.MethodSig);
|
return type.FindMethod(methodRef.Name, methodRef.MethodSig);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<MethodDef> getNormalMethods(TypeDef type) {
|
public static IEnumerable<MethodDef> GetNormalMethods(TypeDef type) {
|
||||||
foreach (var method in type.Methods) {
|
foreach (var method in type.Methods) {
|
||||||
if (method.HasImplMap)
|
if (method.HasImplMap)
|
||||||
continue;
|
continue;
|
||||||
|
@ -266,15 +266,15 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FieldDef getField(ModuleDef module, IField field) {
|
public static FieldDef GetField(ModuleDef module, IField field) {
|
||||||
if (field == null)
|
if (field == null)
|
||||||
return null;
|
return null;
|
||||||
if (field is FieldDef)
|
if (field is FieldDef)
|
||||||
return (FieldDef)field;
|
return (FieldDef)field;
|
||||||
return getField(getType(module, field.DeclaringType), field);
|
return GetField(GetType(module, field.DeclaringType), field);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FieldDef getField(TypeDef type, IField fieldRef) {
|
public static FieldDef GetField(TypeDef type, IField fieldRef) {
|
||||||
if (type == null || fieldRef == null)
|
if (type == null || fieldRef == null)
|
||||||
return null;
|
return null;
|
||||||
if (fieldRef is FieldDef)
|
if (fieldRef is FieldDef)
|
||||||
|
@ -282,7 +282,7 @@ namespace de4dot.blocks {
|
||||||
return type.FindField(fieldRef.Name, fieldRef.FieldSig);
|
return type.FindField(fieldRef.Name, fieldRef.FieldSig);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FieldDef getField(TypeDef type, string typeFullName) {
|
public static FieldDef GetField(TypeDef type, string typeFullName) {
|
||||||
if (type == null)
|
if (type == null)
|
||||||
return null;
|
return null;
|
||||||
foreach (var field in type.Fields) {
|
foreach (var field in type.Fields) {
|
||||||
|
@ -292,7 +292,7 @@ namespace de4dot.blocks {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<IMethod> getMethodCalls(MethodDef method) {
|
public static IEnumerable<IMethod> GetMethodCalls(MethodDef method) {
|
||||||
var list = new List<IMethod>();
|
var list = new List<IMethod>();
|
||||||
if (method.HasBody) {
|
if (method.HasBody) {
|
||||||
foreach (var instr in method.Body.Instructions) {
|
foreach (var instr in method.Body.Instructions) {
|
||||||
|
@ -304,7 +304,7 @@ namespace de4dot.blocks {
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool hasString(MethodDef method, string s) {
|
public static bool HasString(MethodDef method, string s) {
|
||||||
if (method == null || method.Body == null)
|
if (method == null || method.Body == null)
|
||||||
return false;
|
return false;
|
||||||
foreach (var instr in method.Body.Instructions) {
|
foreach (var instr in method.Body.Instructions) {
|
||||||
|
@ -314,7 +314,7 @@ namespace de4dot.blocks {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IList<string> getCodeStrings(MethodDef method) {
|
public static IList<string> GetCodeStrings(MethodDef method) {
|
||||||
var strings = new List<string>();
|
var strings = new List<string>();
|
||||||
if (method != null && method.Body != null) {
|
if (method != null && method.Body != null) {
|
||||||
foreach (var instr in method.Body.Instructions) {
|
foreach (var instr in method.Body.Instructions) {
|
||||||
|
@ -325,17 +325,17 @@ namespace de4dot.blocks {
|
||||||
return strings;
|
return strings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Resource getResource(ModuleDef module, string name) {
|
public static Resource GetResource(ModuleDef module, string name) {
|
||||||
return getResource(module, new List<string> { name });
|
return GetResource(module, new List<string> { name });
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Resource getResource(ModuleDef module, IEnumerable<string> strings) {
|
public static Resource GetResource(ModuleDef module, IEnumerable<string> strings) {
|
||||||
if (!module.HasResources)
|
if (!module.HasResources)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var resources = module.Resources;
|
var resources = module.Resources;
|
||||||
foreach (var tmp in strings) {
|
foreach (var tmp in strings) {
|
||||||
var resourceName = removeFromNullChar(tmp);
|
var resourceName = RemoveFromNullChar(tmp);
|
||||||
if (resourceName == null)
|
if (resourceName == null)
|
||||||
continue;
|
continue;
|
||||||
UTF8String name = resourceName;
|
UTF8String name = resourceName;
|
||||||
|
@ -348,7 +348,7 @@ namespace de4dot.blocks {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
static string removeFromNullChar(string s) {
|
static string RemoveFromNullChar(string s) {
|
||||||
int index = s.IndexOf((char)0);
|
int index = s.IndexOf((char)0);
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
return s;
|
return s;
|
||||||
|
@ -356,7 +356,7 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copies most things but not everything
|
// Copies most things but not everything
|
||||||
public static MethodDef clone(MethodDef method) {
|
public static MethodDef Clone(MethodDef method) {
|
||||||
var newMethod = new MethodDefUser(method.Name, method.MethodSig, method.ImplAttributes, method.Attributes);
|
var newMethod = new MethodDefUser(method.Name, method.MethodSig, method.ImplAttributes, method.Attributes);
|
||||||
newMethod.Rid = method.Rid;
|
newMethod.Rid = method.Rid;
|
||||||
newMethod.DeclaringType2 = method.DeclaringType;
|
newMethod.DeclaringType2 = method.DeclaringType;
|
||||||
|
@ -369,11 +369,11 @@ namespace de4dot.blocks {
|
||||||
newMethod.GenericParameters.Add(newGp);
|
newMethod.GenericParameters.Add(newGp);
|
||||||
}
|
}
|
||||||
newMethod.Body = new CilBody();
|
newMethod.Body = new CilBody();
|
||||||
copyBodyFromTo(method, newMethod);
|
CopyBodyFromTo(method, newMethod);
|
||||||
return newMethod;
|
return newMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void copyBody(MethodDef method, out IList<Instruction> instructions, out IList<ExceptionHandler> exceptionHandlers) {
|
public static void CopyBody(MethodDef method, out IList<Instruction> instructions, out IList<ExceptionHandler> exceptionHandlers) {
|
||||||
if (method == null || !method.HasBody) {
|
if (method == null || !method.HasBody) {
|
||||||
instructions = new List<Instruction>();
|
instructions = new List<Instruction>();
|
||||||
exceptionHandlers = new List<ExceptionHandler>();
|
exceptionHandlers = new List<ExceptionHandler>();
|
||||||
|
@ -384,7 +384,7 @@ namespace de4dot.blocks {
|
||||||
var oldExHandlers = method.Body.ExceptionHandlers;
|
var oldExHandlers = method.Body.ExceptionHandlers;
|
||||||
instructions = new List<Instruction>(oldInstrs.Count);
|
instructions = new List<Instruction>(oldInstrs.Count);
|
||||||
exceptionHandlers = new List<ExceptionHandler>(oldExHandlers.Count);
|
exceptionHandlers = new List<ExceptionHandler>(oldExHandlers.Count);
|
||||||
var oldToIndex = Utils.createObjectToIndexDictionary(oldInstrs);
|
var oldToIndex = Utils.CreateObjectToIndexDictionary(oldInstrs);
|
||||||
|
|
||||||
foreach (var oldInstr in oldInstrs)
|
foreach (var oldInstr in oldInstrs)
|
||||||
instructions.Add(oldInstr.Clone());
|
instructions.Add(oldInstr.Clone());
|
||||||
|
@ -404,24 +404,24 @@ namespace de4dot.blocks {
|
||||||
|
|
||||||
foreach (var oldEx in oldExHandlers) {
|
foreach (var oldEx in oldExHandlers) {
|
||||||
var newEx = new ExceptionHandler(oldEx.HandlerType) {
|
var newEx = new ExceptionHandler(oldEx.HandlerType) {
|
||||||
TryStart = getInstruction(instructions, oldToIndex, oldEx.TryStart),
|
TryStart = GetInstruction(instructions, oldToIndex, oldEx.TryStart),
|
||||||
TryEnd = getInstruction(instructions, oldToIndex, oldEx.TryEnd),
|
TryEnd = GetInstruction(instructions, oldToIndex, oldEx.TryEnd),
|
||||||
FilterStart = getInstruction(instructions, oldToIndex, oldEx.FilterStart),
|
FilterStart = GetInstruction(instructions, oldToIndex, oldEx.FilterStart),
|
||||||
HandlerStart = getInstruction(instructions, oldToIndex, oldEx.HandlerStart),
|
HandlerStart = GetInstruction(instructions, oldToIndex, oldEx.HandlerStart),
|
||||||
HandlerEnd = getInstruction(instructions, oldToIndex, oldEx.HandlerEnd),
|
HandlerEnd = GetInstruction(instructions, oldToIndex, oldEx.HandlerEnd),
|
||||||
CatchType = oldEx.CatchType,
|
CatchType = oldEx.CatchType,
|
||||||
};
|
};
|
||||||
exceptionHandlers.Add(newEx);
|
exceptionHandlers.Add(newEx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Instruction getInstruction(IList<Instruction> instructions, IDictionary<Instruction, int> instructionToIndex, Instruction instruction) {
|
static Instruction GetInstruction(IList<Instruction> instructions, IDictionary<Instruction, int> instructionToIndex, Instruction instruction) {
|
||||||
if (instruction == null)
|
if (instruction == null)
|
||||||
return null;
|
return null;
|
||||||
return instructions[instructionToIndex[instruction]];
|
return instructions[instructionToIndex[instruction]];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void restoreBody(MethodDef method, IEnumerable<Instruction> instructions, IEnumerable<ExceptionHandler> exceptionHandlers) {
|
public static void RestoreBody(MethodDef method, IEnumerable<Instruction> instructions, IEnumerable<ExceptionHandler> exceptionHandlers) {
|
||||||
if (method == null || method.Body == null)
|
if (method == null || method.Body == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -436,19 +436,19 @@ namespace de4dot.blocks {
|
||||||
bodyExceptionHandlers.Add(eh);
|
bodyExceptionHandlers.Add(eh);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void copyBodyFromTo(MethodDef fromMethod, MethodDef toMethod) {
|
public static void CopyBodyFromTo(MethodDef fromMethod, MethodDef toMethod) {
|
||||||
if (fromMethod == toMethod)
|
if (fromMethod == toMethod)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
IList<Instruction> instructions;
|
IList<Instruction> instructions;
|
||||||
IList<ExceptionHandler> exceptionHandlers;
|
IList<ExceptionHandler> exceptionHandlers;
|
||||||
copyBody(fromMethod, out instructions, out exceptionHandlers);
|
CopyBody(fromMethod, out instructions, out exceptionHandlers);
|
||||||
restoreBody(toMethod, instructions, exceptionHandlers);
|
RestoreBody(toMethod, instructions, exceptionHandlers);
|
||||||
copyLocalsFromTo(fromMethod, toMethod);
|
CopyLocalsFromTo(fromMethod, toMethod);
|
||||||
updateInstructionOperands(fromMethod, toMethod);
|
UpdateInstructionOperands(fromMethod, toMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void copyLocalsFromTo(MethodDef fromMethod, MethodDef toMethod) {
|
static void CopyLocalsFromTo(MethodDef fromMethod, MethodDef toMethod) {
|
||||||
var fromBody = fromMethod.Body;
|
var fromBody = fromMethod.Body;
|
||||||
var toBody = toMethod.Body;
|
var toBody = toMethod.Body;
|
||||||
|
|
||||||
|
@ -457,7 +457,7 @@ namespace de4dot.blocks {
|
||||||
toBody.Variables.Add(new Local(local.Type));
|
toBody.Variables.Add(new Local(local.Type));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void updateInstructionOperands(MethodDef fromMethod, MethodDef toMethod) {
|
static void UpdateInstructionOperands(MethodDef fromMethod, MethodDef toMethod) {
|
||||||
var fromBody = fromMethod.Body;
|
var fromBody = fromMethod.Body;
|
||||||
var toBody = toMethod.Body;
|
var toBody = toMethod.Body;
|
||||||
|
|
||||||
|
@ -481,7 +481,7 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string getCustomArgAsString(CustomAttribute cattr, int arg) {
|
public static string GetCustomArgAsString(CustomAttribute cattr, int arg) {
|
||||||
if (cattr == null || arg >= cattr.ConstructorArguments.Count)
|
if (cattr == null || arg >= cattr.ConstructorArguments.Count)
|
||||||
return null;
|
return null;
|
||||||
var carg = cattr.ConstructorArguments[arg];
|
var carg = cattr.ConstructorArguments[arg];
|
||||||
|
@ -490,7 +490,7 @@ namespace de4dot.blocks {
|
||||||
return UTF8String.ToSystemStringOrEmpty((UTF8String)carg.Value);
|
return UTF8String.ToSystemStringOrEmpty((UTF8String)carg.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<MethodDef> getCalledMethods(ModuleDef module, MethodDef method) {
|
public static IEnumerable<MethodDef> GetCalledMethods(ModuleDef module, MethodDef method) {
|
||||||
if (method != null && method.HasBody) {
|
if (method != null && method.HasBody) {
|
||||||
foreach (var call in method.Body.Instructions) {
|
foreach (var call in method.Body.Instructions) {
|
||||||
if (call.OpCode.Code != Code.Call && call.OpCode.Code != Code.Callvirt)
|
if (call.OpCode.Code != Code.Call && call.OpCode.Code != Code.Callvirt)
|
||||||
|
@ -498,15 +498,15 @@ namespace de4dot.blocks {
|
||||||
var methodRef = call.Operand as IMethod;
|
var methodRef = call.Operand as IMethod;
|
||||||
if (methodRef == null)
|
if (methodRef == null)
|
||||||
continue;
|
continue;
|
||||||
var type = getType(module, methodRef.DeclaringType);
|
var type = GetType(module, methodRef.DeclaringType);
|
||||||
var methodDef = getMethod(type, methodRef);
|
var methodDef = GetMethod(type, methodRef);
|
||||||
if (methodDef != null)
|
if (methodDef != null)
|
||||||
yield return methodDef;
|
yield return methodDef;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IList<Instruction> getInstructions(IList<Instruction> instructions, int i, params OpCode[] opcodes) {
|
public static IList<Instruction> GetInstructions(IList<Instruction> instructions, int i, params OpCode[] opcodes) {
|
||||||
if (i + opcodes.Length > instructions.Count)
|
if (i + opcodes.Length > instructions.Count)
|
||||||
return null;
|
return null;
|
||||||
if (opcodes.Length == 0)
|
if (opcodes.Length == 0)
|
||||||
|
@ -524,25 +524,25 @@ namespace de4dot.blocks {
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool hasReturnValue(IMethod method) {
|
public static bool HasReturnValue(IMethod method) {
|
||||||
if (method == null || method.MethodSig == null || method.MethodSig.RetType == null)
|
if (method == null || method.MethodSig == null || method.MethodSig.RetType == null)
|
||||||
return false;
|
return false;
|
||||||
return method.MethodSig.RetType.RemovePinnedAndModifiers().ElementType != ElementType.Void;
|
return method.MethodSig.RetType.RemovePinnedAndModifiers().ElementType != ElementType.Void;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Parameter getParameter(IList<Parameter> parameters, int index) {
|
public static Parameter GetParameter(IList<Parameter> parameters, int index) {
|
||||||
if (0 <= index && index < parameters.Count)
|
if (0 <= index && index < parameters.Count)
|
||||||
return parameters[index];
|
return parameters[index];
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TypeSig getArg(IList<TypeSig> args, int index) {
|
public static TypeSig GetArg(IList<TypeSig> args, int index) {
|
||||||
if (0 <= index && index < args.Count)
|
if (0 <= index && index < args.Count)
|
||||||
return args[index];
|
return args[index];
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<TypeSig> getArgs(IMethod method) {
|
public static List<TypeSig> GetArgs(IMethod method) {
|
||||||
var sig = method.MethodSig;
|
var sig = method.MethodSig;
|
||||||
var args = new List<TypeSig>(sig.Params.Count + 1);
|
var args = new List<TypeSig>(sig.Params.Count + 1);
|
||||||
if (sig.ImplicitThis)
|
if (sig.ImplicitThis)
|
||||||
|
@ -552,7 +552,7 @@ namespace de4dot.blocks {
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getArgsCount(IMethod method) {
|
public static int GetArgsCount(IMethod method) {
|
||||||
var sig = method.MethodSig;
|
var sig = method.MethodSig;
|
||||||
if (sig == null)
|
if (sig == null)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -562,22 +562,22 @@ namespace de4dot.blocks {
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IList<TypeSig> replaceGenericParameters(GenericInstSig typeOwner, MethodSpec methodOwner, IList<TypeSig> types) {
|
public static IList<TypeSig> ReplaceGenericParameters(GenericInstSig typeOwner, MethodSpec methodOwner, IList<TypeSig> types) {
|
||||||
if (typeOwner == null && methodOwner == null)
|
if (typeOwner == null && methodOwner == null)
|
||||||
return types;
|
return types;
|
||||||
for (int i = 0; i < types.Count; i++)
|
for (int i = 0; i < types.Count; i++)
|
||||||
types[i] = getGenericArgument(typeOwner, methodOwner, types[i]);
|
types[i] = GetGenericArgument(typeOwner, methodOwner, types[i]);
|
||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TypeSig getGenericArgument(GenericInstSig typeOwner, MethodSpec methodOwner, TypeSig type) {
|
public static TypeSig GetGenericArgument(GenericInstSig typeOwner, MethodSpec methodOwner, TypeSig type) {
|
||||||
var typeArgs = typeOwner == null ? null : typeOwner.GenericArguments;
|
var typeArgs = typeOwner == null ? null : typeOwner.GenericArguments;
|
||||||
var genMethodArgs = methodOwner == null || methodOwner.GenericInstMethodSig == null ?
|
var genMethodArgs = methodOwner == null || methodOwner.GenericInstMethodSig == null ?
|
||||||
null : methodOwner.GenericInstMethodSig.GenericArguments;
|
null : methodOwner.GenericInstMethodSig.GenericArguments;
|
||||||
return GenericArgsSubstitutor.create(type, typeArgs, genMethodArgs);
|
return GenericArgsSubstitutor.Create(type, typeArgs, genMethodArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Instruction getInstruction(IList<Instruction> instructions, ref int index) {
|
public static Instruction GetInstruction(IList<Instruction> instructions, ref int index) {
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
if (index < 0 || index >= instructions.Count)
|
if (index < 0 || index >= instructions.Count)
|
||||||
return null;
|
return null;
|
||||||
|
@ -596,7 +596,7 @@ namespace de4dot.blocks {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TypeDefOrRefSig findOrCreateTypeRef(ModuleDef module, AssemblyRef asmRef, string ns, string name, bool isValueType) {
|
public static TypeDefOrRefSig FindOrCreateTypeRef(ModuleDef module, AssemblyRef asmRef, string ns, string name, bool isValueType) {
|
||||||
var typeRef = module.UpdateRowId(new TypeRefUser(module, ns, name, asmRef));
|
var typeRef = module.UpdateRowId(new TypeRefUser(module, ns, name, asmRef));
|
||||||
if (isValueType)
|
if (isValueType)
|
||||||
return new ValueTypeSig(typeRef);
|
return new ValueTypeSig(typeRef);
|
||||||
|
@ -604,7 +604,7 @@ namespace de4dot.blocks {
|
||||||
return new ClassSig(typeRef);
|
return new ClassSig(typeRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FrameworkType getFrameworkType(ModuleDefMD module) {
|
public static FrameworkType GetFrameworkType(ModuleDefMD module) {
|
||||||
foreach (var modRef in module.GetAssemblyRefs()) {
|
foreach (var modRef in module.GetAssemblyRefs()) {
|
||||||
if (modRef.Name != "mscorlib")
|
if (modRef.Name != "mscorlib")
|
||||||
continue;
|
continue;
|
||||||
|
@ -627,7 +627,7 @@ namespace de4dot.blocks {
|
||||||
return FrameworkType.Unknown;
|
return FrameworkType.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getMethodCalls(MethodDef method, string methodFullName) {
|
public static int GetMethodCalls(MethodDef method, string methodFullName) {
|
||||||
if (method == null || method.Body == null)
|
if (method == null || method.Body == null)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -645,7 +645,7 @@ namespace de4dot.blocks {
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool callsMethod(MethodDef method, string methodFullName) {
|
public static bool CallsMethod(MethodDef method, string methodFullName) {
|
||||||
if (method == null || method.Body == null)
|
if (method == null || method.Body == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -662,25 +662,25 @@ namespace de4dot.blocks {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool callsMethod(MethodDef method, string returnType, string parameters) {
|
public static bool CallsMethod(MethodDef method, string returnType, string parameters) {
|
||||||
if (method == null || method.Body == null)
|
if (method == null || method.Body == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
foreach (var instr in method.Body.Instructions) {
|
foreach (var instr in method.Body.Instructions) {
|
||||||
if (instr.OpCode.Code != Code.Call && instr.OpCode.Code != Code.Callvirt && instr.OpCode.Code != Code.Newobj)
|
if (instr.OpCode.Code != Code.Call && instr.OpCode.Code != Code.Callvirt && instr.OpCode.Code != Code.Newobj)
|
||||||
continue;
|
continue;
|
||||||
if (isMethod(instr.Operand as IMethod, returnType, parameters))
|
if (IsMethod(instr.Operand as IMethod, returnType, parameters))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IList<Instruction> getArgPushes(IList<Instruction> instrs, int index) {
|
public static IList<Instruction> GetArgPushes(IList<Instruction> instrs, int index) {
|
||||||
return getArgPushes(instrs, ref index);
|
return GetArgPushes(instrs, ref index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IList<Instruction> getArgPushes(IList<Instruction> instrs, ref int index) {
|
public static IList<Instruction> GetArgPushes(IList<Instruction> instrs, ref int index) {
|
||||||
if (index < 0 || index >= instrs.Count)
|
if (index < 0 || index >= instrs.Count)
|
||||||
return null;
|
return null;
|
||||||
var startInstr = instrs[index];
|
var startInstr = instrs[index];
|
||||||
|
@ -707,7 +707,7 @@ namespace de4dot.blocks {
|
||||||
|
|
||||||
if (pops != 0) {
|
if (pops != 0) {
|
||||||
index++;
|
index++;
|
||||||
if (getArgPushes(instrs, ref index) == null)
|
if (GetArgPushes(instrs, ref index) == null)
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,21 +31,21 @@ namespace de4dot.blocks {
|
||||||
get { return methods.Count; }
|
get { return methods.Count; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(uint token, DumpedMethod info) {
|
public void Add(uint token, DumpedMethod info) {
|
||||||
methods[token] = info;
|
methods[token] = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DumpedMethod get(MethodDef method) {
|
public DumpedMethod Get(MethodDef method) {
|
||||||
return get(method.MDToken.ToUInt32());
|
return Get(method.MDToken.ToUInt32());
|
||||||
}
|
}
|
||||||
|
|
||||||
public DumpedMethod get(uint token) {
|
public DumpedMethod Get(uint token) {
|
||||||
DumpedMethod dm;
|
DumpedMethod dm;
|
||||||
methods.TryGetValue(token, out dm);
|
methods.TryGetValue(token, out dm);
|
||||||
return dm;
|
return dm;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(DumpedMethod dm) {
|
public void Add(DumpedMethod dm) {
|
||||||
if (MDToken.ToTable(dm.token) != Table.Method || MDToken.ToRID(dm.token) == 0)
|
if (MDToken.ToTable(dm.token) != Table.Method || MDToken.ToRID(dm.token) == 0)
|
||||||
throw new ArgumentException("Invalid token");
|
throw new ArgumentException("Invalid token");
|
||||||
methods[dm.token] = dm;
|
methods[dm.token] = dm;
|
||||||
|
|
|
@ -41,7 +41,7 @@ namespace de4dot.blocks {
|
||||||
this.stackStart = stackStart;
|
this.stackStart = stackStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void calculateStackUsage() {
|
public void CalculateStackUsage() {
|
||||||
Block block = baseBlock as Block;
|
Block block = baseBlock as Block;
|
||||||
if (block == null) {
|
if (block == null) {
|
||||||
stackEnd = stackStart;
|
stackEnd = stackStart;
|
||||||
|
@ -60,17 +60,17 @@ namespace de4dot.blocks {
|
||||||
this.sorted = sorted;
|
this.sorted = sorted;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<BaseBlock> fix() {
|
public List<BaseBlock> Fix() {
|
||||||
createBlockInfos();
|
CreateBlockInfos();
|
||||||
createNewList();
|
CreateNewList();
|
||||||
return newList;
|
return newList;
|
||||||
}
|
}
|
||||||
|
|
||||||
void createBlockInfos() {
|
void CreateBlockInfos() {
|
||||||
int firstBlockStackStart = scopeBlock is TryHandlerBlock ? 1 : 0;
|
int firstBlockStackStart = scopeBlock is TryHandlerBlock ? 1 : 0;
|
||||||
foreach (var bb in getStartBlocks()) {
|
foreach (var bb in GetStartBlocks()) {
|
||||||
int stackStart = ReferenceEquals(bb, sorted[0]) ? firstBlockStackStart : 0;
|
int stackStart = ReferenceEquals(bb, sorted[0]) ? firstBlockStackStart : 0;
|
||||||
scanBaseBlock(bb, stackStart);
|
ScanBaseBlock(bb, stackStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
// One reason for this to fail is if there are still dead blocks left. Could also
|
// One reason for this to fail is if there are still dead blocks left. Could also
|
||||||
|
@ -79,29 +79,29 @@ namespace de4dot.blocks {
|
||||||
throw new ApplicationException(string.Format("Didn't add all blocks: {0} vs {1}", blockInfos.Count, sorted.Count));
|
throw new ApplicationException(string.Format("Didn't add all blocks: {0} vs {1}", blockInfos.Count, sorted.Count));
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerable<BaseBlock> getStartBlocks() {
|
IEnumerable<BaseBlock> GetStartBlocks() {
|
||||||
if (sorted.Count > 0) {
|
if (sorted.Count > 0) {
|
||||||
yield return sorted[0];
|
yield return sorted[0];
|
||||||
foreach (var bb in sorted) {
|
foreach (var bb in sorted) {
|
||||||
if (ReferenceEquals(bb, sorted[0]))
|
if (ReferenceEquals(bb, sorted[0]))
|
||||||
continue;
|
continue;
|
||||||
var block = bb as Block;
|
var block = bb as Block;
|
||||||
if (block == null || block.Sources == null || isOneSourceInAnotherScopeBlock(block))
|
if (block == null || block.Sources == null || IsOneSourceInAnotherScopeBlock(block))
|
||||||
yield return bb;
|
yield return bb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isOneSourceInAnotherScopeBlock(Block block) {
|
bool IsOneSourceInAnotherScopeBlock(Block block) {
|
||||||
foreach (var source in block.Sources) {
|
foreach (var source in block.Sources) {
|
||||||
if (!scopeBlock.isOurBaseBlock(source))
|
if (!scopeBlock.IsOurBaseBlock(source))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void scanBaseBlock(BaseBlock bb, int stackStart) {
|
void ScanBaseBlock(BaseBlock bb, int stackStart) {
|
||||||
if (blockInfos.ContainsKey(bb) || !scopeBlock.isOurBaseBlock(bb))
|
if (blockInfos.ContainsKey(bb) || !scopeBlock.IsOurBaseBlock(bb))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var blockInfo = new BlockInfo(bb, stackStart);
|
var blockInfo = new BlockInfo(bb, stackStart);
|
||||||
|
@ -115,38 +115,38 @@ namespace de4dot.blocks {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
blockInfo.calculateStackUsage();
|
blockInfo.CalculateStackUsage();
|
||||||
|
|
||||||
foreach (var target in block.getTargets())
|
foreach (var target in block.GetTargets())
|
||||||
scanBaseBlock(target, blockInfo.stackEnd);
|
ScanBaseBlock(target, blockInfo.stackEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void createNewList() {
|
void CreateNewList() {
|
||||||
newList = new List<BaseBlock>(sorted.Count);
|
newList = new List<BaseBlock>(sorted.Count);
|
||||||
foreach (var bb in sorted)
|
foreach (var bb in sorted)
|
||||||
addToNewList(bb);
|
AddToNewList(bb);
|
||||||
if (newList.Count != sorted.Count)
|
if (newList.Count != sorted.Count)
|
||||||
throw new ApplicationException(string.Format("Too many/few blocks after sorting: {0} vs {1}", newList.Count, sorted.Count));
|
throw new ApplicationException(string.Format("Too many/few blocks after sorting: {0} vs {1}", newList.Count, sorted.Count));
|
||||||
if (newList.Count > 0 && !ReferenceEquals(newList[0], sorted[0]))
|
if (newList.Count > 0 && !ReferenceEquals(newList[0], sorted[0]))
|
||||||
throw new ApplicationException("Start block is not first block after sorting");
|
throw new ApplicationException("Start block is not first block after sorting");
|
||||||
}
|
}
|
||||||
|
|
||||||
void addToNewList(BaseBlock bb) {
|
void AddToNewList(BaseBlock bb) {
|
||||||
if (inNewList.ContainsKey(bb) || !scopeBlock.isOurBaseBlock(bb))
|
if (inNewList.ContainsKey(bb) || !scopeBlock.IsOurBaseBlock(bb))
|
||||||
return;
|
return;
|
||||||
inNewList[bb] = false;
|
inNewList[bb] = false;
|
||||||
|
|
||||||
var blockInfo = blockInfos[bb];
|
var blockInfo = blockInfos[bb];
|
||||||
var block = bb as Block;
|
var block = bb as Block;
|
||||||
if (blockInfo.stackStart == 0 || ReferenceEquals(bb, sorted[0]) ||
|
if (blockInfo.stackStart == 0 || ReferenceEquals(bb, sorted[0]) ||
|
||||||
block == null || block.Sources == null || isInNewList(block.Sources)) {
|
block == null || block.Sources == null || IsInNewList(block.Sources)) {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
foreach (var source in block.Sources) {
|
foreach (var source in block.Sources) {
|
||||||
if (!scopeBlock.isOurBaseBlock(source))
|
if (!scopeBlock.IsOurBaseBlock(source))
|
||||||
continue;
|
continue;
|
||||||
int oldCount = newList.Count;
|
int oldCount = newList.Count;
|
||||||
addToNewList(source); // Make sure it's before this block
|
AddToNewList(source); // Make sure it's before this block
|
||||||
if (oldCount != newList.Count)
|
if (oldCount != newList.Count)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -156,7 +156,7 @@ namespace de4dot.blocks {
|
||||||
newList.Add(bb);
|
newList.Add(bb);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isInNewList(IEnumerable<Block> blocks) {
|
bool IsInNewList(IEnumerable<Block> blocks) {
|
||||||
foreach (var block in blocks) {
|
foreach (var block in blocks) {
|
||||||
if (inNewList.ContainsKey(block) && inNewList[block])
|
if (inNewList.ContainsKey(block) && inNewList[block])
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -26,115 +26,115 @@ namespace de4dot.blocks {
|
||||||
IList<TypeSig> genericMethodArgs;
|
IList<TypeSig> genericMethodArgs;
|
||||||
bool updated;
|
bool updated;
|
||||||
|
|
||||||
public static ITypeDefOrRef create(ITypeDefOrRef type, GenericInstSig git) {
|
public static ITypeDefOrRef Create(ITypeDefOrRef type, GenericInstSig git) {
|
||||||
if (git == null)
|
if (git == null)
|
||||||
return type;
|
return type;
|
||||||
return create(type, git.GenericArguments);
|
return Create(type, git.GenericArguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ITypeDefOrRef create(ITypeDefOrRef type, IList<TypeSig> genericArgs) {
|
public static ITypeDefOrRef Create(ITypeDefOrRef type, IList<TypeSig> genericArgs) {
|
||||||
if (genericArgs == null || genericArgs.Count == 0)
|
if (genericArgs == null || genericArgs.Count == 0)
|
||||||
return type;
|
return type;
|
||||||
var ts = type as TypeSpec;
|
var ts = type as TypeSpec;
|
||||||
if (ts == null)
|
if (ts == null)
|
||||||
return type;
|
return type;
|
||||||
var newSig = create(ts.TypeSig, genericArgs);
|
var newSig = Create(ts.TypeSig, genericArgs);
|
||||||
return newSig == ts.TypeSig ? type : new TypeSpecUser(newSig);
|
return newSig == ts.TypeSig ? type : new TypeSpecUser(newSig);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TypeSig create(TypeSig type, IList<TypeSig> genericArgs) {
|
public static TypeSig Create(TypeSig type, IList<TypeSig> genericArgs) {
|
||||||
if (type == null || genericArgs == null || genericArgs.Count == 0)
|
if (type == null || genericArgs == null || genericArgs.Count == 0)
|
||||||
return type;
|
return type;
|
||||||
return new GenericArgsSubstitutor(genericArgs).create(type);
|
return new GenericArgsSubstitutor(genericArgs).Create(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TypeSig create(TypeSig type, IList<TypeSig> genericArgs, IList<TypeSig> genericMethodArgs) {
|
public static TypeSig Create(TypeSig type, IList<TypeSig> genericArgs, IList<TypeSig> genericMethodArgs) {
|
||||||
if (type == null || ((genericArgs == null || genericArgs.Count == 0) &&
|
if (type == null || ((genericArgs == null || genericArgs.Count == 0) &&
|
||||||
(genericMethodArgs == null || genericMethodArgs.Count == 0)))
|
(genericMethodArgs == null || genericMethodArgs.Count == 0)))
|
||||||
return type;
|
return type;
|
||||||
return new GenericArgsSubstitutor(genericArgs, genericMethodArgs).create(type);
|
return new GenericArgsSubstitutor(genericArgs, genericMethodArgs).Create(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IField create(IField field, GenericInstSig git) {
|
public static IField Create(IField field, GenericInstSig git) {
|
||||||
if (git == null)
|
if (git == null)
|
||||||
return field;
|
return field;
|
||||||
return create(field, git.GenericArguments);
|
return Create(field, git.GenericArguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IField create(IField field, IList<TypeSig> genericArgs) {
|
public static IField Create(IField field, IList<TypeSig> genericArgs) {
|
||||||
if (field == null || genericArgs == null || genericArgs.Count == 0)
|
if (field == null || genericArgs == null || genericArgs.Count == 0)
|
||||||
return field;
|
return field;
|
||||||
var newSig = create(field.FieldSig, genericArgs);
|
var newSig = Create(field.FieldSig, genericArgs);
|
||||||
if (newSig == field.FieldSig)
|
if (newSig == field.FieldSig)
|
||||||
return field;
|
return field;
|
||||||
var module = field.DeclaringType != null ? field.DeclaringType.Module : null;
|
var module = field.DeclaringType != null ? field.DeclaringType.Module : null;
|
||||||
return new MemberRefUser(module, field.Name, newSig, field.DeclaringType);
|
return new MemberRefUser(module, field.Name, newSig, field.DeclaringType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FieldSig create(FieldSig sig, GenericInstSig git) {
|
public static FieldSig Create(FieldSig sig, GenericInstSig git) {
|
||||||
if (git == null)
|
if (git == null)
|
||||||
return sig;
|
return sig;
|
||||||
return create(sig, git.GenericArguments);
|
return Create(sig, git.GenericArguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FieldSig create(FieldSig sig, IList<TypeSig> genericArgs) {
|
public static FieldSig Create(FieldSig sig, IList<TypeSig> genericArgs) {
|
||||||
if (sig == null || genericArgs == null || genericArgs.Count == 0)
|
if (sig == null || genericArgs == null || genericArgs.Count == 0)
|
||||||
return sig;
|
return sig;
|
||||||
return new GenericArgsSubstitutor(genericArgs).create(sig);
|
return new GenericArgsSubstitutor(genericArgs).Create(sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IMethod create(IMethod method, GenericInstSig git) {
|
public static IMethod Create(IMethod method, GenericInstSig git) {
|
||||||
if (git == null)
|
if (git == null)
|
||||||
return method;
|
return method;
|
||||||
|
|
||||||
var mdr = method as IMethodDefOrRef;
|
var mdr = method as IMethodDefOrRef;
|
||||||
if (mdr != null)
|
if (mdr != null)
|
||||||
return create(mdr, git);
|
return Create(mdr, git);
|
||||||
|
|
||||||
var ms = method as MethodSpec;
|
var ms = method as MethodSpec;
|
||||||
if (ms != null)
|
if (ms != null)
|
||||||
return create(ms, git);
|
return Create(ms, git);
|
||||||
|
|
||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MethodSpec create(MethodSpec method, GenericInstSig git) {
|
public static MethodSpec Create(MethodSpec method, GenericInstSig git) {
|
||||||
if (method == null || git == null)
|
if (method == null || git == null)
|
||||||
return method;
|
return method;
|
||||||
var newMethod = create(method.Method, git);
|
var newMethod = Create(method.Method, git);
|
||||||
var newInst = create(method.GenericInstMethodSig, git);
|
var newInst = Create(method.GenericInstMethodSig, git);
|
||||||
bool updated = newMethod != method.Method || newInst != method.GenericInstMethodSig;
|
bool updated = newMethod != method.Method || newInst != method.GenericInstMethodSig;
|
||||||
return updated ? new MethodSpecUser(newMethod, newInst) : method;
|
return updated ? new MethodSpecUser(newMethod, newInst) : method;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GenericInstMethodSig create(GenericInstMethodSig sig, GenericInstSig git) {
|
public static GenericInstMethodSig Create(GenericInstMethodSig sig, GenericInstSig git) {
|
||||||
if (git == null)
|
if (git == null)
|
||||||
return sig;
|
return sig;
|
||||||
return create(sig, git.GenericArguments);
|
return Create(sig, git.GenericArguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GenericInstMethodSig create(GenericInstMethodSig sig, IList<TypeSig> genericArgs) {
|
public static GenericInstMethodSig Create(GenericInstMethodSig sig, IList<TypeSig> genericArgs) {
|
||||||
if (sig == null || genericArgs == null || genericArgs.Count == 0)
|
if (sig == null || genericArgs == null || genericArgs.Count == 0)
|
||||||
return sig;
|
return sig;
|
||||||
return new GenericArgsSubstitutor(genericArgs).create(sig);
|
return new GenericArgsSubstitutor(genericArgs).Create(sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IMethodDefOrRef create(IMethodDefOrRef method, GenericInstSig git) {
|
public static IMethodDefOrRef Create(IMethodDefOrRef method, GenericInstSig git) {
|
||||||
if (git == null)
|
if (git == null)
|
||||||
return method;
|
return method;
|
||||||
return create(method, git.GenericArguments);
|
return Create(method, git.GenericArguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IMethodDefOrRef create(IMethodDefOrRef method, IList<TypeSig> genericArgs) {
|
public static IMethodDefOrRef Create(IMethodDefOrRef method, IList<TypeSig> genericArgs) {
|
||||||
return create(method, genericArgs, null);
|
return Create(method, genericArgs, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IMethodDefOrRef create(IMethodDefOrRef method, GenericInstSig git, IList<TypeSig> genericMethodArgs) {
|
public static IMethodDefOrRef Create(IMethodDefOrRef method, GenericInstSig git, IList<TypeSig> genericMethodArgs) {
|
||||||
return create(method, git == null ? null : git.GenericArguments, genericMethodArgs);
|
return Create(method, git == null ? null : git.GenericArguments, genericMethodArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a new method but keeps declaring type as is
|
// Creates a new method but keeps declaring type as is
|
||||||
public static IMethodDefOrRef create(IMethodDefOrRef method, IList<TypeSig> genericArgs, IList<TypeSig> genericMethodArgs) {
|
public static IMethodDefOrRef Create(IMethodDefOrRef method, IList<TypeSig> genericArgs, IList<TypeSig> genericMethodArgs) {
|
||||||
if (method == null)
|
if (method == null)
|
||||||
return method;
|
return method;
|
||||||
if ((genericArgs == null || genericArgs.Count == 0) && (genericMethodArgs == null || genericMethodArgs.Count == 0))
|
if ((genericArgs == null || genericArgs.Count == 0) && (genericMethodArgs == null || genericMethodArgs.Count == 0))
|
||||||
|
@ -144,7 +144,7 @@ namespace de4dot.blocks {
|
||||||
if (sig == null)
|
if (sig == null)
|
||||||
return method;
|
return method;
|
||||||
|
|
||||||
var newSig = new GenericArgsSubstitutor(genericArgs, genericMethodArgs).create(sig);
|
var newSig = new GenericArgsSubstitutor(genericArgs, genericMethodArgs).Create(sig);
|
||||||
if (newSig == sig)
|
if (newSig == sig)
|
||||||
return method;
|
return method;
|
||||||
|
|
||||||
|
@ -163,12 +163,12 @@ namespace de4dot.blocks {
|
||||||
this.updated = false;
|
this.updated = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeSig create(TypeSig type) {
|
TypeSig Create(TypeSig type) {
|
||||||
var newType = create2(type);
|
var newType = Create2(type);
|
||||||
return updated ? newType : type;
|
return updated ? newType : type;
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeSig create2(TypeSig type) {
|
TypeSig Create2(TypeSig type) {
|
||||||
if (type == null)
|
if (type == null)
|
||||||
return type;
|
return type;
|
||||||
TypeSig result;
|
TypeSig result;
|
||||||
|
@ -197,11 +197,11 @@ namespace de4dot.blocks {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ElementType.Ptr:
|
case ElementType.Ptr:
|
||||||
result = new PtrSig(create2(type.Next));
|
result = new PtrSig(Create2(type.Next));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ElementType.ByRef:
|
case ElementType.ByRef:
|
||||||
result = new ByRefSig(create2(type.Next));
|
result = new ByRefSig(Create2(type.Next));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ElementType.Array:
|
case ElementType.Array:
|
||||||
|
@ -210,11 +210,11 @@ namespace de4dot.blocks {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ElementType.SZArray:
|
case ElementType.SZArray:
|
||||||
result = new SZArraySig(create2(type.Next));
|
result = new SZArraySig(Create2(type.Next));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ElementType.Pinned:
|
case ElementType.Pinned:
|
||||||
result = new PinnedSig(create2(type.Next));
|
result = new PinnedSig(Create2(type.Next));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ElementType.ValueType:
|
case ElementType.ValueType:
|
||||||
|
@ -244,9 +244,9 @@ namespace de4dot.blocks {
|
||||||
|
|
||||||
case ElementType.GenericInst:
|
case ElementType.GenericInst:
|
||||||
var gis = (GenericInstSig)type;
|
var gis = (GenericInstSig)type;
|
||||||
var newGis = new GenericInstSig(create2(gis.GenericType) as ClassOrValueTypeSig, gis.GenericArguments.Count);
|
var newGis = new GenericInstSig(Create2(gis.GenericType) as ClassOrValueTypeSig, gis.GenericArguments.Count);
|
||||||
for (int i = 0; i < gis.GenericArguments.Count; i++)
|
for (int i = 0; i < gis.GenericArguments.Count; i++)
|
||||||
newGis.GenericArguments.Add(create2(gis.GenericArguments[i]));
|
newGis.GenericArguments.Add(Create2(gis.GenericArguments[i]));
|
||||||
result = newGis;
|
result = newGis;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -267,7 +267,7 @@ namespace de4dot.blocks {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ElementType.FnPtr:
|
case ElementType.FnPtr:
|
||||||
result = new FnPtrSig(create(((FnPtrSig)type).MethodSig));
|
result = new FnPtrSig(Create(((FnPtrSig)type).MethodSig));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ElementType.End:
|
case ElementType.End:
|
||||||
|
@ -282,31 +282,31 @@ namespace de4dot.blocks {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodSig create(MethodSig sig) {
|
MethodSig Create(MethodSig sig) {
|
||||||
if (sig == null)
|
if (sig == null)
|
||||||
return sig;
|
return sig;
|
||||||
var newSig = new MethodSig(sig.GetCallingConvention());
|
var newSig = new MethodSig(sig.GetCallingConvention());
|
||||||
newSig.RetType = create2(sig.RetType);
|
newSig.RetType = Create2(sig.RetType);
|
||||||
for (int i = 0; i < sig.Params.Count; i++)
|
for (int i = 0; i < sig.Params.Count; i++)
|
||||||
newSig.Params.Add(create2(sig.Params[i]));
|
newSig.Params.Add(Create2(sig.Params[i]));
|
||||||
newSig.GenParamCount = sig.GenParamCount;
|
newSig.GenParamCount = sig.GenParamCount;
|
||||||
if (sig.ParamsAfterSentinel != null) {
|
if (sig.ParamsAfterSentinel != null) {
|
||||||
newSig.ParamsAfterSentinel = new List<TypeSig>();
|
newSig.ParamsAfterSentinel = new List<TypeSig>();
|
||||||
for (int i = 0; i < sig.ParamsAfterSentinel.Count; i++)
|
for (int i = 0; i < sig.ParamsAfterSentinel.Count; i++)
|
||||||
newSig.ParamsAfterSentinel.Add(create2(sig.ParamsAfterSentinel[i]));
|
newSig.ParamsAfterSentinel.Add(Create2(sig.ParamsAfterSentinel[i]));
|
||||||
}
|
}
|
||||||
return updated ? newSig : sig;
|
return updated ? newSig : sig;
|
||||||
}
|
}
|
||||||
|
|
||||||
GenericInstMethodSig create(GenericInstMethodSig sig) {
|
GenericInstMethodSig Create(GenericInstMethodSig sig) {
|
||||||
var newSig = new GenericInstMethodSig();
|
var newSig = new GenericInstMethodSig();
|
||||||
for (int i = 0; i < sig.GenericArguments.Count; i++)
|
for (int i = 0; i < sig.GenericArguments.Count; i++)
|
||||||
newSig.GenericArguments.Add(create2(sig.GenericArguments[i]));
|
newSig.GenericArguments.Add(Create2(sig.GenericArguments[i]));
|
||||||
return updated ? newSig : sig;
|
return updated ? newSig : sig;
|
||||||
}
|
}
|
||||||
|
|
||||||
FieldSig create(FieldSig sig) {
|
FieldSig Create(FieldSig sig) {
|
||||||
var newSig = new FieldSig(create2(sig.Type));
|
var newSig = new FieldSig(Create2(sig.Type));
|
||||||
return updated ? newSig : sig;
|
return updated ? newSig : sig;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,11 +44,11 @@ namespace de4dot.blocks {
|
||||||
|
|
||||||
// Returns the variable or null if it's not a ldloc/stloc instruction. It does not return
|
// Returns the variable or null if it's not a ldloc/stloc instruction. It does not return
|
||||||
// a local variable if it's a ldloca/ldloca.s instruction.
|
// a local variable if it's a ldloca/ldloca.s instruction.
|
||||||
public static Local getLocalVar(IList<Local> locals, Instr instr) {
|
public static Local GetLocalVar(IList<Local> locals, Instr instr) {
|
||||||
return instr.Instruction.GetLocal(locals);
|
return instr.Instruction.GetLocal(locals);
|
||||||
}
|
}
|
||||||
|
|
||||||
static public bool isFallThrough(OpCode opCode) {
|
static public bool IsFallThrough(OpCode opCode) {
|
||||||
switch (opCode.FlowControl) {
|
switch (opCode.FlowControl) {
|
||||||
case FlowControl.Call:
|
case FlowControl.Call:
|
||||||
return opCode != OpCodes.Jmp;
|
return opCode != OpCodes.Jmp;
|
||||||
|
@ -61,7 +61,7 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the instruction only pushes one value onto the stack and pops nothing
|
// Returns true if the instruction only pushes one value onto the stack and pops nothing
|
||||||
public bool isSimpleLoad() {
|
public bool IsSimpleLoad() {
|
||||||
switch (OpCode.Code) {
|
switch (OpCode.Code) {
|
||||||
case Code.Ldarg:
|
case Code.Ldarg:
|
||||||
case Code.Ldarg_S:
|
case Code.Ldarg_S:
|
||||||
|
@ -103,55 +103,55 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isLdcI4() {
|
public bool IsLdcI4() {
|
||||||
return instruction.IsLdcI4();
|
return instruction.IsLdcI4();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getLdcI4Value() {
|
public int GetLdcI4Value() {
|
||||||
return instruction.GetLdcI4Value();
|
return instruction.GetLdcI4Value();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isLdarg() {
|
public bool IsLdarg() {
|
||||||
return instruction.IsLdarg();
|
return instruction.IsLdarg();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isStloc() {
|
public bool IsStloc() {
|
||||||
return instruction.IsStloc();
|
return instruction.IsStloc();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isLdloc() {
|
public bool IsLdloc() {
|
||||||
return instruction.IsLdloc();
|
return instruction.IsLdloc();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isNop() {
|
public bool IsNop() {
|
||||||
return OpCode == OpCodes.Nop;
|
return OpCode == OpCodes.Nop;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isPop() {
|
public bool IsPop() {
|
||||||
return OpCode == OpCodes.Pop;
|
return OpCode == OpCodes.Pop;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isLeave() {
|
public bool IsLeave() {
|
||||||
return instruction.IsLeave();
|
return instruction.IsLeave();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isBr() {
|
public bool IsBr() {
|
||||||
return instruction.IsBr();
|
return instruction.IsBr();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isBrfalse() {
|
public bool IsBrfalse() {
|
||||||
return instruction.IsBrfalse();
|
return instruction.IsBrfalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isBrtrue() {
|
public bool IsBrtrue() {
|
||||||
return instruction.IsBrtrue();
|
return instruction.IsBrtrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isConditionalBranch() {
|
public bool IsConditionalBranch() {
|
||||||
return instruction.IsConditionalBranch();
|
return instruction.IsConditionalBranch();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool getFlippedBranchOpCode(out OpCode opcode) {
|
public bool GetFlippedBranchOpCode(out OpCode opcode) {
|
||||||
switch (OpCode.Code) {
|
switch (OpCode.Code) {
|
||||||
case Code.Bge: opcode = OpCodes.Blt; return true;
|
case Code.Bge: opcode = OpCodes.Blt; return true;
|
||||||
case Code.Bge_S: opcode = OpCodes.Blt_S; return true;
|
case Code.Bge_S: opcode = OpCodes.Blt_S; return true;
|
||||||
|
@ -190,20 +190,20 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void flipConditonalBranch() {
|
public void FlipConditonalBranch() {
|
||||||
OpCode opcode;
|
OpCode opcode;
|
||||||
if (!getFlippedBranchOpCode(out opcode))
|
if (!GetFlippedBranchOpCode(out opcode))
|
||||||
throw new ApplicationException("Can't flip conditional since it's not a supported conditional instruction");
|
throw new ApplicationException("Can't flip conditional since it's not a supported conditional instruction");
|
||||||
instruction.OpCode = opcode;
|
instruction.OpCode = opcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if we can flip a conditional branch
|
// Returns true if we can flip a conditional branch
|
||||||
public bool canFlipConditionalBranch() {
|
public bool CanFlipConditionalBranch() {
|
||||||
OpCode opcode;
|
OpCode opcode;
|
||||||
return getFlippedBranchOpCode(out opcode);
|
return GetFlippedBranchOpCode(out opcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateTargets(List<Instr> targets) {
|
public void UpdateTargets(List<Instr> targets) {
|
||||||
switch (OpCode.OperandType) {
|
switch (OpCode.OperandType) {
|
||||||
case OperandType.ShortInlineBrTarget:
|
case OperandType.ShortInlineBrTarget:
|
||||||
case OperandType.InlineBrTarget:
|
case OperandType.InlineBrTarget:
|
||||||
|
|
|
@ -33,44 +33,44 @@ namespace de4dot.blocks {
|
||||||
this.exceptionHandlers = exceptionHandlers;
|
this.exceptionHandlers = exceptionHandlers;
|
||||||
this.branches = new Dictionary<int, List<int>>();
|
this.branches = new Dictionary<int, List<int>>();
|
||||||
|
|
||||||
createInstrToIndex();
|
CreateInstrToIndex();
|
||||||
createBranches();
|
CreateBranches();
|
||||||
createExceptionBranches();
|
CreateExceptionBranches();
|
||||||
}
|
}
|
||||||
|
|
||||||
void createInstrToIndex() {
|
void CreateInstrToIndex() {
|
||||||
instrToIndex = new Dictionary<Instruction, int>();
|
instrToIndex = new Dictionary<Instruction, int>();
|
||||||
|
|
||||||
for (int i = 0; i < instructions.Count; i++)
|
for (int i = 0; i < instructions.Count; i++)
|
||||||
instrToIndex[instructions[i]] = i;
|
instrToIndex[instructions[i]] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<int> getBranchTargetList(int index) {
|
List<int> GetBranchTargetList(int index) {
|
||||||
List<int> targetsList;
|
List<int> targetsList;
|
||||||
if (!branches.TryGetValue(index, out targetsList))
|
if (!branches.TryGetValue(index, out targetsList))
|
||||||
branches[index] = targetsList = new List<int>();
|
branches[index] = targetsList = new List<int>();
|
||||||
return targetsList;
|
return targetsList;
|
||||||
}
|
}
|
||||||
|
|
||||||
void markAsBranchTarget(Instruction instr) {
|
void MarkAsBranchTarget(Instruction instr) {
|
||||||
if (instr == null)
|
if (instr == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int index = instrToIndex[instr];
|
int index = instrToIndex[instr];
|
||||||
getBranchTargetList(index); // Just create the list
|
GetBranchTargetList(index); // Just create the list
|
||||||
}
|
}
|
||||||
|
|
||||||
void createExceptionBranches() {
|
void CreateExceptionBranches() {
|
||||||
foreach (var eh in exceptionHandlers) {
|
foreach (var eh in exceptionHandlers) {
|
||||||
markAsBranchTarget(eh.TryStart);
|
MarkAsBranchTarget(eh.TryStart);
|
||||||
markAsBranchTarget(eh.TryEnd);
|
MarkAsBranchTarget(eh.TryEnd);
|
||||||
markAsBranchTarget(eh.FilterStart);
|
MarkAsBranchTarget(eh.FilterStart);
|
||||||
markAsBranchTarget(eh.HandlerStart);
|
MarkAsBranchTarget(eh.HandlerStart);
|
||||||
markAsBranchTarget(eh.HandlerEnd);
|
MarkAsBranchTarget(eh.HandlerEnd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void createBranches() {
|
void CreateBranches() {
|
||||||
for (int i = 0; i < instructions.Count; i++) {
|
for (int i = 0; i < instructions.Count; i++) {
|
||||||
var instr = instructions[i];
|
var instr = instructions[i];
|
||||||
|
|
||||||
|
@ -113,13 +113,13 @@ namespace de4dot.blocks {
|
||||||
targets.Add(i + 1);
|
targets.Add(i + 1);
|
||||||
for (int j = 0; j < targets.Count; j++) {
|
for (int j = 0; j < targets.Count; j++) {
|
||||||
int targetIndex = targets[j];
|
int targetIndex = targets[j];
|
||||||
getBranchTargetList(targetIndex).Add(i);
|
GetBranchTargetList(targetIndex).Add(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void findBlocks(List<Block> instrToBlock, List<Block> allBlocks) {
|
void FindBlocks(List<Block> instrToBlock, List<Block> allBlocks) {
|
||||||
Block block = null;
|
Block block = null;
|
||||||
for (var i = 0; i < instructions.Count; i++) {
|
for (var i = 0; i < instructions.Count; i++) {
|
||||||
List<int> branchSources;
|
List<int> branchSources;
|
||||||
|
@ -128,7 +128,7 @@ namespace de4dot.blocks {
|
||||||
allBlocks.Add(block);
|
allBlocks.Add(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
block.add(new Instr(this.instructions[i]));
|
block.Add(new Instr(this.instructions[i]));
|
||||||
instrToBlock.Add(block);
|
instrToBlock.Add(block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,7 @@ namespace de4dot.blocks {
|
||||||
// Fix all branches so they now point to a Block, and not an Instruction. The
|
// Fix all branches so they now point to a Block, and not an Instruction. The
|
||||||
// block's Targets field is updated, not the Instruction's Operand field.
|
// block's Targets field is updated, not the Instruction's Operand field.
|
||||||
// Also update Block.FallThrough with next Block if last instr falls through.
|
// Also update Block.FallThrough with next Block if last instr falls through.
|
||||||
void fixBranchTargets(List<Block> instrToBlock, List<Block> allBlocks) {
|
void FixBranchTargets(List<Block> instrToBlock, List<Block> allBlocks) {
|
||||||
for (var i = 0; i < allBlocks.Count; i++) {
|
for (var i = 0; i < allBlocks.Count; i++) {
|
||||||
var block = allBlocks[i];
|
var block = allBlocks[i];
|
||||||
var lastInstr = block.LastInstr;
|
var lastInstr = block.LastInstr;
|
||||||
|
@ -160,15 +160,15 @@ namespace de4dot.blocks {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i + 1 < allBlocks.Count && Instr.isFallThrough(lastInstr.OpCode))
|
if (i + 1 < allBlocks.Count && Instr.IsFallThrough(lastInstr.OpCode))
|
||||||
block.FallThrough = allBlocks[i + 1];
|
block.FallThrough = allBlocks[i + 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updates the sources field of each block
|
// Updates the sources field of each block
|
||||||
void fixBlockSources(List<Block> allBlocks) {
|
void FixBlockSources(List<Block> allBlocks) {
|
||||||
foreach (var block in allBlocks) {
|
foreach (var block in allBlocks) {
|
||||||
block.updateSources();
|
block.UpdateSources();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,7 +195,7 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<List<ExceptionHandler>> getSortedExceptionInfos() {
|
List<List<ExceptionHandler>> GetSortedExceptionInfos() {
|
||||||
var exInfos = new Dictionary<EHInfo, List<ExceptionHandler>>();
|
var exInfos = new Dictionary<EHInfo, List<ExceptionHandler>>();
|
||||||
foreach (var eh in exceptionHandlers) {
|
foreach (var eh in exceptionHandlers) {
|
||||||
List<ExceptionHandler> handlers;
|
List<ExceptionHandler> handlers;
|
||||||
|
@ -220,8 +220,8 @@ namespace de4dot.blocks {
|
||||||
|
|
||||||
// Same start instruction. The nested one is the one that ends earliest,
|
// Same start instruction. The nested one is the one that ends earliest,
|
||||||
// so it should be sorted before the outer one.
|
// so it should be sorted before the outer one.
|
||||||
ai = getInstrIndex(a[0].TryEnd);
|
ai = GetInstrIndex(a[0].TryEnd);
|
||||||
bi = getInstrIndex(b[0].TryEnd);
|
bi = GetInstrIndex(b[0].TryEnd);
|
||||||
if (ai < bi) return -1;
|
if (ai < bi) return -1;
|
||||||
if (ai > bi) return 1;
|
if (ai > bi) return 1;
|
||||||
|
|
||||||
|
@ -245,7 +245,7 @@ namespace de4dot.blocks {
|
||||||
|
|
||||||
List<BaseBlockInfo> blocksLeft = new List<BaseBlockInfo>();
|
List<BaseBlockInfo> blocksLeft = new List<BaseBlockInfo>();
|
||||||
|
|
||||||
public void add(BaseBlock bb, int start, int end) {
|
public void Add(BaseBlock bb, int start, int end) {
|
||||||
if (start < 0 || end < 0 || end < start)
|
if (start < 0 || end < 0 || end < start)
|
||||||
throw new ApplicationException("Invalid start and/or end index");
|
throw new ApplicationException("Invalid start and/or end index");
|
||||||
if (blocksLeft.Count != 0) {
|
if (blocksLeft.Count != 0) {
|
||||||
|
@ -256,7 +256,7 @@ namespace de4dot.blocks {
|
||||||
blocksLeft.Add(new BaseBlockInfo(start, end, bb));
|
blocksLeft.Add(new BaseBlockInfo(start, end, bb));
|
||||||
}
|
}
|
||||||
|
|
||||||
int findStart(int instrIndex) {
|
int FindStart(int instrIndex) {
|
||||||
for (int i = 0; i < blocksLeft.Count; i++) {
|
for (int i = 0; i < blocksLeft.Count; i++) {
|
||||||
if (blocksLeft[i].startInstr == instrIndex)
|
if (blocksLeft[i].startInstr == instrIndex)
|
||||||
return i;
|
return i;
|
||||||
|
@ -264,7 +264,7 @@ namespace de4dot.blocks {
|
||||||
throw new ApplicationException("Could not find start BaseBlockInfo");
|
throw new ApplicationException("Could not find start BaseBlockInfo");
|
||||||
}
|
}
|
||||||
|
|
||||||
int findEnd(int instrIndex) {
|
int FindEnd(int instrIndex) {
|
||||||
for (int i = 0; i < blocksLeft.Count; i++) {
|
for (int i = 0; i < blocksLeft.Count; i++) {
|
||||||
if (blocksLeft[i].endInstr == instrIndex)
|
if (blocksLeft[i].endInstr == instrIndex)
|
||||||
return i;
|
return i;
|
||||||
|
@ -272,14 +272,14 @@ namespace de4dot.blocks {
|
||||||
throw new ApplicationException("Could not find end BaseBlockInfo");
|
throw new ApplicationException("Could not find end BaseBlockInfo");
|
||||||
}
|
}
|
||||||
|
|
||||||
List<BaseBlock> getBlocks(int startInstr, int endInstr, out int startIndex, out int endIndex) {
|
List<BaseBlock> GetBlocks(int startInstr, int endInstr, out int startIndex, out int endIndex) {
|
||||||
if (endInstr < startInstr || startInstr < 0 || endInstr < 0)
|
if (endInstr < startInstr || startInstr < 0 || endInstr < 0)
|
||||||
throw new ApplicationException("Invalid startInstr and/or endInstr");
|
throw new ApplicationException("Invalid startInstr and/or endInstr");
|
||||||
|
|
||||||
var rv = new List<BaseBlock>();
|
var rv = new List<BaseBlock>();
|
||||||
|
|
||||||
startIndex = findStart(startInstr);
|
startIndex = FindStart(startInstr);
|
||||||
endIndex = findEnd(endInstr);
|
endIndex = FindEnd(endInstr);
|
||||||
|
|
||||||
for (int i = startIndex; i <= endIndex; i++)
|
for (int i = startIndex; i <= endIndex; i++)
|
||||||
rv.Add(blocksLeft[i].baseBlock);
|
rv.Add(blocksLeft[i].baseBlock);
|
||||||
|
@ -288,13 +288,13 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace the BaseBlocks with a new BaseBlock, returning the old ones.
|
// Replace the BaseBlocks with a new BaseBlock, returning the old ones.
|
||||||
public List<BaseBlock> replace(int startInstr, int endInstr, ScopeBlock bb) {
|
public List<BaseBlock> Replace(int startInstr, int endInstr, ScopeBlock bb) {
|
||||||
if (endInstr < startInstr)
|
if (endInstr < startInstr)
|
||||||
return new List<BaseBlock>();
|
return new List<BaseBlock>();
|
||||||
|
|
||||||
int startIndex, endIndex;
|
int startIndex, endIndex;
|
||||||
var rv = getBlocks(startInstr, endInstr, out startIndex, out endIndex);
|
var rv = GetBlocks(startInstr, endInstr, out startIndex, out endIndex);
|
||||||
updateParent(rv, bb);
|
UpdateParent(rv, bb);
|
||||||
|
|
||||||
var bbi = new BaseBlockInfo(blocksLeft[startIndex].startInstr, blocksLeft[endIndex].endInstr, bb);
|
var bbi = new BaseBlockInfo(blocksLeft[startIndex].startInstr, blocksLeft[endIndex].endInstr, bb);
|
||||||
blocksLeft.RemoveRange(startIndex, endIndex - startIndex + 1);
|
blocksLeft.RemoveRange(startIndex, endIndex - startIndex + 1);
|
||||||
|
@ -303,78 +303,78 @@ namespace de4dot.blocks {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<BaseBlock> getBlocks(ScopeBlock parent) {
|
public List<BaseBlock> GetBlocks(ScopeBlock parent) {
|
||||||
if (blocksLeft.Count == 0)
|
if (blocksLeft.Count == 0)
|
||||||
return new List<BaseBlock>();
|
return new List<BaseBlock>();
|
||||||
int startIndex, endIndex;
|
int startIndex, endIndex;
|
||||||
var lb = getBlocks(0, blocksLeft[blocksLeft.Count - 1].endInstr, out startIndex, out endIndex);
|
var lb = GetBlocks(0, blocksLeft[blocksLeft.Count - 1].endInstr, out startIndex, out endIndex);
|
||||||
return updateParent(lb, parent);
|
return UpdateParent(lb, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<BaseBlock> updateParent(List<BaseBlock> lb, ScopeBlock parent) {
|
List<BaseBlock> UpdateParent(List<BaseBlock> lb, ScopeBlock parent) {
|
||||||
foreach (var bb in lb)
|
foreach (var bb in lb)
|
||||||
bb.Parent = parent;
|
bb.Parent = parent;
|
||||||
return lb;
|
return lb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseBlocksList createBaseBlockList(List<Block> allBlocks, List<List<ExceptionHandler>> exSorted) {
|
BaseBlocksList CreateBaseBlockList(List<Block> allBlocks, List<List<ExceptionHandler>> exSorted) {
|
||||||
var bbl = new BaseBlocksList();
|
var bbl = new BaseBlocksList();
|
||||||
foreach (var block in allBlocks) {
|
foreach (var block in allBlocks) {
|
||||||
int start = instrToIndex[block.FirstInstr.Instruction];
|
int start = instrToIndex[block.FirstInstr.Instruction];
|
||||||
int end = instrToIndex[block.LastInstr.Instruction];
|
int end = instrToIndex[block.LastInstr.Instruction];
|
||||||
bbl.add(block, start, end);
|
bbl.Add(block, start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var exHandlers in exSorted) {
|
foreach (var exHandlers in exSorted) {
|
||||||
var tryBlock = new TryBlock();
|
var tryBlock = new TryBlock();
|
||||||
var tryStart = instrToIndex[exHandlers[0].TryStart];
|
var tryStart = instrToIndex[exHandlers[0].TryStart];
|
||||||
var tryEnd = getInstrIndex(exHandlers[0].TryEnd) - 1;
|
var tryEnd = GetInstrIndex(exHandlers[0].TryEnd) - 1;
|
||||||
tryBlock.BaseBlocks = bbl.replace(tryStart, tryEnd, tryBlock);
|
tryBlock.BaseBlocks = bbl.Replace(tryStart, tryEnd, tryBlock);
|
||||||
|
|
||||||
foreach (var exHandler in exHandlers) {
|
foreach (var exHandler in exHandlers) {
|
||||||
var tryHandlerBlock = new TryHandlerBlock(exHandler);
|
var tryHandlerBlock = new TryHandlerBlock(exHandler);
|
||||||
tryBlock.addTryHandler(tryHandlerBlock);
|
tryBlock.AddTryHandler(tryHandlerBlock);
|
||||||
|
|
||||||
int filterStart = -1, handlerStart = -1, handlerEnd = -1;
|
int filterStart = -1, handlerStart = -1, handlerEnd = -1;
|
||||||
|
|
||||||
if (exHandler.FilterStart != null) {
|
if (exHandler.FilterStart != null) {
|
||||||
filterStart = instrToIndex[exHandler.FilterStart];
|
filterStart = instrToIndex[exHandler.FilterStart];
|
||||||
var end = instrToIndex[exHandler.HandlerStart] - 1;
|
var end = instrToIndex[exHandler.HandlerStart] - 1;
|
||||||
tryHandlerBlock.FilterHandlerBlock.BaseBlocks = bbl.replace(filterStart, end, tryHandlerBlock.FilterHandlerBlock);
|
tryHandlerBlock.FilterHandlerBlock.BaseBlocks = bbl.Replace(filterStart, end, tryHandlerBlock.FilterHandlerBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
handlerStart = instrToIndex[exHandler.HandlerStart];
|
handlerStart = instrToIndex[exHandler.HandlerStart];
|
||||||
handlerEnd = getInstrIndex(exHandler.HandlerEnd) - 1;
|
handlerEnd = GetInstrIndex(exHandler.HandlerEnd) - 1;
|
||||||
tryHandlerBlock.HandlerBlock.BaseBlocks = bbl.replace(handlerStart, handlerEnd, tryHandlerBlock.HandlerBlock);
|
tryHandlerBlock.HandlerBlock.BaseBlocks = bbl.Replace(handlerStart, handlerEnd, tryHandlerBlock.HandlerBlock);
|
||||||
|
|
||||||
tryHandlerBlock.BaseBlocks = bbl.replace(filterStart == -1 ? handlerStart : filterStart, handlerEnd, tryHandlerBlock);
|
tryHandlerBlock.BaseBlocks = bbl.Replace(filterStart == -1 ? handlerStart : filterStart, handlerEnd, tryHandlerBlock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return bbl;
|
return bbl;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getInstrIndex(Instruction instruction) {
|
int GetInstrIndex(Instruction instruction) {
|
||||||
if (instruction == null)
|
if (instruction == null)
|
||||||
return instructions.Count;
|
return instructions.Count;
|
||||||
return instrToIndex[instruction];
|
return instrToIndex[instruction];
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodBlocks parse() {
|
public MethodBlocks Parse() {
|
||||||
var instrToBlock = new List<Block>(instructions.Count);
|
var instrToBlock = new List<Block>(instructions.Count);
|
||||||
var allBlocks = new List<Block>();
|
var allBlocks = new List<Block>();
|
||||||
findBlocks(instrToBlock, allBlocks);
|
FindBlocks(instrToBlock, allBlocks);
|
||||||
fixBranchTargets(instrToBlock, allBlocks);
|
FixBranchTargets(instrToBlock, allBlocks);
|
||||||
fixBlockSources(allBlocks);
|
FixBlockSources(allBlocks);
|
||||||
var exSorted = getSortedExceptionInfos();
|
var exSorted = GetSortedExceptionInfos();
|
||||||
var bbl = createBaseBlockList(allBlocks, exSorted);
|
var bbl = CreateBaseBlockList(allBlocks, exSorted);
|
||||||
|
|
||||||
foreach (var block in allBlocks)
|
foreach (var block in allBlocks)
|
||||||
block.removeLastBr();
|
block.RemoveLastBr();
|
||||||
|
|
||||||
var mb = new MethodBlocks();
|
var mb = new MethodBlocks();
|
||||||
mb.BaseBlocks = bbl.getBlocks(mb);
|
mb.BaseBlocks = bbl.GetBlocks(mb);
|
||||||
return mb;
|
return mb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,23 +32,23 @@ namespace de4dot.blocks {
|
||||||
get { return tokenToValue.Count; }
|
get { return tokenToValue.Count; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<TypeDef> getKeys() {
|
public IEnumerable<TypeDef> GetKeys() {
|
||||||
return tokenToKey.Values;
|
return tokenToKey.Values;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<TValue> getValues() {
|
public IEnumerable<TValue> GetValues() {
|
||||||
return tokenToValue.Values;
|
return tokenToValue.Values;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopeAndTokenKey getTokenKey(TypeDef typeDef) {
|
ScopeAndTokenKey GetTokenKey(TypeDef typeDef) {
|
||||||
return new ScopeAndTokenKey(typeDef);
|
return new ScopeAndTokenKey(typeDef);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TValue find(IType typeRef) {
|
public TValue Find(IType typeRef) {
|
||||||
TValue value;
|
TValue value;
|
||||||
var typeDef = typeRef as TypeDef;
|
var typeDef = typeRef as TypeDef;
|
||||||
if (typeDef != null)
|
if (typeDef != null)
|
||||||
tokenToValue.TryGetValue(getTokenKey(typeDef), out value);
|
tokenToValue.TryGetValue(GetTokenKey(typeDef), out value);
|
||||||
else if (typeRef != null)
|
else if (typeRef != null)
|
||||||
refToValue.TryGetValue(typeRef, out value);
|
refToValue.TryGetValue(typeRef, out value);
|
||||||
else
|
else
|
||||||
|
@ -56,23 +56,23 @@ namespace de4dot.blocks {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TValue findAny(IType type) {
|
public TValue FindAny(IType type) {
|
||||||
TValue value;
|
TValue value;
|
||||||
var typeDef = type as TypeDef;
|
var typeDef = type as TypeDef;
|
||||||
if (typeDef != null && tokenToValue.TryGetValue(getTokenKey(typeDef), out value))
|
if (typeDef != null && tokenToValue.TryGetValue(GetTokenKey(typeDef), out value))
|
||||||
return value;
|
return value;
|
||||||
|
|
||||||
refToValue.TryGetValue(type, out value);
|
refToValue.TryGetValue(type, out value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(TypeDef typeDef, TValue value) {
|
public void Add(TypeDef typeDef, TValue value) {
|
||||||
var tokenKey = getTokenKey(typeDef);
|
var tokenKey = GetTokenKey(typeDef);
|
||||||
tokenToValue[tokenKey] = value;
|
tokenToValue[tokenKey] = value;
|
||||||
tokenToKey[tokenKey] = typeDef;
|
tokenToKey[tokenKey] = typeDef;
|
||||||
|
|
||||||
if (!refToValue.ContainsKey(typeDef) ||
|
if (!refToValue.ContainsKey(typeDef) ||
|
||||||
getAccessibilityOrder(typeDef) < getAccessibilityOrder(refToKey[typeDef])) {
|
GetAccessibilityOrder(typeDef) < GetAccessibilityOrder(refToKey[typeDef])) {
|
||||||
refToKey[typeDef] = typeDef;
|
refToKey[typeDef] = typeDef;
|
||||||
refToValue[typeDef] = value;
|
refToValue[typeDef] = value;
|
||||||
}
|
}
|
||||||
|
@ -89,11 +89,11 @@ namespace de4dot.blocks {
|
||||||
60, // NestedFamANDAssem
|
60, // NestedFamANDAssem
|
||||||
30, // NestedFamORAssem
|
30, // NestedFamORAssem
|
||||||
};
|
};
|
||||||
static int getAccessibilityOrder(TypeDef typeDef) {
|
static int GetAccessibilityOrder(TypeDef typeDef) {
|
||||||
return accessibilityOrder[(int)typeDef.Attributes & 7];
|
return accessibilityOrder[(int)typeDef.Attributes & 7];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onTypesRenamed() {
|
public void OnTypesRenamed() {
|
||||||
var newTypeRefToValue = new Dictionary<IType, TValue>(refToValue.Count);
|
var newTypeRefToValue = new Dictionary<IType, TValue>(refToValue.Count);
|
||||||
foreach (var kvp in refToValue)
|
foreach (var kvp in refToValue)
|
||||||
newTypeRefToValue[kvp.Key] = kvp.Value;
|
newTypeRefToValue[kvp.Key] = kvp.Value;
|
||||||
|
@ -111,48 +111,48 @@ namespace de4dot.blocks {
|
||||||
get { return tokenToValue.Count; }
|
get { return tokenToValue.Count; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<FieldDef> getKeys() {
|
public IEnumerable<FieldDef> GetKeys() {
|
||||||
return tokenToKey.Values;
|
return tokenToKey.Values;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<TValue> getValues() {
|
public IEnumerable<TValue> GetValues() {
|
||||||
return tokenToValue.Values;
|
return tokenToValue.Values;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopeAndTokenKey getTokenKey(FieldDef fieldDef) {
|
ScopeAndTokenKey GetTokenKey(FieldDef fieldDef) {
|
||||||
return new ScopeAndTokenKey(fieldDef);
|
return new ScopeAndTokenKey(fieldDef);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal abstract IFieldRefKey getRefKey(IField fieldRef);
|
internal abstract IFieldRefKey GetRefKey(IField fieldRef);
|
||||||
|
|
||||||
public TValue find(IField fieldRef) {
|
public TValue Find(IField fieldRef) {
|
||||||
TValue value;
|
TValue value;
|
||||||
var fieldDef = fieldRef as FieldDef;
|
var fieldDef = fieldRef as FieldDef;
|
||||||
if (fieldDef != null)
|
if (fieldDef != null)
|
||||||
tokenToValue.TryGetValue(getTokenKey(fieldDef), out value);
|
tokenToValue.TryGetValue(GetTokenKey(fieldDef), out value);
|
||||||
else
|
else
|
||||||
refToValue.TryGetValue(getRefKey(fieldRef), out value);
|
refToValue.TryGetValue(GetRefKey(fieldRef), out value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TValue findAny(IField fieldRef) {
|
public TValue FindAny(IField fieldRef) {
|
||||||
TValue value;
|
TValue value;
|
||||||
var fieldDef = fieldRef as FieldDef;
|
var fieldDef = fieldRef as FieldDef;
|
||||||
if (fieldDef != null && tokenToValue.TryGetValue(getTokenKey(fieldDef), out value))
|
if (fieldDef != null && tokenToValue.TryGetValue(GetTokenKey(fieldDef), out value))
|
||||||
return value;
|
return value;
|
||||||
|
|
||||||
refToValue.TryGetValue(getRefKey(fieldRef), out value);
|
refToValue.TryGetValue(GetRefKey(fieldRef), out value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(FieldDef fieldDef, TValue value) {
|
public void Add(FieldDef fieldDef, TValue value) {
|
||||||
var tokenKey = getTokenKey(fieldDef);
|
var tokenKey = GetTokenKey(fieldDef);
|
||||||
tokenToValue[tokenKey] = value;
|
tokenToValue[tokenKey] = value;
|
||||||
tokenToKey[tokenKey] = fieldDef;
|
tokenToKey[tokenKey] = fieldDef;
|
||||||
|
|
||||||
var refKey = getRefKey(fieldDef);
|
var refKey = GetRefKey(fieldDef);
|
||||||
if (!refToValue.ContainsKey(refKey) ||
|
if (!refToValue.ContainsKey(refKey) ||
|
||||||
getAccessibilityOrder(fieldDef) < getAccessibilityOrder(refToKey[refKey])) {
|
GetAccessibilityOrder(fieldDef) < GetAccessibilityOrder(refToKey[refKey])) {
|
||||||
refToKey[refKey] = fieldDef;
|
refToKey[refKey] = fieldDef;
|
||||||
refToValue[refKey] = value;
|
refToValue[refKey] = value;
|
||||||
}
|
}
|
||||||
|
@ -169,26 +169,26 @@ namespace de4dot.blocks {
|
||||||
0, // Public
|
0, // Public
|
||||||
70, // <reserved>
|
70, // <reserved>
|
||||||
};
|
};
|
||||||
static int getAccessibilityOrder(FieldDef fieldDef) {
|
static int GetAccessibilityOrder(FieldDef fieldDef) {
|
||||||
return accessibilityOrder[(int)fieldDef.Attributes & 7];
|
return accessibilityOrder[(int)fieldDef.Attributes & 7];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onTypesRenamed() {
|
public void OnTypesRenamed() {
|
||||||
var newFieldRefToDef = new Dictionary<IFieldRefKey, TValue>(refToValue.Count);
|
var newFieldRefToDef = new Dictionary<IFieldRefKey, TValue>(refToValue.Count);
|
||||||
foreach (var kvp in refToValue)
|
foreach (var kvp in refToValue)
|
||||||
newFieldRefToDef[getRefKey((FieldDef)kvp.Key.FieldRef)] = kvp.Value;
|
newFieldRefToDef[GetRefKey((FieldDef)kvp.Key.FieldRef)] = kvp.Value;
|
||||||
refToValue = newFieldRefToDef;
|
refToValue = newFieldRefToDef;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class FieldDefDict<TValue> : FieldDefDictBase<TValue> {
|
public class FieldDefDict<TValue> : FieldDefDictBase<TValue> {
|
||||||
internal override IFieldRefKey getRefKey(IField fieldRef) {
|
internal override IFieldRefKey GetRefKey(IField fieldRef) {
|
||||||
return new FieldRefKey(fieldRef);
|
return new FieldRefKey(fieldRef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class FieldDefAndDeclaringTypeDict<TValue> : FieldDefDictBase<TValue> {
|
public class FieldDefAndDeclaringTypeDict<TValue> : FieldDefDictBase<TValue> {
|
||||||
internal override IFieldRefKey getRefKey(IField fieldRef) {
|
internal override IFieldRefKey GetRefKey(IField fieldRef) {
|
||||||
return new FieldRefAndDeclaringTypeKey(fieldRef);
|
return new FieldRefAndDeclaringTypeKey(fieldRef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,48 +203,48 @@ namespace de4dot.blocks {
|
||||||
get { return tokenToValue.Count; }
|
get { return tokenToValue.Count; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<MethodDef> getKeys() {
|
public IEnumerable<MethodDef> GetKeys() {
|
||||||
return tokenToKey.Values;
|
return tokenToKey.Values;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<TValue> getValues() {
|
public IEnumerable<TValue> GetValues() {
|
||||||
return tokenToValue.Values;
|
return tokenToValue.Values;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopeAndTokenKey getTokenKey(MethodDef methodDef) {
|
ScopeAndTokenKey GetTokenKey(MethodDef methodDef) {
|
||||||
return new ScopeAndTokenKey(methodDef);
|
return new ScopeAndTokenKey(methodDef);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal abstract IMethodRefKey getRefKey(IMethod methodRef);
|
internal abstract IMethodRefKey GetRefKey(IMethod methodRef);
|
||||||
|
|
||||||
public TValue find(IMethod methodRef) {
|
public TValue Find(IMethod methodRef) {
|
||||||
TValue value;
|
TValue value;
|
||||||
var methodDef = methodRef as MethodDef;
|
var methodDef = methodRef as MethodDef;
|
||||||
if (methodDef != null)
|
if (methodDef != null)
|
||||||
tokenToValue.TryGetValue(getTokenKey(methodDef), out value);
|
tokenToValue.TryGetValue(GetTokenKey(methodDef), out value);
|
||||||
else
|
else
|
||||||
refToValue.TryGetValue(getRefKey(methodRef), out value);
|
refToValue.TryGetValue(GetRefKey(methodRef), out value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TValue findAny(IMethod methodRef) {
|
public TValue FindAny(IMethod methodRef) {
|
||||||
TValue value;
|
TValue value;
|
||||||
var methodDef = methodRef as MethodDef;
|
var methodDef = methodRef as MethodDef;
|
||||||
if (methodDef != null && tokenToValue.TryGetValue(getTokenKey(methodDef), out value))
|
if (methodDef != null && tokenToValue.TryGetValue(GetTokenKey(methodDef), out value))
|
||||||
return value;
|
return value;
|
||||||
|
|
||||||
refToValue.TryGetValue(getRefKey(methodRef), out value);
|
refToValue.TryGetValue(GetRefKey(methodRef), out value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(MethodDef methodDef, TValue value) {
|
public void Add(MethodDef methodDef, TValue value) {
|
||||||
var tokenKey = getTokenKey(methodDef);
|
var tokenKey = GetTokenKey(methodDef);
|
||||||
tokenToValue[tokenKey] = value;
|
tokenToValue[tokenKey] = value;
|
||||||
tokenToKey[tokenKey] = methodDef;
|
tokenToKey[tokenKey] = methodDef;
|
||||||
|
|
||||||
var refKey = getRefKey(methodDef);
|
var refKey = GetRefKey(methodDef);
|
||||||
if (!refToValue.ContainsKey(refKey) ||
|
if (!refToValue.ContainsKey(refKey) ||
|
||||||
getAccessibilityOrder(methodDef) < getAccessibilityOrder(refToKey[refKey])) {
|
GetAccessibilityOrder(methodDef) < GetAccessibilityOrder(refToKey[refKey])) {
|
||||||
refToKey[refKey] = methodDef;
|
refToKey[refKey] = methodDef;
|
||||||
refToValue[refKey] = value;
|
refToValue[refKey] = value;
|
||||||
}
|
}
|
||||||
|
@ -261,26 +261,26 @@ namespace de4dot.blocks {
|
||||||
0, // Public
|
0, // Public
|
||||||
70, // <reserved>
|
70, // <reserved>
|
||||||
};
|
};
|
||||||
static int getAccessibilityOrder(MethodDef methodDef) {
|
static int GetAccessibilityOrder(MethodDef methodDef) {
|
||||||
return accessibilityOrder[(int)methodDef.Attributes & 7];
|
return accessibilityOrder[(int)methodDef.Attributes & 7];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onTypesRenamed() {
|
public void OnTypesRenamed() {
|
||||||
var newFieldRefToDef = new Dictionary<IMethodRefKey, TValue>(refToValue.Count);
|
var newFieldRefToDef = new Dictionary<IMethodRefKey, TValue>(refToValue.Count);
|
||||||
foreach (var kvp in refToValue)
|
foreach (var kvp in refToValue)
|
||||||
newFieldRefToDef[getRefKey((MethodDef)kvp.Key.MethodRef)] = kvp.Value;
|
newFieldRefToDef[GetRefKey((MethodDef)kvp.Key.MethodRef)] = kvp.Value;
|
||||||
refToValue = newFieldRefToDef;
|
refToValue = newFieldRefToDef;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MethodDefDict<TValue> : MethodDefDictBase<TValue> {
|
public class MethodDefDict<TValue> : MethodDefDictBase<TValue> {
|
||||||
internal override IMethodRefKey getRefKey(IMethod methodRef) {
|
internal override IMethodRefKey GetRefKey(IMethod methodRef) {
|
||||||
return new MethodRefKey(methodRef);
|
return new MethodRefKey(methodRef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MethodDefAndDeclaringTypeDict<TValue> : MethodDefDictBase<TValue> {
|
public class MethodDefAndDeclaringTypeDict<TValue> : MethodDefDictBase<TValue> {
|
||||||
internal override IMethodRefKey getRefKey(IMethod methodRef) {
|
internal override IMethodRefKey GetRefKey(IMethod methodRef) {
|
||||||
return new MethodRefAndDeclaringTypeKey(methodRef);
|
return new MethodRefAndDeclaringTypeKey(methodRef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -294,59 +294,59 @@ namespace de4dot.blocks {
|
||||||
get { return tokenToValue.Count; }
|
get { return tokenToValue.Count; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<EventDef> getKeys() {
|
public IEnumerable<EventDef> GetKeys() {
|
||||||
return tokenToKey.Values;
|
return tokenToKey.Values;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<TValue> getValues() {
|
public IEnumerable<TValue> GetValues() {
|
||||||
return tokenToValue.Values;
|
return tokenToValue.Values;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopeAndTokenKey getTokenKey(EventDef eventRef) {
|
ScopeAndTokenKey GetTokenKey(EventDef eventRef) {
|
||||||
return new ScopeAndTokenKey(eventRef);
|
return new ScopeAndTokenKey(eventRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal abstract IEventRefKey getRefKey(EventDef eventRef);
|
internal abstract IEventRefKey GetRefKey(EventDef eventRef);
|
||||||
|
|
||||||
public TValue find(EventDef eventRef) {
|
public TValue Find(EventDef eventRef) {
|
||||||
TValue value;
|
TValue value;
|
||||||
tokenToValue.TryGetValue(getTokenKey(eventRef), out value);
|
tokenToValue.TryGetValue(GetTokenKey(eventRef), out value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TValue findAny(EventDef eventRef) {
|
public TValue FindAny(EventDef eventRef) {
|
||||||
TValue value;
|
TValue value;
|
||||||
if (tokenToValue.TryGetValue(getTokenKey(eventRef), out value))
|
if (tokenToValue.TryGetValue(GetTokenKey(eventRef), out value))
|
||||||
return value;
|
return value;
|
||||||
|
|
||||||
refToValue.TryGetValue(getRefKey(eventRef), out value);
|
refToValue.TryGetValue(GetRefKey(eventRef), out value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(EventDef eventDef, TValue value) {
|
public void Add(EventDef eventDef, TValue value) {
|
||||||
var tokenKey = getTokenKey(eventDef);
|
var tokenKey = GetTokenKey(eventDef);
|
||||||
tokenToValue[tokenKey] = value;
|
tokenToValue[tokenKey] = value;
|
||||||
tokenToKey[tokenKey] = eventDef;
|
tokenToKey[tokenKey] = eventDef;
|
||||||
|
|
||||||
refToValue[getRefKey(eventDef)] = value;
|
refToValue[GetRefKey(eventDef)] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onTypesRenamed() {
|
public void OnTypesRenamed() {
|
||||||
var newFieldRefToDef = new Dictionary<IEventRefKey, TValue>(refToValue.Count);
|
var newFieldRefToDef = new Dictionary<IEventRefKey, TValue>(refToValue.Count);
|
||||||
foreach (var kvp in refToValue)
|
foreach (var kvp in refToValue)
|
||||||
newFieldRefToDef[getRefKey((EventDef)kvp.Key.EventDef)] = kvp.Value;
|
newFieldRefToDef[GetRefKey((EventDef)kvp.Key.EventDef)] = kvp.Value;
|
||||||
refToValue = newFieldRefToDef;
|
refToValue = newFieldRefToDef;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class EventDefDict<TValue> : EventDefDictBase<TValue> {
|
public class EventDefDict<TValue> : EventDefDictBase<TValue> {
|
||||||
internal override IEventRefKey getRefKey(EventDef eventRef) {
|
internal override IEventRefKey GetRefKey(EventDef eventRef) {
|
||||||
return new EventRefKey(eventRef);
|
return new EventRefKey(eventRef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class EventDefAndDeclaringTypeDict<TValue> : EventDefDictBase<TValue> {
|
public class EventDefAndDeclaringTypeDict<TValue> : EventDefDictBase<TValue> {
|
||||||
internal override IEventRefKey getRefKey(EventDef eventRef) {
|
internal override IEventRefKey GetRefKey(EventDef eventRef) {
|
||||||
return new EventRefAndDeclaringTypeKey(eventRef);
|
return new EventRefAndDeclaringTypeKey(eventRef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -360,59 +360,59 @@ namespace de4dot.blocks {
|
||||||
get { return tokenToValue.Count; }
|
get { return tokenToValue.Count; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<PropertyDef> getKeys() {
|
public IEnumerable<PropertyDef> GetKeys() {
|
||||||
return tokenToKey.Values;
|
return tokenToKey.Values;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<TValue> getValues() {
|
public IEnumerable<TValue> GetValues() {
|
||||||
return tokenToValue.Values;
|
return tokenToValue.Values;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopeAndTokenKey getTokenKey(PropertyDef propertyRef) {
|
ScopeAndTokenKey GetTokenKey(PropertyDef propertyRef) {
|
||||||
return new ScopeAndTokenKey(propertyRef);
|
return new ScopeAndTokenKey(propertyRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal abstract IPropertyRefKey getRefKey(PropertyDef propertyRef);
|
internal abstract IPropertyRefKey GetRefKey(PropertyDef propertyRef);
|
||||||
|
|
||||||
public TValue find(PropertyDef propRef) {
|
public TValue Find(PropertyDef propRef) {
|
||||||
TValue value;
|
TValue value;
|
||||||
tokenToValue.TryGetValue(getTokenKey(propRef), out value);
|
tokenToValue.TryGetValue(GetTokenKey(propRef), out value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TValue findAny(PropertyDef propRef) {
|
public TValue FindAny(PropertyDef propRef) {
|
||||||
TValue value;
|
TValue value;
|
||||||
if (tokenToValue.TryGetValue(getTokenKey(propRef), out value))
|
if (tokenToValue.TryGetValue(GetTokenKey(propRef), out value))
|
||||||
return value;
|
return value;
|
||||||
|
|
||||||
refToValue.TryGetValue(getRefKey(propRef), out value);
|
refToValue.TryGetValue(GetRefKey(propRef), out value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(PropertyDef propDef, TValue value) {
|
public void Add(PropertyDef propDef, TValue value) {
|
||||||
var tokenKey = getTokenKey(propDef);
|
var tokenKey = GetTokenKey(propDef);
|
||||||
tokenToValue[tokenKey] = value;
|
tokenToValue[tokenKey] = value;
|
||||||
tokenToKey[tokenKey] = propDef;
|
tokenToKey[tokenKey] = propDef;
|
||||||
|
|
||||||
refToValue[getRefKey(propDef)] = value;
|
refToValue[GetRefKey(propDef)] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onTypesRenamed() {
|
public void OnTypesRenamed() {
|
||||||
var newFieldRefToDef = new Dictionary<IPropertyRefKey, TValue>(refToValue.Count);
|
var newFieldRefToDef = new Dictionary<IPropertyRefKey, TValue>(refToValue.Count);
|
||||||
foreach (var kvp in refToValue)
|
foreach (var kvp in refToValue)
|
||||||
newFieldRefToDef[getRefKey((PropertyDef)kvp.Key.PropertyDef)] = kvp.Value;
|
newFieldRefToDef[GetRefKey((PropertyDef)kvp.Key.PropertyDef)] = kvp.Value;
|
||||||
refToValue = newFieldRefToDef;
|
refToValue = newFieldRefToDef;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PropertyDefDict<TValue> : PropertyDefDictBase<TValue> {
|
public class PropertyDefDict<TValue> : PropertyDefDictBase<TValue> {
|
||||||
internal override IPropertyRefKey getRefKey(PropertyDef propRef) {
|
internal override IPropertyRefKey GetRefKey(PropertyDef propRef) {
|
||||||
return new PropertyRefKey(propRef);
|
return new PropertyRefKey(propRef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PropertyDefAndDeclaringTypeDict<TValue> : PropertyDefDictBase<TValue> {
|
public class PropertyDefAndDeclaringTypeDict<TValue> : PropertyDefDictBase<TValue> {
|
||||||
internal override IPropertyRefKey getRefKey(PropertyDef propRef) {
|
internal override IPropertyRefKey GetRefKey(PropertyDef propRef) {
|
||||||
return new PropertyRefAndDeclaringTypeKey(propRef);
|
return new PropertyRefAndDeclaringTypeKey(propRef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -467,16 +467,16 @@ namespace de4dot.blocks {
|
||||||
return true;
|
return true;
|
||||||
if (a == null || b == null)
|
if (a == null || b == null)
|
||||||
return false;
|
return false;
|
||||||
return getCanonicalizedScopeName(a) == getCanonicalizedScopeName(b);
|
return GetCanonicalizedScopeName(a) == GetCanonicalizedScopeName(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int GetHashCode(IScope a) {
|
static int GetHashCode(IScope a) {
|
||||||
if (a == null)
|
if (a == null)
|
||||||
return 0;
|
return 0;
|
||||||
return getCanonicalizedScopeName(a).GetHashCode();
|
return GetCanonicalizedScopeName(a).GetHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
static string getAssemblyName(IScope a) {
|
static string GetAssemblyName(IScope a) {
|
||||||
switch (a.ScopeType) {
|
switch (a.ScopeType) {
|
||||||
case ScopeType.AssemblyRef:
|
case ScopeType.AssemblyRef:
|
||||||
return ((AssemblyRef)a).Name.String;
|
return ((AssemblyRef)a).Name.String;
|
||||||
|
@ -489,10 +489,10 @@ namespace de4dot.blocks {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
static string getCanonicalizedScopeName(IScope a) {
|
static string GetCanonicalizedScopeName(IScope a) {
|
||||||
if (a == null)
|
if (a == null)
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
var asmName = getAssemblyName(a);
|
var asmName = GetAssemblyName(a);
|
||||||
if (asmName != null) {
|
if (asmName != null) {
|
||||||
// The version number should be ignored. Older code may reference an old version of
|
// The version number should be ignored. Older code may reference an old version of
|
||||||
// the assembly, but if the newer one has been loaded, that one is used.
|
// the assembly, but if the newer one has been loaded, that one is used.
|
||||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
[assembly: AssemblyVersion("2.0.2.3405")]
|
[assembly: AssemblyVersion("2.0.3.3405")]
|
||||||
[assembly: AssemblyFileVersion("2.0.2.3405")]
|
[assembly: AssemblyFileVersion("2.0.3.3405")]
|
||||||
|
|
|
@ -32,52 +32,52 @@ namespace de4dot.blocks {
|
||||||
set { baseBlocks = value; }
|
set { baseBlocks = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<BaseBlock> getBaseBlocks() {
|
public IEnumerable<BaseBlock> GetBaseBlocks() {
|
||||||
if (baseBlocks != null) {
|
if (baseBlocks != null) {
|
||||||
foreach (var bb in baseBlocks)
|
foreach (var bb in baseBlocks)
|
||||||
yield return bb;
|
yield return bb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<BaseBlock> getAllBaseBlocks() {
|
public List<BaseBlock> GetAllBaseBlocks() {
|
||||||
return getTheBlocks(new List<BaseBlock>());
|
return GetTheBlocks(new List<BaseBlock>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Block> getAllBlocks() {
|
public List<Block> GetAllBlocks() {
|
||||||
return getTheBlocks(new List<Block>());
|
return GetTheBlocks(new List<Block>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Block> getAllBlocks(List<Block> allBlocks) {
|
public List<Block> GetAllBlocks(List<Block> allBlocks) {
|
||||||
allBlocks.Clear();
|
allBlocks.Clear();
|
||||||
return getTheBlocks(allBlocks);
|
return GetTheBlocks(allBlocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ScopeBlock> getAllScopeBlocks() {
|
public List<ScopeBlock> GetAllScopeBlocks() {
|
||||||
return getTheBlocks(new List<ScopeBlock>());
|
return GetTheBlocks(new List<ScopeBlock>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<T> getTheBlocks<T>(List<T> list) where T : BaseBlock {
|
public List<T> GetTheBlocks<T>(List<T> list) where T : BaseBlock {
|
||||||
addBlocks(list, this);
|
AddBlocks(list, this);
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addBlocks<T>(IList<T> list, ScopeBlock scopeBlock) where T : BaseBlock {
|
void AddBlocks<T>(IList<T> list, ScopeBlock scopeBlock) where T : BaseBlock {
|
||||||
foreach (var bb in scopeBlock.getBaseBlocks()) {
|
foreach (var bb in scopeBlock.GetBaseBlocks()) {
|
||||||
T t = bb as T;
|
T t = bb as T;
|
||||||
if (t != null)
|
if (t != null)
|
||||||
list.Add(t);
|
list.Add(t);
|
||||||
if (bb is ScopeBlock)
|
if (bb is ScopeBlock)
|
||||||
addBlocks(list, (ScopeBlock)bb);
|
AddBlocks(list, (ScopeBlock)bb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Block> findBlocks() {
|
List<Block> FindBlocks() {
|
||||||
return findBlocks(null);
|
return FindBlocks(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Block> findBlocks(Func<Block, bool> blockChecker) {
|
List<Block> FindBlocks(Func<Block, bool> blockChecker) {
|
||||||
var blocks = new List<Block>();
|
var blocks = new List<Block>();
|
||||||
foreach (var bb in getBaseBlocks()) {
|
foreach (var bb in GetBaseBlocks()) {
|
||||||
Block block = bb as Block;
|
Block block = bb as Block;
|
||||||
if (block != null && (blockChecker == null || blockChecker(block)))
|
if (block != null && (blockChecker == null || blockChecker(block)))
|
||||||
blocks.Add(block);
|
blocks.Add(block);
|
||||||
|
@ -85,7 +85,7 @@ namespace de4dot.blocks {
|
||||||
return blocks;
|
return blocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool getLdcValue(Instr instr, out int value) {
|
internal bool GetLdcValue(Instr instr, out int value) {
|
||||||
if (Code.Ldc_I4_0 <= instr.OpCode.Code && instr.OpCode.Code <= Code.Ldc_I4_8)
|
if (Code.Ldc_I4_0 <= instr.OpCode.Code && instr.OpCode.Code <= Code.Ldc_I4_8)
|
||||||
value = instr.OpCode.Code - Code.Ldc_I4_0;
|
value = instr.OpCode.Code - Code.Ldc_I4_0;
|
||||||
else if (instr.OpCode.Code == Code.Ldc_I4)
|
else if (instr.OpCode.Code == Code.Ldc_I4)
|
||||||
|
@ -103,18 +103,18 @@ namespace de4dot.blocks {
|
||||||
|
|
||||||
// Remove the block if it's a dead block. If it has refs to other dead blocks, those
|
// Remove the block if it's a dead block. If it has refs to other dead blocks, those
|
||||||
// are also removed.
|
// are also removed.
|
||||||
public void removeDeadBlock(Block block) {
|
public void RemoveDeadBlock(Block block) {
|
||||||
removeDeadBlocks(new List<Block> { block });
|
RemoveDeadBlocks(new List<Block> { block });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all dead blocks we can find
|
// Remove all dead blocks we can find
|
||||||
public void removeDeadBlocks() {
|
public void RemoveDeadBlocks() {
|
||||||
removeDeadBlocks(findBlocks());
|
RemoveDeadBlocks(FindBlocks());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the blocks if they're dead blocks. If they have refs to other dead blocks,
|
// Remove the blocks if they're dead blocks. If they have refs to other dead blocks,
|
||||||
// those are also removed.
|
// those are also removed.
|
||||||
public void removeDeadBlocks(List<Block> blocks) {
|
public void RemoveDeadBlocks(List<Block> blocks) {
|
||||||
while (blocks.Count != 0) {
|
while (blocks.Count != 0) {
|
||||||
var block = blocks[blocks.Count - 1];
|
var block = blocks[blocks.Count - 1];
|
||||||
blocks.RemoveAt(blocks.Count - 1);
|
blocks.RemoveAt(blocks.Count - 1);
|
||||||
|
@ -122,7 +122,7 @@ namespace de4dot.blocks {
|
||||||
continue; // Not dead
|
continue; // Not dead
|
||||||
if (block == baseBlocks[0])
|
if (block == baseBlocks[0])
|
||||||
continue; // It's the start of this block fence so must be present
|
continue; // It's the start of this block fence so must be present
|
||||||
if (!isOurBaseBlock(block))
|
if (!IsOurBaseBlock(block))
|
||||||
continue; // Some other ScopeBlock owns it, eg. first instr of an exception handler
|
continue; // Some other ScopeBlock owns it, eg. first instr of an exception handler
|
||||||
|
|
||||||
// It's a dead block we can delete!
|
// It's a dead block we can delete!
|
||||||
|
@ -131,27 +131,27 @@ namespace de4dot.blocks {
|
||||||
blocks.Add(block.FallThrough);
|
blocks.Add(block.FallThrough);
|
||||||
if (block.Targets != null)
|
if (block.Targets != null)
|
||||||
blocks.AddRange(block.Targets);
|
blocks.AddRange(block.Targets);
|
||||||
block.removeDeadBlock();
|
block.RemoveDeadBlock();
|
||||||
if (!baseBlocks.Remove(block))
|
if (!baseBlocks.Remove(block))
|
||||||
throw new ApplicationException("Could not remove dead block from baseBlocks");
|
throw new ApplicationException("Could not remove dead block from baseBlocks");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isOurBaseBlock(BaseBlock bb) {
|
public bool IsOurBaseBlock(BaseBlock bb) {
|
||||||
return bb != null && bb.Parent == this;
|
return bb != null && bb.Parent == this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For each block, if it has only one target, and the target has only one source, then
|
// For each block, if it has only one target, and the target has only one source, then
|
||||||
// merge them into one block.
|
// merge them into one block.
|
||||||
public int mergeBlocks() {
|
public int MergeBlocks() {
|
||||||
int mergedBlocks = 0;
|
int mergedBlocks = 0;
|
||||||
var blocks = findBlocks();
|
var blocks = FindBlocks();
|
||||||
for (int i = 0; i < blocks.Count; i++) {
|
for (int i = 0; i < blocks.Count; i++) {
|
||||||
var block = blocks[i];
|
var block = blocks[i];
|
||||||
var target = block.getOnlyTarget();
|
var target = block.GetOnlyTarget();
|
||||||
if (!isOurBaseBlock(target))
|
if (!IsOurBaseBlock(target))
|
||||||
continue; // Only merge blocks we own!
|
continue; // Only merge blocks we own!
|
||||||
if (!block.canMerge(target))
|
if (!block.CanMerge(target))
|
||||||
continue; // Can't merge them!
|
continue; // Can't merge them!
|
||||||
if (target == baseBlocks[0])
|
if (target == baseBlocks[0])
|
||||||
continue; // The first one has an implicit source (eg. start of method or exception handler)
|
continue; // The first one has an implicit source (eg. start of method or exception handler)
|
||||||
|
@ -160,7 +160,7 @@ namespace de4dot.blocks {
|
||||||
if (targetIndex < 0)
|
if (targetIndex < 0)
|
||||||
throw new ApplicationException("Could not remove target block from blocks");
|
throw new ApplicationException("Could not remove target block from blocks");
|
||||||
blocks.RemoveAt(targetIndex);
|
blocks.RemoveAt(targetIndex);
|
||||||
block.merge(target);
|
block.Merge(target);
|
||||||
if (!baseBlocks.Remove(target))
|
if (!baseBlocks.Remove(target))
|
||||||
throw new ApplicationException("Could not remove merged block from baseBlocks");
|
throw new ApplicationException("Could not remove merged block from baseBlocks");
|
||||||
if (targetIndex < i)
|
if (targetIndex < i)
|
||||||
|
@ -174,20 +174,20 @@ namespace de4dot.blocks {
|
||||||
|
|
||||||
// If bb is in baseBlocks (a direct child), return bb. If bb is a BaseBlock in a
|
// If bb is in baseBlocks (a direct child), return bb. If bb is a BaseBlock in a
|
||||||
// ScopeBlock that is a direct child, then return that ScopeBlock. Else return null.
|
// ScopeBlock that is a direct child, then return that ScopeBlock. Else return null.
|
||||||
public BaseBlock toChild(BaseBlock bb) {
|
public BaseBlock ToChild(BaseBlock bb) {
|
||||||
if (isOurBaseBlock(bb))
|
if (IsOurBaseBlock(bb))
|
||||||
return bb;
|
return bb;
|
||||||
|
|
||||||
for (var sb = bb.Parent; sb != null; sb = sb.Parent) {
|
for (var sb = bb.Parent; sb != null; sb = sb.Parent) {
|
||||||
if (isOurBaseBlock(sb))
|
if (IsOurBaseBlock(sb))
|
||||||
return sb;
|
return sb;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void repartitionBlocks() {
|
internal void RepartitionBlocks() {
|
||||||
var newBaseBlocks = new BlocksSorter(this).sort();
|
var newBaseBlocks = new BlocksSorter(this).Sort();
|
||||||
|
|
||||||
const bool insane = true;
|
const bool insane = true;
|
||||||
if (insane) {
|
if (insane) {
|
||||||
|
@ -206,7 +206,7 @@ namespace de4dot.blocks {
|
||||||
|
|
||||||
// Removes the TryBlock and all its TryHandlerBlocks. The code inside the try block
|
// Removes the TryBlock and all its TryHandlerBlocks. The code inside the try block
|
||||||
// is not removed.
|
// is not removed.
|
||||||
public void removeTryBlock(TryBlock tryBlock) {
|
public void RemoveTryBlock(TryBlock tryBlock) {
|
||||||
int tryBlockIndex = baseBlocks.IndexOf(tryBlock);
|
int tryBlockIndex = baseBlocks.IndexOf(tryBlock);
|
||||||
if (tryBlockIndex < 0)
|
if (tryBlockIndex < 0)
|
||||||
throw new ApplicationException("Can't remove the TryBlock since it's not this ScopeBlock's TryBlock");
|
throw new ApplicationException("Can't remove the TryBlock since it's not this ScopeBlock's TryBlock");
|
||||||
|
@ -220,15 +220,15 @@ namespace de4dot.blocks {
|
||||||
// Get removed blocks and make sure they're not referenced by remaining code
|
// Get removed blocks and make sure they're not referenced by remaining code
|
||||||
var removedBlocks = new List<Block>();
|
var removedBlocks = new List<Block>();
|
||||||
foreach (var handler in tryBlock.TryHandlerBlocks)
|
foreach (var handler in tryBlock.TryHandlerBlocks)
|
||||||
handler.getTheBlocks(removedBlocks);
|
handler.GetTheBlocks(removedBlocks);
|
||||||
if (!verifyNoExternalRefs(removedBlocks))
|
if (!VerifyNoExternalRefs(removedBlocks))
|
||||||
throw new ApplicationException("Removed blocks are referenced by remaining code");
|
throw new ApplicationException("Removed blocks are referenced by remaining code");
|
||||||
|
|
||||||
removeAllDeadBlocks(Utils.convert<TryHandlerBlock, BaseBlock>(tryBlock.TryHandlerBlocks));
|
RemoveAllDeadBlocks(Utils.Convert<TryHandlerBlock, BaseBlock>(tryBlock.TryHandlerBlocks));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if no external blocks references the blocks
|
// Returns true if no external blocks references the blocks
|
||||||
static bool verifyNoExternalRefs(IList<Block> removedBlocks) {
|
static bool VerifyNoExternalRefs(IList<Block> removedBlocks) {
|
||||||
var removedDict = new Dictionary<Block, bool>();
|
var removedDict = new Dictionary<Block, bool>();
|
||||||
foreach (var removedBlock in removedBlocks)
|
foreach (var removedBlock in removedBlocks)
|
||||||
removedDict[removedBlock] = true;
|
removedDict[removedBlock] = true;
|
||||||
|
@ -243,13 +243,13 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all blocks in deadBlocks. They're guaranteed to be dead.
|
// Remove all blocks in deadBlocks. They're guaranteed to be dead.
|
||||||
void removeAllDeadBlocks(IEnumerable<BaseBlock> deadBlocks) {
|
void RemoveAllDeadBlocks(IEnumerable<BaseBlock> deadBlocks) {
|
||||||
removeAllDeadBlocks(deadBlocks, null);
|
RemoveAllDeadBlocks(deadBlocks, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all blocks in deadBlocks. They're guaranteed to be dead. deadBlocksDict is
|
// Remove all blocks in deadBlocks. They're guaranteed to be dead. deadBlocksDict is
|
||||||
// a dictionary of all dead blocks (even those not in this ScopeBlock).
|
// a dictionary of all dead blocks (even those not in this ScopeBlock).
|
||||||
internal void removeAllDeadBlocks(IEnumerable<BaseBlock> deadBlocks, Dictionary<BaseBlock, bool> deadBlocksDict) {
|
internal void RemoveAllDeadBlocks(IEnumerable<BaseBlock> deadBlocks, Dictionary<BaseBlock, bool> deadBlocksDict) {
|
||||||
|
|
||||||
// Verify that all the blocks really are dead. If all their source blocks are
|
// Verify that all the blocks really are dead. If all their source blocks are
|
||||||
// dead, then they are dead.
|
// dead, then they are dead.
|
||||||
|
@ -260,7 +260,7 @@ namespace de4dot.blocks {
|
||||||
allDeadBlocks.Add(bb as Block);
|
allDeadBlocks.Add(bb as Block);
|
||||||
else if (bb is ScopeBlock) {
|
else if (bb is ScopeBlock) {
|
||||||
var sb = (ScopeBlock)bb;
|
var sb = (ScopeBlock)bb;
|
||||||
allDeadBlocks.AddRange(sb.getAllBlocks());
|
allDeadBlocks.AddRange(sb.GetAllBlocks());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw new ApplicationException(string.Format("Unknown BaseBlock type {0}", bb.GetType()));
|
throw new ApplicationException(string.Format("Unknown BaseBlock type {0}", bb.GetType()));
|
||||||
|
@ -278,20 +278,20 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var block in allDeadBlocks)
|
foreach (var block in allDeadBlocks)
|
||||||
block.removeGuaranteedDeadBlock();
|
block.RemoveGuaranteedDeadBlock();
|
||||||
foreach (var bb in deadBlocks) {
|
foreach (var bb in deadBlocks) {
|
||||||
if (!baseBlocks.Remove(bb))
|
if (!baseBlocks.Remove(bb))
|
||||||
throw new ApplicationException("Could not remove dead base block from baseBlocks");
|
throw new ApplicationException("Could not remove dead base block from baseBlocks");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeGuaranteedDeadBlock(Block block) {
|
public void RemoveGuaranteedDeadBlock(Block block) {
|
||||||
if (!baseBlocks.Remove(block))
|
if (!baseBlocks.Remove(block))
|
||||||
throw new ApplicationException("Could not remove dead block");
|
throw new ApplicationException("Could not remove dead block");
|
||||||
block.removeGuaranteedDeadBlock();
|
block.RemoveGuaranteedDeadBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(Block block) {
|
public void Add(Block block) {
|
||||||
if (block.Parent != null)
|
if (block.Parent != null)
|
||||||
throw new ApplicationException("Block already has a parent");
|
throw new ApplicationException("Block already has a parent");
|
||||||
baseBlocks.Add(block);
|
baseBlocks.Add(block);
|
||||||
|
|
|
@ -31,7 +31,7 @@ namespace de4dot.blocks {
|
||||||
get { return handlerBlocks; }
|
get { return handlerBlocks; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addTryHandler(TryHandlerBlock tryHandlerBlock) {
|
public void AddTryHandler(TryHandlerBlock tryHandlerBlock) {
|
||||||
handlerBlocks.Add(tryHandlerBlock);
|
handlerBlocks.Add(tryHandlerBlock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,21 +47,21 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
|
|
||||||
static class Utils {
|
static class Utils {
|
||||||
public static IDictionary<T, int> createObjectToIndexDictionary<T>(IList<T> objs) {
|
public static IDictionary<T, int> CreateObjectToIndexDictionary<T>(IList<T> objs) {
|
||||||
var dict = new Dictionary<T, int>();
|
var dict = new Dictionary<T, int>();
|
||||||
for (int i = 0; i < objs.Count; i++)
|
for (int i = 0; i < objs.Count; i++)
|
||||||
dict[objs[i]] = i;
|
dict[objs[i]] = i;
|
||||||
return dict;
|
return dict;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<TOut> convert<TIn, TOut>(IEnumerable<TIn> list) where TIn : TOut {
|
public static List<TOut> Convert<TIn, TOut>(IEnumerable<TIn> list) where TIn : TOut {
|
||||||
var olist = new List<TOut>();
|
var olist = new List<TOut>();
|
||||||
foreach (var l in list)
|
foreach (var l in list)
|
||||||
olist.Add(l);
|
olist.Add(l);
|
||||||
return olist;
|
return olist;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<T> unique<T>(IEnumerable<T> values) {
|
public static IEnumerable<T> Unique<T>(IEnumerable<T> values) {
|
||||||
// HashSet is only available in .NET 3.5 and later.
|
// HashSet is only available in .NET 3.5 and later.
|
||||||
var dict = new Dictionary<T, bool>();
|
var dict = new Dictionary<T, bool>();
|
||||||
foreach (var val in values)
|
foreach (var val in values)
|
||||||
|
|
|
@ -31,11 +31,11 @@ namespace de4dot.blocks.cflow {
|
||||||
branchEmulator = new BranchEmulator(instructionEmulator, this);
|
branchEmulator = new BranchEmulator(instructionEmulator, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool deobfuscate(Block block) {
|
protected override bool Deobfuscate(Block block) {
|
||||||
this.block = block;
|
this.block = block;
|
||||||
if (!block.LastInstr.isConditionalBranch() && block.LastInstr.OpCode.Code != Code.Switch)
|
if (!block.LastInstr.IsConditionalBranch() && block.LastInstr.OpCode.Code != Code.Switch)
|
||||||
return false;
|
return false;
|
||||||
instructionEmulator.init(blocks);
|
instructionEmulator.Initialize(blocks);
|
||||||
|
|
||||||
var instructions = block.Instructions;
|
var instructions = block.Instructions;
|
||||||
if (instructions.Count == 0)
|
if (instructions.Count == 0)
|
||||||
|
@ -43,7 +43,7 @@ namespace de4dot.blocks.cflow {
|
||||||
try {
|
try {
|
||||||
for (int i = 0; i < instructions.Count - 1; i++) {
|
for (int i = 0; i < instructions.Count - 1; i++) {
|
||||||
var instr = instructions[i].Instruction;
|
var instr = instructions[i].Instruction;
|
||||||
instructionEmulator.emulate(instr);
|
instructionEmulator.Emulate(instr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (NullReferenceException) {
|
catch (NullReferenceException) {
|
||||||
|
@ -51,28 +51,28 @@ namespace de4dot.blocks.cflow {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return branchEmulator.emulate(block.LastInstr.Instruction);
|
return branchEmulator.Emulate(block.LastInstr.Instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
void popPushedArgs(int stackArgs) {
|
void PopPushedArgs(int stackArgs) {
|
||||||
// Pop the arguments to the bcc instruction. The dead code remover will get rid of the
|
// Pop the arguments to the bcc instruction. The dead code remover will get rid of the
|
||||||
// pop and any pushed arguments. Insert the pops just before the bcc instr.
|
// pop and any pushed arguments. Insert the pops just before the bcc instr.
|
||||||
for (int i = 0; i < stackArgs; i++)
|
for (int i = 0; i < stackArgs; i++)
|
||||||
block.insert(block.Instructions.Count - 1, OpCodes.Pop.ToInstruction());
|
block.Insert(block.Instructions.Count - 1, OpCodes.Pop.ToInstruction());
|
||||||
}
|
}
|
||||||
|
|
||||||
void IBranchHandler.handleNormal(int stackArgs, bool isTaken) {
|
void IBranchHandler.HandleNormal(int stackArgs, bool isTaken) {
|
||||||
popPushedArgs(stackArgs);
|
PopPushedArgs(stackArgs);
|
||||||
block.replaceBccWithBranch(isTaken);
|
block.ReplaceBccWithBranch(isTaken);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IBranchHandler.handleSwitch(Int32Value switchIndex) {
|
bool IBranchHandler.HandleSwitch(Int32Value switchIndex) {
|
||||||
var target = CflowUtils.getSwitchTarget(block.Targets, block.FallThrough, switchIndex);
|
var target = CflowUtils.GetSwitchTarget(block.Targets, block.FallThrough, switchIndex);
|
||||||
if (target == null)
|
if (target == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
popPushedArgs(1);
|
PopPushedArgs(1);
|
||||||
block.replaceSwitchWithBranch(target);
|
block.ReplaceSwitchWithBranch(target);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,17 +27,17 @@ namespace de4dot.blocks.cflow {
|
||||||
|
|
||||||
public bool ExecuteOnNoChange { get; set; }
|
public bool ExecuteOnNoChange { get; set; }
|
||||||
|
|
||||||
public virtual void deobfuscateBegin(Blocks blocks) {
|
public virtual void DeobfuscateBegin(Blocks blocks) {
|
||||||
this.blocks = blocks;
|
this.blocks = blocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool deobfuscate(List<Block> allBlocks) {
|
public bool Deobfuscate(List<Block> allBlocks) {
|
||||||
init(allBlocks);
|
Initialize(allBlocks);
|
||||||
|
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
foreach (var block in allBlocks) {
|
foreach (var block in allBlocks) {
|
||||||
try {
|
try {
|
||||||
changed |= deobfuscate(block);
|
changed |= Deobfuscate(block);
|
||||||
}
|
}
|
||||||
catch (NullReferenceException) {
|
catch (NullReferenceException) {
|
||||||
// Here if eg. invalid metadata token in a call instruction (operand is null)
|
// Here if eg. invalid metadata token in a call instruction (operand is null)
|
||||||
|
@ -46,10 +46,10 @@ namespace de4dot.blocks.cflow {
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void init(List<Block> allBlocks) {
|
protected virtual void Initialize(List<Block> allBlocks) {
|
||||||
this.allBlocks = allBlocks;
|
this.allBlocks = allBlocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract bool deobfuscate(Block block);
|
protected abstract bool Deobfuscate(Block block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,15 +28,15 @@ namespace de4dot.blocks.cflow {
|
||||||
List<IBlocksDeobfuscator> ourBlocksDeobfuscators = new List<IBlocksDeobfuscator>();
|
List<IBlocksDeobfuscator> ourBlocksDeobfuscators = new List<IBlocksDeobfuscator>();
|
||||||
|
|
||||||
public BlocksCflowDeobfuscator() {
|
public BlocksCflowDeobfuscator() {
|
||||||
init();
|
Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public BlocksCflowDeobfuscator(IEnumerable<IBlocksDeobfuscator> blocksDeobfuscator) {
|
public BlocksCflowDeobfuscator(IEnumerable<IBlocksDeobfuscator> blocksDeobfuscator) {
|
||||||
init();
|
Initialize();
|
||||||
add(blocksDeobfuscator);
|
Add(blocksDeobfuscator);
|
||||||
}
|
}
|
||||||
|
|
||||||
void init() {
|
void Initialize() {
|
||||||
ourBlocksDeobfuscators.Add(new BlockCflowDeobfuscator { ExecuteOnNoChange = false });
|
ourBlocksDeobfuscators.Add(new BlockCflowDeobfuscator { ExecuteOnNoChange = false });
|
||||||
ourBlocksDeobfuscators.Add(new SwitchCflowDeobfuscator { ExecuteOnNoChange = false });
|
ourBlocksDeobfuscators.Add(new SwitchCflowDeobfuscator { ExecuteOnNoChange = false });
|
||||||
ourBlocksDeobfuscators.Add(new DeadStoreRemover { ExecuteOnNoChange = false });
|
ourBlocksDeobfuscators.Add(new DeadStoreRemover { ExecuteOnNoChange = false });
|
||||||
|
@ -46,73 +46,73 @@ namespace de4dot.blocks.cflow {
|
||||||
ourBlocksDeobfuscators.Add(new DupBlockCflowDeobfuscator { ExecuteOnNoChange = true });
|
ourBlocksDeobfuscators.Add(new DupBlockCflowDeobfuscator { ExecuteOnNoChange = true });
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(IEnumerable<IBlocksDeobfuscator> blocksDeobfuscators) {
|
public void Add(IEnumerable<IBlocksDeobfuscator> blocksDeobfuscators) {
|
||||||
foreach (var bd in blocksDeobfuscators)
|
foreach (var bd in blocksDeobfuscators)
|
||||||
add(bd);
|
Add(bd);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(IBlocksDeobfuscator blocksDeobfuscator) {
|
public void Add(IBlocksDeobfuscator blocksDeobfuscator) {
|
||||||
if (blocksDeobfuscator != null)
|
if (blocksDeobfuscator != null)
|
||||||
userBlocksDeobfuscators.Add(blocksDeobfuscator);
|
userBlocksDeobfuscators.Add(blocksDeobfuscator);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init(Blocks blocks) {
|
public void Initialize(Blocks blocks) {
|
||||||
this.blocks = blocks;
|
this.blocks = blocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deobfuscate() {
|
public void Deobfuscate() {
|
||||||
bool changed;
|
bool changed;
|
||||||
int iterations = -1;
|
int iterations = -1;
|
||||||
|
|
||||||
deobfuscateBegin(userBlocksDeobfuscators);
|
DeobfuscateBegin(userBlocksDeobfuscators);
|
||||||
deobfuscateBegin(ourBlocksDeobfuscators);
|
DeobfuscateBegin(ourBlocksDeobfuscators);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
iterations++;
|
iterations++;
|
||||||
changed = false;
|
changed = false;
|
||||||
removeDeadBlocks();
|
RemoveDeadBlocks();
|
||||||
mergeBlocks();
|
MergeBlocks();
|
||||||
|
|
||||||
blocks.MethodBlocks.getAllBlocks(allBlocks);
|
blocks.MethodBlocks.GetAllBlocks(allBlocks);
|
||||||
|
|
||||||
if (iterations == 0)
|
if (iterations == 0)
|
||||||
changed |= fixDotfuscatorLoop();
|
changed |= FixDotfuscatorLoop();
|
||||||
|
|
||||||
changed |= deobfuscate(userBlocksDeobfuscators, allBlocks);
|
changed |= Deobfuscate(userBlocksDeobfuscators, allBlocks);
|
||||||
changed |= deobfuscate(ourBlocksDeobfuscators, allBlocks);
|
changed |= Deobfuscate(ourBlocksDeobfuscators, allBlocks);
|
||||||
changed |= deobfuscateNoChange(changed, userBlocksDeobfuscators, allBlocks);
|
changed |= DeobfuscateNoChange(changed, userBlocksDeobfuscators, allBlocks);
|
||||||
changed |= deobfuscateNoChange(changed, ourBlocksDeobfuscators, allBlocks);
|
changed |= DeobfuscateNoChange(changed, ourBlocksDeobfuscators, allBlocks);
|
||||||
} while (changed);
|
} while (changed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void deobfuscateBegin(IEnumerable<IBlocksDeobfuscator> bds) {
|
void DeobfuscateBegin(IEnumerable<IBlocksDeobfuscator> bds) {
|
||||||
foreach (var bd in bds)
|
foreach (var bd in bds)
|
||||||
bd.deobfuscateBegin(blocks);
|
bd.DeobfuscateBegin(blocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool deobfuscate(IEnumerable<IBlocksDeobfuscator> bds, List<Block> allBlocks) {
|
bool Deobfuscate(IEnumerable<IBlocksDeobfuscator> bds, List<Block> allBlocks) {
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
foreach (var bd in bds) {
|
foreach (var bd in bds) {
|
||||||
if (bd.ExecuteOnNoChange)
|
if (bd.ExecuteOnNoChange)
|
||||||
continue;
|
continue;
|
||||||
changed |= bd.deobfuscate(allBlocks);
|
changed |= bd.Deobfuscate(allBlocks);
|
||||||
}
|
}
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool deobfuscateNoChange(bool changed, IEnumerable<IBlocksDeobfuscator> bds, List<Block> allBlocks) {
|
bool DeobfuscateNoChange(bool changed, IEnumerable<IBlocksDeobfuscator> bds, List<Block> allBlocks) {
|
||||||
foreach (var bd in bds) {
|
foreach (var bd in bds) {
|
||||||
if (changed)
|
if (changed)
|
||||||
break;
|
break;
|
||||||
if (!bd.ExecuteOnNoChange)
|
if (!bd.ExecuteOnNoChange)
|
||||||
continue;
|
continue;
|
||||||
changed |= bd.deobfuscate(allBlocks);
|
changed |= bd.Deobfuscate(allBlocks);
|
||||||
}
|
}
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hack for old Dotfuscator
|
// Hack for old Dotfuscator
|
||||||
bool fixDotfuscatorLoop() {
|
bool FixDotfuscatorLoop() {
|
||||||
/*
|
/*
|
||||||
blk1:
|
blk1:
|
||||||
...
|
...
|
||||||
|
@ -136,7 +136,7 @@ namespace de4dot.blocks.cflow {
|
||||||
continue;
|
continue;
|
||||||
if (instructions[1].OpCode.Code != Code.Dup)
|
if (instructions[1].OpCode.Code != Code.Dup)
|
||||||
continue;
|
continue;
|
||||||
if (!instructions[2].isLdcI4())
|
if (!instructions[2].IsLdcI4())
|
||||||
continue;
|
continue;
|
||||||
if (instructions[3].OpCode.Code != Code.Sub && instructions[3].OpCode.Code != Code.Add)
|
if (instructions[3].OpCode.Code != Code.Sub && instructions[3].OpCode.Code != Code.Add)
|
||||||
continue;
|
continue;
|
||||||
|
@ -148,32 +148,32 @@ namespace de4dot.blocks.cflow {
|
||||||
var prev = block.Sources[0];
|
var prev = block.Sources[0];
|
||||||
if (prev == block)
|
if (prev == block)
|
||||||
prev = block.Sources[1];
|
prev = block.Sources[1];
|
||||||
if (prev == null || !prev.LastInstr.isLdcI4())
|
if (prev == null || !prev.LastInstr.IsLdcI4())
|
||||||
continue;
|
continue;
|
||||||
var next = block.FallThrough;
|
var next = block.FallThrough;
|
||||||
if (next.FirstInstr.OpCode.Code != Code.Pop)
|
if (next.FirstInstr.OpCode.Code != Code.Pop)
|
||||||
continue;
|
continue;
|
||||||
block.replaceLastInstrsWithBranch(5, next);
|
block.ReplaceLastInstrsWithBranch(5, next);
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool removeDeadBlocks() {
|
bool RemoveDeadBlocks() {
|
||||||
return new DeadBlocksRemover(blocks.MethodBlocks).remove() > 0;
|
return new DeadBlocksRemover(blocks.MethodBlocks).Remove() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mergeBlocks() {
|
bool MergeBlocks() {
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
foreach (var scopeBlock in getAllScopeBlocks(blocks.MethodBlocks))
|
foreach (var scopeBlock in GetAllScopeBlocks(blocks.MethodBlocks))
|
||||||
changed |= scopeBlock.mergeBlocks() > 0;
|
changed |= scopeBlock.MergeBlocks() > 0;
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerable<ScopeBlock> getAllScopeBlocks(ScopeBlock scopeBlock) {
|
IEnumerable<ScopeBlock> GetAllScopeBlocks(ScopeBlock scopeBlock) {
|
||||||
var list = new List<ScopeBlock>();
|
var list = new List<ScopeBlock>();
|
||||||
list.Add(scopeBlock);
|
list.Add(scopeBlock);
|
||||||
list.AddRange(scopeBlock.getAllScopeBlocks());
|
list.AddRange(scopeBlock.GetAllScopeBlocks());
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,10 +22,10 @@ using dnlib.DotNet.Emit;
|
||||||
namespace de4dot.blocks.cflow {
|
namespace de4dot.blocks.cflow {
|
||||||
public interface IBranchHandler {
|
public interface IBranchHandler {
|
||||||
// stackArgs is the number of args used by the branch instruction (1 or 2)
|
// stackArgs is the number of args used by the branch instruction (1 or 2)
|
||||||
void handleNormal(int stackArgs, bool isTaken);
|
void HandleNormal(int stackArgs, bool isTaken);
|
||||||
|
|
||||||
// Returns true if the switch target was found (even if it was the fall-through)
|
// Returns true if the switch target was found (even if it was the fall-through)
|
||||||
bool handleSwitch(Int32Value switchIndex);
|
bool HandleSwitch(Int32Value switchIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BranchEmulator {
|
public class BranchEmulator {
|
||||||
|
@ -37,216 +37,216 @@ namespace de4dot.blocks.cflow {
|
||||||
this.branchHandler = branchHandler;
|
this.branchHandler = branchHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool emulate(Instruction instr) {
|
public bool Emulate(Instruction instr) {
|
||||||
switch (instr.OpCode.Code) {
|
switch (instr.OpCode.Code) {
|
||||||
case Code.Br:
|
case Code.Br:
|
||||||
case Code.Br_S: return emulate_Br();
|
case Code.Br_S: return Emulate_Br();
|
||||||
case Code.Beq:
|
case Code.Beq:
|
||||||
case Code.Beq_S: return emulate_Beq();
|
case Code.Beq_S: return Emulate_Beq();
|
||||||
case Code.Bge:
|
case Code.Bge:
|
||||||
case Code.Bge_S: return emulate_Bge();
|
case Code.Bge_S: return Emulate_Bge();
|
||||||
case Code.Bge_Un:
|
case Code.Bge_Un:
|
||||||
case Code.Bge_Un_S: return emulate_Bge_Un();
|
case Code.Bge_Un_S: return Emulate_Bge_Un();
|
||||||
case Code.Bgt:
|
case Code.Bgt:
|
||||||
case Code.Bgt_S: return emulate_Bgt();
|
case Code.Bgt_S: return Emulate_Bgt();
|
||||||
case Code.Bgt_Un:
|
case Code.Bgt_Un:
|
||||||
case Code.Bgt_Un_S: return emulate_Bgt_Un();
|
case Code.Bgt_Un_S: return Emulate_Bgt_Un();
|
||||||
case Code.Ble:
|
case Code.Ble:
|
||||||
case Code.Ble_S: return emulate_Ble();
|
case Code.Ble_S: return Emulate_Ble();
|
||||||
case Code.Ble_Un:
|
case Code.Ble_Un:
|
||||||
case Code.Ble_Un_S: return emulate_Ble_Un();
|
case Code.Ble_Un_S: return Emulate_Ble_Un();
|
||||||
case Code.Blt:
|
case Code.Blt:
|
||||||
case Code.Blt_S: return emulate_Blt();
|
case Code.Blt_S: return Emulate_Blt();
|
||||||
case Code.Blt_Un:
|
case Code.Blt_Un:
|
||||||
case Code.Blt_Un_S: return emulate_Blt_Un();
|
case Code.Blt_Un_S: return Emulate_Blt_Un();
|
||||||
case Code.Bne_Un:
|
case Code.Bne_Un:
|
||||||
case Code.Bne_Un_S: return emulate_Bne_Un();
|
case Code.Bne_Un_S: return Emulate_Bne_Un();
|
||||||
case Code.Brfalse:
|
case Code.Brfalse:
|
||||||
case Code.Brfalse_S:return emulate_Brfalse();
|
case Code.Brfalse_S:return Emulate_Brfalse();
|
||||||
case Code.Brtrue:
|
case Code.Brtrue:
|
||||||
case Code.Brtrue_S: return emulate_Brtrue();
|
case Code.Brtrue_S: return Emulate_Brtrue();
|
||||||
case Code.Switch: return emulate_Switch();
|
case Code.Switch: return Emulate_Switch();
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool emulateBranch(int stackArgs, Bool3 cond) {
|
bool EmulateBranch(int stackArgs, Bool3 cond) {
|
||||||
if (cond == Bool3.Unknown)
|
if (cond == Bool3.Unknown)
|
||||||
return false;
|
return false;
|
||||||
return emulateBranch(stackArgs, cond == Bool3.True);
|
return EmulateBranch(stackArgs, cond == Bool3.True);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool emulateBranch(int stackArgs, bool isTaken) {
|
bool EmulateBranch(int stackArgs, bool isTaken) {
|
||||||
branchHandler.handleNormal(stackArgs, isTaken);
|
branchHandler.HandleNormal(stackArgs, isTaken);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool emulate_Br() {
|
bool Emulate_Br() {
|
||||||
return emulateBranch(0, true);
|
return EmulateBranch(0, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool emulate_Beq() {
|
bool Emulate_Beq() {
|
||||||
var val2 = instructionEmulator.pop();
|
var val2 = instructionEmulator.Pop();
|
||||||
var val1 = instructionEmulator.pop();
|
var val1 = instructionEmulator.Pop();
|
||||||
|
|
||||||
if (val1.isInt32() && val2.isInt32())
|
if (val1.IsInt32() && val2.IsInt32())
|
||||||
return emulateBranch(2, Int32Value.compareEq((Int32Value)val1, (Int32Value)val2));
|
return EmulateBranch(2, Int32Value.CompareEq((Int32Value)val1, (Int32Value)val2));
|
||||||
else if (val1.isInt64() && val2.isInt64())
|
else if (val1.IsInt64() && val2.IsInt64())
|
||||||
return emulateBranch(2, Int64Value.compareEq((Int64Value)val1, (Int64Value)val2));
|
return EmulateBranch(2, Int64Value.CompareEq((Int64Value)val1, (Int64Value)val2));
|
||||||
else if (val1.isNull() && val2.isNull())
|
else if (val1.IsNull() && val2.IsNull())
|
||||||
return emulateBranch(2, true);
|
return EmulateBranch(2, true);
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool emulate_Bne_Un() {
|
bool Emulate_Bne_Un() {
|
||||||
var val2 = instructionEmulator.pop();
|
var val2 = instructionEmulator.Pop();
|
||||||
var val1 = instructionEmulator.pop();
|
var val1 = instructionEmulator.Pop();
|
||||||
|
|
||||||
if (val1.isInt32() && val2.isInt32())
|
if (val1.IsInt32() && val2.IsInt32())
|
||||||
return emulateBranch(2, Int32Value.compareNeq((Int32Value)val1, (Int32Value)val2));
|
return EmulateBranch(2, Int32Value.CompareNeq((Int32Value)val1, (Int32Value)val2));
|
||||||
else if (val1.isInt64() && val2.isInt64())
|
else if (val1.IsInt64() && val2.IsInt64())
|
||||||
return emulateBranch(2, Int64Value.compareNeq((Int64Value)val1, (Int64Value)val2));
|
return EmulateBranch(2, Int64Value.CompareNeq((Int64Value)val1, (Int64Value)val2));
|
||||||
else if (val1.isNull() && val2.isNull())
|
else if (val1.IsNull() && val2.IsNull())
|
||||||
return emulateBranch(2, false);
|
return EmulateBranch(2, false);
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool emulate_Bge() {
|
bool Emulate_Bge() {
|
||||||
var val2 = instructionEmulator.pop();
|
var val2 = instructionEmulator.Pop();
|
||||||
var val1 = instructionEmulator.pop();
|
var val1 = instructionEmulator.Pop();
|
||||||
|
|
||||||
if (val1.isInt32() && val2.isInt32())
|
if (val1.IsInt32() && val2.IsInt32())
|
||||||
return emulateBranch(2, Int32Value.compareGe((Int32Value)val1, (Int32Value)val2));
|
return EmulateBranch(2, Int32Value.CompareGe((Int32Value)val1, (Int32Value)val2));
|
||||||
else if (val1.isInt64() && val2.isInt64())
|
else if (val1.IsInt64() && val2.IsInt64())
|
||||||
return emulateBranch(2, Int64Value.compareGe((Int64Value)val1, (Int64Value)val2));
|
return EmulateBranch(2, Int64Value.CompareGe((Int64Value)val1, (Int64Value)val2));
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool emulate_Bge_Un() {
|
bool Emulate_Bge_Un() {
|
||||||
var val2 = instructionEmulator.pop();
|
var val2 = instructionEmulator.Pop();
|
||||||
var val1 = instructionEmulator.pop();
|
var val1 = instructionEmulator.Pop();
|
||||||
|
|
||||||
if (val1.isInt32() && val2.isInt32())
|
if (val1.IsInt32() && val2.IsInt32())
|
||||||
return emulateBranch(2, Int32Value.compareGe_Un((Int32Value)val1, (Int32Value)val2));
|
return EmulateBranch(2, Int32Value.CompareGe_Un((Int32Value)val1, (Int32Value)val2));
|
||||||
else if (val1.isInt64() && val2.isInt64())
|
else if (val1.IsInt64() && val2.IsInt64())
|
||||||
return emulateBranch(2, Int64Value.compareGe_Un((Int64Value)val1, (Int64Value)val2));
|
return EmulateBranch(2, Int64Value.CompareGe_Un((Int64Value)val1, (Int64Value)val2));
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool emulate_Bgt() {
|
bool Emulate_Bgt() {
|
||||||
var val2 = instructionEmulator.pop();
|
var val2 = instructionEmulator.Pop();
|
||||||
var val1 = instructionEmulator.pop();
|
var val1 = instructionEmulator.Pop();
|
||||||
|
|
||||||
if (val1.isInt32() && val2.isInt32())
|
if (val1.IsInt32() && val2.IsInt32())
|
||||||
return emulateBranch(2, Int32Value.compareGt((Int32Value)val1, (Int32Value)val2));
|
return EmulateBranch(2, Int32Value.CompareGt((Int32Value)val1, (Int32Value)val2));
|
||||||
else if (val1.isInt64() && val2.isInt64())
|
else if (val1.IsInt64() && val2.IsInt64())
|
||||||
return emulateBranch(2, Int64Value.compareGt((Int64Value)val1, (Int64Value)val2));
|
return EmulateBranch(2, Int64Value.CompareGt((Int64Value)val1, (Int64Value)val2));
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool emulate_Bgt_Un() {
|
bool Emulate_Bgt_Un() {
|
||||||
var val2 = instructionEmulator.pop();
|
var val2 = instructionEmulator.Pop();
|
||||||
var val1 = instructionEmulator.pop();
|
var val1 = instructionEmulator.Pop();
|
||||||
|
|
||||||
if (val1.isInt32() && val2.isInt32())
|
if (val1.IsInt32() && val2.IsInt32())
|
||||||
return emulateBranch(2, Int32Value.compareGt_Un((Int32Value)val1, (Int32Value)val2));
|
return EmulateBranch(2, Int32Value.CompareGt_Un((Int32Value)val1, (Int32Value)val2));
|
||||||
else if (val1.isInt64() && val2.isInt64())
|
else if (val1.IsInt64() && val2.IsInt64())
|
||||||
return emulateBranch(2, Int64Value.compareGt_Un((Int64Value)val1, (Int64Value)val2));
|
return EmulateBranch(2, Int64Value.CompareGt_Un((Int64Value)val1, (Int64Value)val2));
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool emulate_Ble() {
|
bool Emulate_Ble() {
|
||||||
var val2 = instructionEmulator.pop();
|
var val2 = instructionEmulator.Pop();
|
||||||
var val1 = instructionEmulator.pop();
|
var val1 = instructionEmulator.Pop();
|
||||||
|
|
||||||
if (val1.isInt32() && val2.isInt32())
|
if (val1.IsInt32() && val2.IsInt32())
|
||||||
return emulateBranch(2, Int32Value.compareLe((Int32Value)val1, (Int32Value)val2));
|
return EmulateBranch(2, Int32Value.CompareLe((Int32Value)val1, (Int32Value)val2));
|
||||||
else if (val1.isInt64() && val2.isInt64())
|
else if (val1.IsInt64() && val2.IsInt64())
|
||||||
return emulateBranch(2, Int64Value.compareLe((Int64Value)val1, (Int64Value)val2));
|
return EmulateBranch(2, Int64Value.CompareLe((Int64Value)val1, (Int64Value)val2));
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool emulate_Ble_Un() {
|
bool Emulate_Ble_Un() {
|
||||||
var val2 = instructionEmulator.pop();
|
var val2 = instructionEmulator.Pop();
|
||||||
var val1 = instructionEmulator.pop();
|
var val1 = instructionEmulator.Pop();
|
||||||
|
|
||||||
if (val1.isInt32() && val2.isInt32())
|
if (val1.IsInt32() && val2.IsInt32())
|
||||||
return emulateBranch(2, Int32Value.compareLe_Un((Int32Value)val1, (Int32Value)val2));
|
return EmulateBranch(2, Int32Value.CompareLe_Un((Int32Value)val1, (Int32Value)val2));
|
||||||
else if (val1.isInt64() && val2.isInt64())
|
else if (val1.IsInt64() && val2.IsInt64())
|
||||||
return emulateBranch(2, Int64Value.compareLe_Un((Int64Value)val1, (Int64Value)val2));
|
return EmulateBranch(2, Int64Value.CompareLe_Un((Int64Value)val1, (Int64Value)val2));
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool emulate_Blt() {
|
bool Emulate_Blt() {
|
||||||
var val2 = instructionEmulator.pop();
|
var val2 = instructionEmulator.Pop();
|
||||||
var val1 = instructionEmulator.pop();
|
var val1 = instructionEmulator.Pop();
|
||||||
|
|
||||||
if (val1.isInt32() && val2.isInt32())
|
if (val1.IsInt32() && val2.IsInt32())
|
||||||
return emulateBranch(2, Int32Value.compareLt((Int32Value)val1, (Int32Value)val2));
|
return EmulateBranch(2, Int32Value.CompareLt((Int32Value)val1, (Int32Value)val2));
|
||||||
else if (val1.isInt64() && val2.isInt64())
|
else if (val1.IsInt64() && val2.IsInt64())
|
||||||
return emulateBranch(2, Int64Value.compareLt((Int64Value)val1, (Int64Value)val2));
|
return EmulateBranch(2, Int64Value.CompareLt((Int64Value)val1, (Int64Value)val2));
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool emulate_Blt_Un() {
|
bool Emulate_Blt_Un() {
|
||||||
var val2 = instructionEmulator.pop();
|
var val2 = instructionEmulator.Pop();
|
||||||
var val1 = instructionEmulator.pop();
|
var val1 = instructionEmulator.Pop();
|
||||||
|
|
||||||
if (val1.isInt32() && val2.isInt32())
|
if (val1.IsInt32() && val2.IsInt32())
|
||||||
return emulateBranch(2, Int32Value.compareLt_Un((Int32Value)val1, (Int32Value)val2));
|
return EmulateBranch(2, Int32Value.CompareLt_Un((Int32Value)val1, (Int32Value)val2));
|
||||||
else if (val1.isInt64() && val2.isInt64())
|
else if (val1.IsInt64() && val2.IsInt64())
|
||||||
return emulateBranch(2, Int64Value.compareLt_Un((Int64Value)val1, (Int64Value)val2));
|
return EmulateBranch(2, Int64Value.CompareLt_Un((Int64Value)val1, (Int64Value)val2));
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool emulate_Brfalse() {
|
bool Emulate_Brfalse() {
|
||||||
var val1 = instructionEmulator.pop();
|
var val1 = instructionEmulator.Pop();
|
||||||
|
|
||||||
if (val1.isInt32())
|
if (val1.IsInt32())
|
||||||
return emulateBranch(1, Int32Value.compareFalse((Int32Value)val1));
|
return EmulateBranch(1, Int32Value.CompareFalse((Int32Value)val1));
|
||||||
else if (val1.isInt64())
|
else if (val1.IsInt64())
|
||||||
return emulateBranch(1, Int64Value.compareFalse((Int64Value)val1));
|
return EmulateBranch(1, Int64Value.CompareFalse((Int64Value)val1));
|
||||||
else if (val1.isNull())
|
else if (val1.IsNull())
|
||||||
return emulateBranch(1, true);
|
return EmulateBranch(1, true);
|
||||||
else if (val1.isObject() || val1.isString())
|
else if (val1.IsObject() || val1.IsString())
|
||||||
return emulateBranch(1, false);
|
return EmulateBranch(1, false);
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool emulate_Brtrue() {
|
bool Emulate_Brtrue() {
|
||||||
var val1 = instructionEmulator.pop();
|
var val1 = instructionEmulator.Pop();
|
||||||
|
|
||||||
if (val1.isInt32())
|
if (val1.IsInt32())
|
||||||
return emulateBranch(1, Int32Value.compareTrue((Int32Value)val1));
|
return EmulateBranch(1, Int32Value.CompareTrue((Int32Value)val1));
|
||||||
else if (val1.isInt64())
|
else if (val1.IsInt64())
|
||||||
return emulateBranch(1, Int64Value.compareTrue((Int64Value)val1));
|
return EmulateBranch(1, Int64Value.CompareTrue((Int64Value)val1));
|
||||||
else if (val1.isNull())
|
else if (val1.IsNull())
|
||||||
return emulateBranch(1, false);
|
return EmulateBranch(1, false);
|
||||||
else if (val1.isObject() || val1.isString())
|
else if (val1.IsObject() || val1.IsString())
|
||||||
return emulateBranch(1, true);
|
return EmulateBranch(1, true);
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool emulate_Switch() {
|
bool Emulate_Switch() {
|
||||||
var val1 = instructionEmulator.pop();
|
var val1 = instructionEmulator.Pop();
|
||||||
|
|
||||||
if (!val1.isInt32())
|
if (!val1.IsInt32())
|
||||||
return false;
|
return false;
|
||||||
return branchHandler.handleSwitch((Int32Value)val1);
|
return branchHandler.HandleSwitch((Int32Value)val1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,19 +31,19 @@ namespace de4dot.blocks.cflow {
|
||||||
}
|
}
|
||||||
|
|
||||||
public CachedCflowDeobfuscator(IEnumerable<IBlocksDeobfuscator> blocksDeobfuscators) {
|
public CachedCflowDeobfuscator(IEnumerable<IBlocksDeobfuscator> blocksDeobfuscators) {
|
||||||
add(blocksDeobfuscators);
|
Add(blocksDeobfuscators);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(IEnumerable<IBlocksDeobfuscator> blocksDeobfuscators) {
|
public void Add(IEnumerable<IBlocksDeobfuscator> blocksDeobfuscators) {
|
||||||
foreach (var bd in blocksDeobfuscators)
|
foreach (var bd in blocksDeobfuscators)
|
||||||
cflowDeobfuscator.add(bd);
|
cflowDeobfuscator.Add(bd);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(IBlocksDeobfuscator blocksDeobfuscator) {
|
public void Add(IBlocksDeobfuscator blocksDeobfuscator) {
|
||||||
cflowDeobfuscator.add(blocksDeobfuscator);
|
cflowDeobfuscator.Add(blocksDeobfuscator);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodDef deobfuscate(MethodDef method) {
|
public MethodDef Deobfuscate(MethodDef method) {
|
||||||
MethodDef deobfuscatedMethod;
|
MethodDef deobfuscatedMethod;
|
||||||
if (deobfuscated.TryGetValue(method, out deobfuscatedMethod))
|
if (deobfuscated.TryGetValue(method, out deobfuscatedMethod))
|
||||||
return deobfuscatedMethod;
|
return deobfuscatedMethod;
|
||||||
|
@ -53,22 +53,22 @@ namespace de4dot.blocks.cflow {
|
||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
|
|
||||||
deobfuscatedMethod = DotNetUtils.clone(method);
|
deobfuscatedMethod = DotNetUtils.Clone(method);
|
||||||
deobfuscated[method] = deobfuscatedMethod;
|
deobfuscated[method] = deobfuscatedMethod;
|
||||||
|
|
||||||
var blocks = new Blocks(deobfuscatedMethod);
|
var blocks = new Blocks(deobfuscatedMethod);
|
||||||
deobfuscate(blocks);
|
Deobfuscate(blocks);
|
||||||
IList<Instruction> allInstructions;
|
IList<Instruction> allInstructions;
|
||||||
IList<ExceptionHandler> allExceptionHandlers;
|
IList<ExceptionHandler> allExceptionHandlers;
|
||||||
blocks.getCode(out allInstructions, out allExceptionHandlers);
|
blocks.GetCode(out allInstructions, out allExceptionHandlers);
|
||||||
DotNetUtils.restoreBody(deobfuscatedMethod, allInstructions, allExceptionHandlers);
|
DotNetUtils.RestoreBody(deobfuscatedMethod, allInstructions, allExceptionHandlers);
|
||||||
|
|
||||||
return deobfuscatedMethod;
|
return deobfuscatedMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
void deobfuscate(Blocks blocks) {
|
void Deobfuscate(Blocks blocks) {
|
||||||
cflowDeobfuscator.init(blocks);
|
cflowDeobfuscator.Initialize(blocks);
|
||||||
cflowDeobfuscator.deobfuscate();
|
cflowDeobfuscator.Deobfuscate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,30 +29,30 @@ namespace de4dot.blocks.cflow {
|
||||||
}
|
}
|
||||||
|
|
||||||
public CflowDeobfuscator(IBlocksDeobfuscator blocksDeobfuscator) {
|
public CflowDeobfuscator(IBlocksDeobfuscator blocksDeobfuscator) {
|
||||||
cflowDeobfuscator.add(blocksDeobfuscator);
|
cflowDeobfuscator.Add(blocksDeobfuscator);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deobfuscate(MethodDef method) {
|
public void Deobfuscate(MethodDef method) {
|
||||||
deobfuscate(method, (blocks) => {
|
Deobfuscate(method, (blocks) => {
|
||||||
cflowDeobfuscator.init(blocks);
|
cflowDeobfuscator.Initialize(blocks);
|
||||||
cflowDeobfuscator.deobfuscate();
|
cflowDeobfuscator.Deobfuscate();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool hasNonEmptyBody(MethodDef method) {
|
static bool HasNonEmptyBody(MethodDef method) {
|
||||||
return method.Body != null && method.Body.Instructions.Count > 0;
|
return method.Body != null && method.Body.Instructions.Count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void deobfuscate(MethodDef method, Action<Blocks> handler) {
|
void Deobfuscate(MethodDef method, Action<Blocks> handler) {
|
||||||
if (hasNonEmptyBody(method)) {
|
if (HasNonEmptyBody(method)) {
|
||||||
var blocks = new Blocks(method);
|
var blocks = new Blocks(method);
|
||||||
|
|
||||||
handler(blocks);
|
handler(blocks);
|
||||||
|
|
||||||
IList<Instruction> allInstructions;
|
IList<Instruction> allInstructions;
|
||||||
IList<ExceptionHandler> allExceptionHandlers;
|
IList<ExceptionHandler> allExceptionHandlers;
|
||||||
blocks.getCode(out allInstructions, out allExceptionHandlers);
|
blocks.GetCode(out allInstructions, out allExceptionHandlers);
|
||||||
DotNetUtils.restoreBody(method, allInstructions, allExceptionHandlers);
|
DotNetUtils.RestoreBody(method, allInstructions, allExceptionHandlers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +21,8 @@ using System.Collections.Generic;
|
||||||
|
|
||||||
namespace de4dot.blocks.cflow {
|
namespace de4dot.blocks.cflow {
|
||||||
static class CflowUtils {
|
static class CflowUtils {
|
||||||
public static Block getSwitchTarget(IList<Block> targets, Block fallThrough, Int32Value intValue) {
|
public static Block GetSwitchTarget(IList<Block> targets, Block fallThrough, Int32Value intValue) {
|
||||||
if (!intValue.allBitsValid())
|
if (!intValue.AllBitsValid())
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
int index = intValue.value;
|
int index = intValue.value;
|
||||||
|
|
|
@ -29,15 +29,15 @@ namespace de4dot.blocks.cflow {
|
||||||
InstructionEmulator instructionEmulator = new InstructionEmulator();
|
InstructionEmulator instructionEmulator = new InstructionEmulator();
|
||||||
IList<Parameter> args;
|
IList<Parameter> args;
|
||||||
|
|
||||||
protected override void init(List<Block> allBlocks) {
|
protected override void Initialize(List<Block> allBlocks) {
|
||||||
base.init(allBlocks);
|
base.Initialize(allBlocks);
|
||||||
args = blocks.Method.Parameters;
|
args = blocks.Method.Parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool deobfuscate(Block block) {
|
protected override bool Deobfuscate(Block block) {
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
|
||||||
instructionEmulator.init(blocks);
|
instructionEmulator.Initialize(blocks);
|
||||||
var instrs = block.Instructions;
|
var instrs = block.Instructions;
|
||||||
for (int i = 0; i < instrs.Count; i++) {
|
for (int i = 0; i < instrs.Count; i++) {
|
||||||
var instr = instrs[i];
|
var instr = instrs[i];
|
||||||
|
@ -49,7 +49,7 @@ namespace de4dot.blocks.cflow {
|
||||||
case Code.Ldarg_2:
|
case Code.Ldarg_2:
|
||||||
case Code.Ldarg_3:
|
case Code.Ldarg_3:
|
||||||
case Code.Ldarg_S:
|
case Code.Ldarg_S:
|
||||||
changed |= fixLoadInstruction(block, i, instructionEmulator.getArg(instr.Instruction.GetParameter(args)));
|
changed |= FixLoadInstruction(block, i, instructionEmulator.GetArg(instr.Instruction.GetParameter(args)));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Code.Ldloc:
|
case Code.Ldloc:
|
||||||
|
@ -58,22 +58,22 @@ namespace de4dot.blocks.cflow {
|
||||||
case Code.Ldloc_2:
|
case Code.Ldloc_2:
|
||||||
case Code.Ldloc_3:
|
case Code.Ldloc_3:
|
||||||
case Code.Ldloc_S:
|
case Code.Ldloc_S:
|
||||||
changed |= fixLoadInstruction(block, i, instructionEmulator.getLocal(instr.Instruction.GetLocal(blocks.Locals)));
|
changed |= FixLoadInstruction(block, i, instructionEmulator.GetLocal(instr.Instruction.GetLocal(blocks.Locals)));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Code.Ldarga:
|
case Code.Ldarga:
|
||||||
case Code.Ldarga_S:
|
case Code.Ldarga_S:
|
||||||
instructionEmulator.makeArgUnknown((Parameter)instr.Operand);
|
instructionEmulator.MakeArgUnknown((Parameter)instr.Operand);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Code.Ldloca:
|
case Code.Ldloca:
|
||||||
case Code.Ldloca_S:
|
case Code.Ldloca_S:
|
||||||
instructionEmulator.makeLocalUnknown((Local)instr.Operand);
|
instructionEmulator.MakeLocalUnknown((Local)instr.Operand);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
instructionEmulator.emulate(instr.Instruction);
|
instructionEmulator.Emulate(instr.Instruction);
|
||||||
}
|
}
|
||||||
catch (NullReferenceException) {
|
catch (NullReferenceException) {
|
||||||
// Here if eg. invalid metadata token in a call instruction (operand is null)
|
// Here if eg. invalid metadata token in a call instruction (operand is null)
|
||||||
|
@ -84,17 +84,17 @@ namespace de4dot.blocks.cflow {
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fixLoadInstruction(Block block, int index, Value value) {
|
bool FixLoadInstruction(Block block, int index, Value value) {
|
||||||
if (value.isInt32()) {
|
if (value.IsInt32()) {
|
||||||
var intValue = (Int32Value)value;
|
var intValue = (Int32Value)value;
|
||||||
if (!intValue.allBitsValid())
|
if (!intValue.AllBitsValid())
|
||||||
return false;
|
return false;
|
||||||
block.Instructions[index] = new Instr(Instruction.CreateLdcI4(intValue.value));
|
block.Instructions[index] = new Instr(Instruction.CreateLdcI4(intValue.value));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (value.isInt64()) {
|
else if (value.IsInt64()) {
|
||||||
var intValue = (Int64Value)value;
|
var intValue = (Int64Value)value;
|
||||||
if (!intValue.allBitsValid())
|
if (!intValue.AllBitsValid())
|
||||||
return false;
|
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 true;
|
||||||
|
|
|
@ -27,7 +27,7 @@ namespace de4dot.blocks.cflow {
|
||||||
List<int> allDeadInstructions = new List<int>();
|
List<int> allDeadInstructions = new List<int>();
|
||||||
InstructionExpressionFinder instructionExpressionFinder = new InstructionExpressionFinder();
|
InstructionExpressionFinder instructionExpressionFinder = new InstructionExpressionFinder();
|
||||||
|
|
||||||
protected override bool deobfuscate(Block block) {
|
protected override bool Deobfuscate(Block block) {
|
||||||
allDeadInstructions.Clear();
|
allDeadInstructions.Clear();
|
||||||
|
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
@ -56,10 +56,10 @@ namespace de4dot.blocks.cflow {
|
||||||
case Code.Leave_S:
|
case Code.Leave_S:
|
||||||
case Code.Endfinally:
|
case Code.Endfinally:
|
||||||
case Code.Pop:
|
case Code.Pop:
|
||||||
instructionExpressionFinder.init(block, false);
|
instructionExpressionFinder.Initialize(block, false);
|
||||||
if (!instructionExpressionFinder.find(i))
|
if (!instructionExpressionFinder.Find(i))
|
||||||
continue;
|
continue;
|
||||||
if (!okInstructions(block, instructionExpressionFinder.DeadInstructions))
|
if (!OkInstructions(block, instructionExpressionFinder.DeadInstructions))
|
||||||
continue;
|
continue;
|
||||||
allDeadInstructions.AddRange(instructionExpressionFinder.DeadInstructions);
|
allDeadInstructions.AddRange(instructionExpressionFinder.DeadInstructions);
|
||||||
break;
|
break;
|
||||||
|
@ -70,14 +70,14 @@ namespace de4dot.blocks.cflow {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allDeadInstructions.Count > 0) {
|
if (allDeadInstructions.Count > 0) {
|
||||||
block.remove(allDeadInstructions);
|
block.Remove(allDeadInstructions);
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool okInstructions(Block block, IEnumerable<int> indexes) {
|
bool OkInstructions(Block block, IEnumerable<int> indexes) {
|
||||||
foreach (var index in indexes) {
|
foreach (var index in indexes) {
|
||||||
var instr = block.Instructions[index];
|
var instr = block.Instructions[index];
|
||||||
switch (instr.OpCode.Code) {
|
switch (instr.OpCode.Code) {
|
||||||
|
@ -318,27 +318,27 @@ namespace de4dot.blocks.cflow {
|
||||||
get { return deadInstructions; }
|
get { return deadInstructions; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init(Block block, bool methodHasReturnValue) {
|
public void Initialize(Block block, bool methodHasReturnValue) {
|
||||||
deadInstructions.Clear();
|
deadInstructions.Clear();
|
||||||
this.block = block;
|
this.block = block;
|
||||||
this.methodHasReturnValue = methodHasReturnValue;
|
this.methodHasReturnValue = methodHasReturnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool find(int index) {
|
public bool Find(int index) {
|
||||||
return find(ref index, true);
|
return Find(ref index, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool find(ref int index, bool addIt) {
|
bool Find(ref int index, bool addIt) {
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var startInstr = block.Instructions[index];
|
var startInstr = block.Instructions[index];
|
||||||
int startInstrPushes, startInstrPops;
|
int startInstrPushes, startInstrPops;
|
||||||
calculateStackUsage(startInstr.Instruction, false, out startInstrPushes, out startInstrPops);
|
CalculateStackUsage(startInstr.Instruction, false, out startInstrPushes, out startInstrPops);
|
||||||
|
|
||||||
// Don't add it if it clears the stack (eg. leave)
|
// Don't add it if it clears the stack (eg. leave)
|
||||||
if (addIt && startInstrPops >= 0)
|
if (addIt && startInstrPops >= 0)
|
||||||
addIndex(index);
|
AddIndex(index);
|
||||||
|
|
||||||
if (startInstrPops == 0)
|
if (startInstrPops == 0)
|
||||||
return true;
|
return true;
|
||||||
|
@ -349,19 +349,19 @@ namespace de4dot.blocks.cflow {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
int pushes, pops;
|
int pushes, pops;
|
||||||
calculateStackUsage(instr.Instruction, methodHasReturnValue, out pushes, out pops);
|
CalculateStackUsage(instr.Instruction, methodHasReturnValue, out pushes, out pops);
|
||||||
if (pops < 0)
|
if (pops < 0)
|
||||||
break; // eg. leave
|
break; // eg. leave
|
||||||
index--;
|
index--;
|
||||||
|
|
||||||
if (pops > 0) { // if instr uses any args
|
if (pops > 0) { // if instr uses any args
|
||||||
bool otherExpr = pops > 0 && pushes == 0;
|
bool otherExpr = pops > 0 && pushes == 0;
|
||||||
if (!find(ref index, addIt && !otherExpr))
|
if (!Find(ref index, addIt && !otherExpr))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (pushes != 0 || pops != 0) {
|
else if (pushes != 0 || pops != 0) {
|
||||||
if (addIt)
|
if (addIt)
|
||||||
addIndex(index);
|
AddIndex(index);
|
||||||
}
|
}
|
||||||
if (pushes > 0 && startInstrPops >= 0) {
|
if (pushes > 0 && startInstrPops >= 0) {
|
||||||
if (pushes > startInstrPops)
|
if (pushes > startInstrPops)
|
||||||
|
@ -373,12 +373,12 @@ namespace de4dot.blocks.cflow {
|
||||||
return startInstrPops <= 0;
|
return startInstrPops <= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addIndex(int index) {
|
void AddIndex(int index) {
|
||||||
deadInstructions.Add(index);
|
deadInstructions.Add(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void calculateStackUsage(Instruction instr, bool methodHasReturnValue, out int pushes, out int pops) {
|
static void CalculateStackUsage(Instruction instr, bool methodHasReturnValue, out int pushes, out int pops) {
|
||||||
instr.CalculateStackUsage(false, out pushes, out pops);
|
instr.CalculateStackUsage(false, out pushes, out pops);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,16 +41,16 @@ namespace de4dot.blocks.cflow {
|
||||||
|
|
||||||
public bool ExecuteOnNoChange { get; set; }
|
public bool ExecuteOnNoChange { get; set; }
|
||||||
|
|
||||||
public void deobfuscateBegin(Blocks blocks) {
|
public void DeobfuscateBegin(Blocks blocks) {
|
||||||
this.blocks = blocks;
|
this.blocks = blocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool deobfuscate(List<Block> allBlocks) {
|
public bool Deobfuscate(List<Block> allBlocks) {
|
||||||
this.allBlocks = allBlocks;
|
this.allBlocks = allBlocks;
|
||||||
return remove();
|
return Remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool remove() {
|
bool Remove() {
|
||||||
if (blocks.Locals.Count == 0)
|
if (blocks.Locals.Count == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ namespace de4dot.blocks.cflow {
|
||||||
deadLocals.Add(false);
|
deadLocals.Add(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
findLoadStores();
|
FindLoadStores();
|
||||||
|
|
||||||
bool deadStores = false;
|
bool deadStores = false;
|
||||||
for (int i = 0; i < blocks.Locals.Count; i++) {
|
for (int i = 0; i < blocks.Locals.Count; i++) {
|
||||||
|
@ -74,10 +74,10 @@ namespace de4dot.blocks.cflow {
|
||||||
if (!deadStores)
|
if (!deadStores)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return removeDeadStores();
|
return RemoveDeadStores();
|
||||||
}
|
}
|
||||||
|
|
||||||
void findLoadStores() {
|
void FindLoadStores() {
|
||||||
foreach (var block in allBlocks) {
|
foreach (var block in allBlocks) {
|
||||||
foreach (var instr in block.Instructions) {
|
foreach (var instr in block.Instructions) {
|
||||||
Local local;
|
Local local;
|
||||||
|
@ -89,7 +89,7 @@ namespace de4dot.blocks.cflow {
|
||||||
case Code.Ldloc_1:
|
case Code.Ldloc_1:
|
||||||
case Code.Ldloc_2:
|
case Code.Ldloc_2:
|
||||||
case Code.Ldloc_3:
|
case Code.Ldloc_3:
|
||||||
local = Instr.getLocalVar(blocks.Locals, instr);
|
local = Instr.GetLocalVar(blocks.Locals, instr);
|
||||||
flags = AccessFlags.Read;
|
flags = AccessFlags.Read;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ namespace de4dot.blocks.cflow {
|
||||||
case Code.Stloc_1:
|
case Code.Stloc_1:
|
||||||
case Code.Stloc_2:
|
case Code.Stloc_2:
|
||||||
case Code.Stloc_3:
|
case Code.Stloc_3:
|
||||||
local = Instr.getLocalVar(blocks.Locals, instr);
|
local = Instr.GetLocalVar(blocks.Locals, instr);
|
||||||
flags = AccessFlags.Write;
|
flags = AccessFlags.Write;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -122,7 +122,7 @@ namespace de4dot.blocks.cflow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool removeDeadStores() {
|
bool RemoveDeadStores() {
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
foreach (var block in allBlocks) {
|
foreach (var block in allBlocks) {
|
||||||
var instructions = block.Instructions;
|
var instructions = block.Instructions;
|
||||||
|
@ -136,7 +136,7 @@ namespace de4dot.blocks.cflow {
|
||||||
case Code.Stloc_1:
|
case Code.Stloc_1:
|
||||||
case Code.Stloc_2:
|
case Code.Stloc_2:
|
||||||
case Code.Stloc_3:
|
case Code.Stloc_3:
|
||||||
local = Instr.getLocalVar(blocks.Locals, instr);
|
local = Instr.GetLocalVar(blocks.Locals, instr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -25,22 +25,22 @@ namespace de4dot.blocks.cflow {
|
||||||
// If a block is just a dup followed by a bcc, try to append the block
|
// If a block is just a dup followed by a bcc, try to append the block
|
||||||
// to all its sources. Will fix some SA assemblies.
|
// to all its sources. Will fix some SA assemblies.
|
||||||
class DupBlockCflowDeobfuscator : BlockDeobfuscator {
|
class DupBlockCflowDeobfuscator : BlockDeobfuscator {
|
||||||
protected override bool deobfuscate(Block block) {
|
protected override bool Deobfuscate(Block block) {
|
||||||
if (block.Instructions.Count != 2)
|
if (block.Instructions.Count != 2)
|
||||||
return false;
|
return false;
|
||||||
if (block.Instructions[0].OpCode.Code != Code.Dup)
|
if (block.Instructions[0].OpCode.Code != Code.Dup)
|
||||||
return false;
|
return false;
|
||||||
if (!block.LastInstr.isConditionalBranch() && block.LastInstr.OpCode.Code != Code.Switch)
|
if (!block.LastInstr.IsConditionalBranch() && block.LastInstr.OpCode.Code != Code.Switch)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool modified = false;
|
bool modified = false;
|
||||||
foreach (var source in new List<Block>(block.Sources)) {
|
foreach (var source in new List<Block>(block.Sources)) {
|
||||||
if (source.getOnlyTarget() != block)
|
if (source.GetOnlyTarget() != block)
|
||||||
continue;
|
continue;
|
||||||
if (!source.canAppend(block))
|
if (!source.CanAppend(block))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
source.append(block);
|
source.Append(block);
|
||||||
modified = true;
|
modified = true;
|
||||||
}
|
}
|
||||||
return modified;
|
return modified;
|
||||||
|
|
|
@ -23,9 +23,9 @@ namespace de4dot.blocks.cflow {
|
||||||
public interface IBlocksDeobfuscator {
|
public interface IBlocksDeobfuscator {
|
||||||
bool ExecuteOnNoChange { get; }
|
bool ExecuteOnNoChange { get; }
|
||||||
|
|
||||||
void deobfuscateBegin(Blocks blocks);
|
void DeobfuscateBegin(Blocks blocks);
|
||||||
|
|
||||||
// Returns true if something was updated
|
// Returns true if something was updated
|
||||||
bool deobfuscate(List<Block> allBlocks);
|
bool Deobfuscate(List<Block> allBlocks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,6 @@ using dnlib.DotNet;
|
||||||
|
|
||||||
namespace de4dot.blocks.cflow {
|
namespace de4dot.blocks.cflow {
|
||||||
public interface ICflowDeobfuscator {
|
public interface ICflowDeobfuscator {
|
||||||
void deobfuscate(MethodDef method);
|
void Deobfuscate(MethodDef method);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -40,75 +40,75 @@ namespace de4dot.blocks.cflow {
|
||||||
this.validMask = validMask;
|
this.validMask = validMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool hasUnknownBits() {
|
public bool HasUnknownBits() {
|
||||||
return validMask != NO_UNKNOWN_BITS;
|
return validMask != NO_UNKNOWN_BITS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool allBitsValid() {
|
public bool AllBitsValid() {
|
||||||
return !hasUnknownBits();
|
return !HasUnknownBits();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isBitValid(int n) {
|
bool IsBitValid(int n) {
|
||||||
return isBitValid(validMask, n);
|
return IsBitValid(validMask, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isBitValid(uint validMask, int n) {
|
static bool IsBitValid(uint validMask, int n) {
|
||||||
return (validMask & (1U << n)) != 0;
|
return (validMask & (1U << n)) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int32Value createUnknownBool() {
|
public static Int32Value CreateUnknownBool() {
|
||||||
return new Int32Value(0, NO_UNKNOWN_BITS << 1);
|
return new Int32Value(0, NO_UNKNOWN_BITS << 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int32Value createUnknownUInt8() {
|
public static Int32Value CreateUnknownUInt8() {
|
||||||
return new Int32Value(0, NO_UNKNOWN_BITS << 8);
|
return new Int32Value(0, NO_UNKNOWN_BITS << 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int32Value createUnknownUInt16() {
|
public static Int32Value CreateUnknownUInt16() {
|
||||||
return new Int32Value(0, NO_UNKNOWN_BITS << 16);
|
return new Int32Value(0, NO_UNKNOWN_BITS << 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int32Value createUnknown() {
|
public static Int32Value CreateUnknown() {
|
||||||
return new Int32Value(0, 0U);
|
return new Int32Value(0, 0U);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isZero() {
|
public bool IsZero() {
|
||||||
return hasValue(0);
|
return HasValue(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isNonZero() {
|
public bool IsNonZero() {
|
||||||
return (value & validMask) != 0;
|
return (value & validMask) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool hasValue(int value) {
|
public bool HasValue(int value) {
|
||||||
return allBitsValid() && this.value == value;
|
return AllBitsValid() && this.value == value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool hasValue(uint value) {
|
public bool HasValue(uint value) {
|
||||||
return hasValue((int)value);
|
return HasValue((int)value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Int32Value toBoolean() {
|
public Int32Value ToBoolean() {
|
||||||
if (isNonZero())
|
if (IsNonZero())
|
||||||
return new Int32Value(1, NO_UNKNOWN_BITS);
|
return new Int32Value(1, NO_UNKNOWN_BITS);
|
||||||
if (isZero())
|
if (IsZero())
|
||||||
return this;
|
return this;
|
||||||
return createUnknownBool();
|
return CreateUnknownBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Int32Value toInt8() {
|
public Int32Value ToInt8() {
|
||||||
return Conv_I1(this);
|
return Conv_I1(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Int32Value toUInt8() {
|
public Int32Value ToUInt8() {
|
||||||
return Conv_U1(this);
|
return Conv_U1(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Int32Value toInt16() {
|
public Int32Value ToInt16() {
|
||||||
return Conv_I2(this);
|
return Conv_I2(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Int32Value toUInt16() {
|
public Int32Value ToUInt16() {
|
||||||
return Conv_U2(this);
|
return Conv_U2(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@ namespace de4dot.blocks.cflow {
|
||||||
|
|
||||||
public static Int32Value Conv_I1(int value, uint validMask) {
|
public static Int32Value Conv_I1(int value, uint validMask) {
|
||||||
value = (int)(sbyte)value;
|
value = (int)(sbyte)value;
|
||||||
if (isBitValid(validMask, 7))
|
if (IsBitValid(validMask, 7))
|
||||||
validMask |= NO_UNKNOWN_BITS << 8;
|
validMask |= NO_UNKNOWN_BITS << 8;
|
||||||
else
|
else
|
||||||
validMask &= ~(NO_UNKNOWN_BITS << 8);
|
validMask &= ~(NO_UNKNOWN_BITS << 8);
|
||||||
|
@ -179,7 +179,7 @@ namespace de4dot.blocks.cflow {
|
||||||
|
|
||||||
public static Int32Value Conv_I2(int value, uint validMask) {
|
public static Int32Value Conv_I2(int value, uint validMask) {
|
||||||
value = (int)(short)value;
|
value = (int)(short)value;
|
||||||
if (isBitValid(validMask, 15))
|
if (IsBitValid(validMask, 15))
|
||||||
validMask |= NO_UNKNOWN_BITS << 16;
|
validMask |= NO_UNKNOWN_BITS << 16;
|
||||||
else
|
else
|
||||||
validMask &= ~(NO_UNKNOWN_BITS << 16);
|
validMask &= ~(NO_UNKNOWN_BITS << 16);
|
||||||
|
@ -215,97 +215,97 @@ namespace de4dot.blocks.cflow {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int32Value Add(Int32Value a, Int32Value b) {
|
public static Int32Value Add(Int32Value a, Int32Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid())
|
if (a.AllBitsValid() && b.AllBitsValid())
|
||||||
return new Int32Value(a.value + b.value);
|
return new Int32Value(a.value + b.value);
|
||||||
if (ReferenceEquals(a, b))
|
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();
|
return CreateUnknown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int32Value Sub(Int32Value a, Int32Value b) {
|
public static Int32Value Sub(Int32Value a, Int32Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid())
|
if (a.AllBitsValid() && b.AllBitsValid())
|
||||||
return new Int32Value(a.value - b.value);
|
return new Int32Value(a.value - b.value);
|
||||||
if (ReferenceEquals(a, b))
|
if (ReferenceEquals(a, b))
|
||||||
return zero;
|
return zero;
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int32Value Mul(Int32Value a, Int32Value b) {
|
public static Int32Value Mul(Int32Value a, Int32Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid())
|
if (a.AllBitsValid() && b.AllBitsValid())
|
||||||
return new Int32Value(a.value * b.value);
|
return new Int32Value(a.value * b.value);
|
||||||
if (a.isZero() || b.isZero())
|
if (a.IsZero() || b.IsZero())
|
||||||
return zero;
|
return zero;
|
||||||
if (a.hasValue(1))
|
if (a.HasValue(1))
|
||||||
return b;
|
return b;
|
||||||
if (b.hasValue(1))
|
if (b.HasValue(1))
|
||||||
return a;
|
return a;
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int32Value Div(Int32Value a, Int32Value b) {
|
public static Int32Value Div(Int32Value a, Int32Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid()) {
|
if (a.AllBitsValid() && b.AllBitsValid()) {
|
||||||
try {
|
try {
|
||||||
return new Int32Value(a.value / b.value);
|
return new Int32Value(a.value / b.value);
|
||||||
}
|
}
|
||||||
catch (ArithmeticException) {
|
catch (ArithmeticException) {
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ReferenceEquals(a, b) && a.isNonZero())
|
if (ReferenceEquals(a, b) && a.IsNonZero())
|
||||||
return one;
|
return one;
|
||||||
if (b.hasValue(1))
|
if (b.HasValue(1))
|
||||||
return a;
|
return a;
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int32Value Div_Un(Int32Value a, Int32Value b) {
|
public static Int32Value Div_Un(Int32Value a, Int32Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid()) {
|
if (a.AllBitsValid() && b.AllBitsValid()) {
|
||||||
try {
|
try {
|
||||||
return new Int32Value((int)((uint)a.value / (uint)b.value));
|
return new Int32Value((int)((uint)a.value / (uint)b.value));
|
||||||
}
|
}
|
||||||
catch (ArithmeticException) {
|
catch (ArithmeticException) {
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ReferenceEquals(a, b) && a.isNonZero())
|
if (ReferenceEquals(a, b) && a.IsNonZero())
|
||||||
return one;
|
return one;
|
||||||
if (b.hasValue(1))
|
if (b.HasValue(1))
|
||||||
return a;
|
return a;
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int32Value Rem(Int32Value a, Int32Value b) {
|
public static Int32Value Rem(Int32Value a, Int32Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid()) {
|
if (a.AllBitsValid() && b.AllBitsValid()) {
|
||||||
try {
|
try {
|
||||||
return new Int32Value(a.value % b.value);
|
return new Int32Value(a.value % b.value);
|
||||||
}
|
}
|
||||||
catch (ArithmeticException) {
|
catch (ArithmeticException) {
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((ReferenceEquals(a, b) && a.isNonZero()) || b.hasValue(1))
|
if ((ReferenceEquals(a, b) && a.IsNonZero()) || b.HasValue(1))
|
||||||
return zero;
|
return zero;
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int32Value Rem_Un(Int32Value a, Int32Value b) {
|
public static Int32Value Rem_Un(Int32Value a, Int32Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid()) {
|
if (a.AllBitsValid() && b.AllBitsValid()) {
|
||||||
try {
|
try {
|
||||||
return new Int32Value((int)((uint)a.value % (uint)b.value));
|
return new Int32Value((int)((uint)a.value % (uint)b.value));
|
||||||
}
|
}
|
||||||
catch (ArithmeticException) {
|
catch (ArithmeticException) {
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((ReferenceEquals(a, b) && a.isNonZero()) || b.hasValue(1))
|
if ((ReferenceEquals(a, b) && a.IsNonZero()) || b.HasValue(1))
|
||||||
return zero;
|
return zero;
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int32Value Neg(Int32Value a) {
|
public static Int32Value Neg(Int32Value a) {
|
||||||
if (a.allBitsValid())
|
if (a.AllBitsValid())
|
||||||
return new Int32Value(-a.value);
|
return new Int32Value(-a.value);
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int32Value And(Int32Value a, Int32Value b) {
|
public static Int32Value And(Int32Value a, Int32Value b) {
|
||||||
|
@ -333,38 +333,38 @@ namespace de4dot.blocks.cflow {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int32Value Shl(Int32Value a, Int32Value b) {
|
public static Int32Value Shl(Int32Value a, Int32Value b) {
|
||||||
if (b.hasUnknownBits())
|
if (b.HasUnknownBits())
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
if (b.value == 0)
|
if (b.value == 0)
|
||||||
return a;
|
return a;
|
||||||
if (b.value < 0 || b.value >= sizeof(int) * 8)
|
if (b.value < 0 || b.value >= sizeof(int) * 8)
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
int shift = b.value;
|
int shift = b.value;
|
||||||
uint validMask = (a.validMask << shift) | (uint.MaxValue >> (sizeof(int) * 8 - shift));
|
uint validMask = (a.validMask << shift) | (uint.MaxValue >> (sizeof(int) * 8 - shift));
|
||||||
return new Int32Value(a.value << shift, validMask);
|
return new Int32Value(a.value << shift, validMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int32Value Shr(Int32Value a, Int32Value b) {
|
public static Int32Value Shr(Int32Value a, Int32Value b) {
|
||||||
if (b.hasUnknownBits())
|
if (b.HasUnknownBits())
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
if (b.value == 0)
|
if (b.value == 0)
|
||||||
return a;
|
return a;
|
||||||
if (b.value < 0 || b.value >= sizeof(int) * 8)
|
if (b.value < 0 || b.value >= sizeof(int) * 8)
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
int shift = b.value;
|
int shift = b.value;
|
||||||
uint validMask = a.validMask >> shift;
|
uint validMask = a.validMask >> shift;
|
||||||
if (a.isBitValid(sizeof(int) * 8 - 1))
|
if (a.IsBitValid(sizeof(int) * 8 - 1))
|
||||||
validMask |= (uint.MaxValue << (sizeof(int) * 8 - shift));
|
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) {
|
public static Int32Value Shr_Un(Int32Value a, Int32Value b) {
|
||||||
if (b.hasUnknownBits())
|
if (b.HasUnknownBits())
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
if (b.value == 0)
|
if (b.value == 0)
|
||||||
return a;
|
return a;
|
||||||
if (b.value < 0 || b.value >= sizeof(int) * 8)
|
if (b.value < 0 || b.value >= sizeof(int) * 8)
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
int shift = b.value;
|
int shift = b.value;
|
||||||
uint validMask = (a.validMask >> shift) | (uint.MaxValue << (sizeof(int) * 8 - shift));
|
uint validMask = (a.validMask >> shift) | (uint.MaxValue << (sizeof(int) * 8 - shift));
|
||||||
return new Int32Value((int)((uint)a.value >> shift), validMask);
|
return new Int32Value((int)((uint)a.value >> shift), validMask);
|
||||||
|
@ -374,32 +374,32 @@ namespace de4dot.blocks.cflow {
|
||||||
switch (b) {
|
switch (b) {
|
||||||
case Bool3.False: return zero;
|
case Bool3.False: return zero;
|
||||||
case Bool3.True: return one;
|
case Bool3.True: return one;
|
||||||
default: return createUnknownBool();
|
default: return CreateUnknownBool();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int32Value Ceq(Int32Value a, Int32Value b) {
|
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) {
|
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) {
|
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) {
|
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) {
|
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) {
|
public static Bool3 CompareEq(Int32Value a, Int32Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid())
|
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))
|
if (ReferenceEquals(a, b))
|
||||||
return Bool3.True;
|
return Bool3.True;
|
||||||
|
@ -408,8 +408,8 @@ namespace de4dot.blocks.cflow {
|
||||||
return Bool3.Unknown;
|
return Bool3.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bool3 compareNeq(Int32Value a, Int32Value b) {
|
public static Bool3 CompareNeq(Int32Value a, Int32Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid())
|
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))
|
if (ReferenceEquals(a, b))
|
||||||
return Bool3.False;
|
return Bool3.False;
|
||||||
|
@ -418,96 +418,96 @@ namespace de4dot.blocks.cflow {
|
||||||
return Bool3.Unknown;
|
return Bool3.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bool3 compareGt(Int32Value a, Int32Value b) {
|
public static Bool3 CompareGt(Int32Value a, Int32Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid())
|
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))
|
if (a.HasValue(int.MinValue))
|
||||||
return Bool3.False; // min > x => false
|
return Bool3.False; // min > x => false
|
||||||
if (b.hasValue(int.MaxValue))
|
if (b.HasValue(int.MaxValue))
|
||||||
return Bool3.False; // x > max => false
|
return Bool3.False; // x > max => false
|
||||||
return Bool3.Unknown;
|
return Bool3.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bool3 compareGt_Un(Int32Value a, Int32Value b) {
|
public static Bool3 CompareGt_Un(Int32Value a, Int32Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid())
|
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))
|
if (a.HasValue(uint.MinValue))
|
||||||
return Bool3.False; // min > x => false
|
return Bool3.False; // min > x => false
|
||||||
if (b.hasValue(uint.MaxValue))
|
if (b.HasValue(uint.MaxValue))
|
||||||
return Bool3.False; // x > max => false
|
return Bool3.False; // x > max => false
|
||||||
return Bool3.Unknown;
|
return Bool3.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bool3 compareGe(Int32Value a, Int32Value b) {
|
public static Bool3 CompareGe(Int32Value a, Int32Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid())
|
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))
|
if (a.HasValue(int.MaxValue))
|
||||||
return Bool3.True; // max >= x => true
|
return Bool3.True; // max >= x => true
|
||||||
if (b.hasValue(int.MinValue))
|
if (b.HasValue(int.MinValue))
|
||||||
return Bool3.True; // x >= min => true
|
return Bool3.True; // x >= min => true
|
||||||
return Bool3.Unknown;
|
return Bool3.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bool3 compareGe_Un(Int32Value a, Int32Value b) {
|
public static Bool3 CompareGe_Un(Int32Value a, Int32Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid())
|
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))
|
if (a.HasValue(uint.MaxValue))
|
||||||
return Bool3.True; // max >= x => true
|
return Bool3.True; // max >= x => true
|
||||||
if (b.hasValue(uint.MinValue))
|
if (b.HasValue(uint.MinValue))
|
||||||
return Bool3.True; // x >= min => true
|
return Bool3.True; // x >= min => true
|
||||||
return Bool3.Unknown;
|
return Bool3.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bool3 compareLe(Int32Value a, Int32Value b) {
|
public static Bool3 CompareLe(Int32Value a, Int32Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid())
|
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))
|
if (a.HasValue(int.MinValue))
|
||||||
return Bool3.True; // min <= x => true
|
return Bool3.True; // min <= x => true
|
||||||
if (b.hasValue(int.MaxValue))
|
if (b.HasValue(int.MaxValue))
|
||||||
return Bool3.True; // x <= max => true
|
return Bool3.True; // x <= max => true
|
||||||
return Bool3.Unknown;
|
return Bool3.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bool3 compareLe_Un(Int32Value a, Int32Value b) {
|
public static Bool3 CompareLe_Un(Int32Value a, Int32Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid())
|
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))
|
if (a.HasValue(uint.MinValue))
|
||||||
return Bool3.True; // min <= x => true
|
return Bool3.True; // min <= x => true
|
||||||
if (b.hasValue(uint.MaxValue))
|
if (b.HasValue(uint.MaxValue))
|
||||||
return Bool3.True; // x <= max => true
|
return Bool3.True; // x <= max => true
|
||||||
return Bool3.Unknown;
|
return Bool3.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bool3 compareLt(Int32Value a, Int32Value b) {
|
public static Bool3 CompareLt(Int32Value a, Int32Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid())
|
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))
|
if (a.HasValue(int.MaxValue))
|
||||||
return Bool3.False; // max < x => false
|
return Bool3.False; // max < x => false
|
||||||
if (b.hasValue(int.MinValue))
|
if (b.HasValue(int.MinValue))
|
||||||
return Bool3.False; // x < min => false
|
return Bool3.False; // x < min => false
|
||||||
return Bool3.Unknown;
|
return Bool3.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bool3 compareLt_Un(Int32Value a, Int32Value b) {
|
public static Bool3 CompareLt_Un(Int32Value a, Int32Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid())
|
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))
|
if (a.HasValue(uint.MaxValue))
|
||||||
return Bool3.False; // max < x => false
|
return Bool3.False; // max < x => false
|
||||||
if (b.hasValue(uint.MinValue))
|
if (b.HasValue(uint.MinValue))
|
||||||
return Bool3.False; // x < min => false
|
return Bool3.False; // x < min => false
|
||||||
return Bool3.Unknown;
|
return Bool3.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bool3 compareTrue(Int32Value a) {
|
public static Bool3 CompareTrue(Int32Value a) {
|
||||||
if (a.allBitsValid())
|
if (a.AllBitsValid())
|
||||||
return a.value != 0 ? Bool3.True : Bool3.False;
|
return a.value != 0 ? Bool3.True : Bool3.False;
|
||||||
if ((a.value & a.validMask) != 0)
|
if ((a.value & a.validMask) != 0)
|
||||||
return Bool3.True;
|
return Bool3.True;
|
||||||
return Bool3.Unknown;
|
return Bool3.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bool3 compareFalse(Int32Value a) {
|
public static Bool3 CompareFalse(Int32Value a) {
|
||||||
if (a.allBitsValid())
|
if (a.AllBitsValid())
|
||||||
return a.value == 0 ? Bool3.True : Bool3.False;
|
return a.value == 0 ? Bool3.True : Bool3.False;
|
||||||
if ((a.value & a.validMask) != 0)
|
if ((a.value & a.validMask) != 0)
|
||||||
return Bool3.False;
|
return Bool3.False;
|
||||||
|
@ -515,7 +515,7 @@ namespace de4dot.blocks.cflow {
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() {
|
public override string ToString() {
|
||||||
if (allBitsValid())
|
if (AllBitsValid())
|
||||||
return value.ToString();
|
return value.ToString();
|
||||||
return string.Format("0x{0:X8}({1:X8})", value, validMask);
|
return string.Format("0x{0:X8}({1:X8})", value, validMask);
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,40 +40,40 @@ namespace de4dot.blocks.cflow {
|
||||||
this.validMask = validMask;
|
this.validMask = validMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasUnknownBits() {
|
bool HasUnknownBits() {
|
||||||
return validMask != NO_UNKNOWN_BITS;
|
return validMask != NO_UNKNOWN_BITS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool allBitsValid() {
|
public bool AllBitsValid() {
|
||||||
return !hasUnknownBits();
|
return !HasUnknownBits();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isBitValid(int n) {
|
bool IsBitValid(int n) {
|
||||||
return isBitValid(validMask, n);
|
return IsBitValid(validMask, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isBitValid(ulong validMask, int n) {
|
static bool IsBitValid(ulong validMask, int n) {
|
||||||
return (validMask & (1UL << n)) != 0;
|
return (validMask & (1UL << n)) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int64Value createUnknown() {
|
public static Int64Value CreateUnknown() {
|
||||||
return new Int64Value(0, 0UL);
|
return new Int64Value(0, 0UL);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isZero() {
|
public bool IsZero() {
|
||||||
return hasValue(0);
|
return HasValue(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isNonZero() {
|
public bool IsNonZero() {
|
||||||
return ((ulong)value & validMask) != 0;
|
return ((ulong)value & validMask) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool hasValue(long value) {
|
public bool HasValue(long value) {
|
||||||
return allBitsValid() && this.value == value;
|
return AllBitsValid() && this.value == value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool hasValue(ulong value) {
|
public bool HasValue(ulong value) {
|
||||||
return hasValue((long)value);
|
return HasValue((long)value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int64Value Conv_U8(Int32Value a) {
|
public static Int64Value Conv_U8(Int32Value a) {
|
||||||
|
@ -93,7 +93,7 @@ namespace de4dot.blocks.cflow {
|
||||||
public static Int64Value Conv_I8(Int32Value a) {
|
public static Int64Value Conv_I8(Int32Value a) {
|
||||||
long value = a.value;
|
long value = a.value;
|
||||||
ulong validMask = a.validMask;
|
ulong validMask = a.validMask;
|
||||||
if (isBitValid(validMask, 31))
|
if (IsBitValid(validMask, 31))
|
||||||
validMask |= NO_UNKNOWN_BITS << 32;
|
validMask |= NO_UNKNOWN_BITS << 32;
|
||||||
else
|
else
|
||||||
validMask &= ~(NO_UNKNOWN_BITS << 32);
|
validMask &= ~(NO_UNKNOWN_BITS << 32);
|
||||||
|
@ -109,97 +109,97 @@ namespace de4dot.blocks.cflow {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int64Value Add(Int64Value a, Int64Value b) {
|
public static Int64Value Add(Int64Value a, Int64Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid())
|
if (a.AllBitsValid() && b.AllBitsValid())
|
||||||
return new Int64Value(a.value + b.value);
|
return new Int64Value(a.value + b.value);
|
||||||
if (ReferenceEquals(a, b))
|
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();
|
return CreateUnknown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int64Value Sub(Int64Value a, Int64Value b) {
|
public static Int64Value Sub(Int64Value a, Int64Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid())
|
if (a.AllBitsValid() && b.AllBitsValid())
|
||||||
return new Int64Value(a.value - b.value);
|
return new Int64Value(a.value - b.value);
|
||||||
if (ReferenceEquals(a, b))
|
if (ReferenceEquals(a, b))
|
||||||
return zero;
|
return zero;
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int64Value Mul(Int64Value a, Int64Value b) {
|
public static Int64Value Mul(Int64Value a, Int64Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid())
|
if (a.AllBitsValid() && b.AllBitsValid())
|
||||||
return new Int64Value(a.value * b.value);
|
return new Int64Value(a.value * b.value);
|
||||||
if (a.isZero() || b.isZero())
|
if (a.IsZero() || b.IsZero())
|
||||||
return zero;
|
return zero;
|
||||||
if (a.hasValue(1))
|
if (a.HasValue(1))
|
||||||
return b;
|
return b;
|
||||||
if (b.hasValue(1))
|
if (b.HasValue(1))
|
||||||
return a;
|
return a;
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int64Value Div(Int64Value a, Int64Value b) {
|
public static Int64Value Div(Int64Value a, Int64Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid()) {
|
if (a.AllBitsValid() && b.AllBitsValid()) {
|
||||||
try {
|
try {
|
||||||
return new Int64Value(a.value / b.value);
|
return new Int64Value(a.value / b.value);
|
||||||
}
|
}
|
||||||
catch (ArithmeticException) {
|
catch (ArithmeticException) {
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ReferenceEquals(a, b) && a.isNonZero())
|
if (ReferenceEquals(a, b) && a.IsNonZero())
|
||||||
return one;
|
return one;
|
||||||
if (b.hasValue(1))
|
if (b.HasValue(1))
|
||||||
return a;
|
return a;
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int64Value Div_Un(Int64Value a, Int64Value b) {
|
public static Int64Value Div_Un(Int64Value a, Int64Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid()) {
|
if (a.AllBitsValid() && b.AllBitsValid()) {
|
||||||
try {
|
try {
|
||||||
return new Int64Value((long)((ulong)a.value / (ulong)b.value));
|
return new Int64Value((long)((ulong)a.value / (ulong)b.value));
|
||||||
}
|
}
|
||||||
catch (ArithmeticException) {
|
catch (ArithmeticException) {
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ReferenceEquals(a, b) && a.isNonZero())
|
if (ReferenceEquals(a, b) && a.IsNonZero())
|
||||||
return one;
|
return one;
|
||||||
if (b.hasValue(1))
|
if (b.HasValue(1))
|
||||||
return a;
|
return a;
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int64Value Rem(Int64Value a, Int64Value b) {
|
public static Int64Value Rem(Int64Value a, Int64Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid()) {
|
if (a.AllBitsValid() && b.AllBitsValid()) {
|
||||||
try {
|
try {
|
||||||
return new Int64Value(a.value % b.value);
|
return new Int64Value(a.value % b.value);
|
||||||
}
|
}
|
||||||
catch (ArithmeticException) {
|
catch (ArithmeticException) {
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((ReferenceEquals(a, b) && a.isNonZero()) || b.hasValue(1))
|
if ((ReferenceEquals(a, b) && a.IsNonZero()) || b.HasValue(1))
|
||||||
return zero;
|
return zero;
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int64Value Rem_Un(Int64Value a, Int64Value b) {
|
public static Int64Value Rem_Un(Int64Value a, Int64Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid()) {
|
if (a.AllBitsValid() && b.AllBitsValid()) {
|
||||||
try {
|
try {
|
||||||
return new Int64Value((long)((ulong)a.value % (ulong)b.value));
|
return new Int64Value((long)((ulong)a.value % (ulong)b.value));
|
||||||
}
|
}
|
||||||
catch (ArithmeticException) {
|
catch (ArithmeticException) {
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((ReferenceEquals(a, b) && a.isNonZero()) || b.hasValue(1))
|
if ((ReferenceEquals(a, b) && a.IsNonZero()) || b.HasValue(1))
|
||||||
return zero;
|
return zero;
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int64Value Neg(Int64Value a) {
|
public static Int64Value Neg(Int64Value a) {
|
||||||
if (a.allBitsValid())
|
if (a.AllBitsValid())
|
||||||
return new Int64Value(-a.value);
|
return new Int64Value(-a.value);
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int64Value And(Int64Value a, Int64Value b) {
|
public static Int64Value And(Int64Value a, Int64Value b) {
|
||||||
|
@ -227,73 +227,73 @@ namespace de4dot.blocks.cflow {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int64Value Shl(Int64Value a, Int32Value b) {
|
public static Int64Value Shl(Int64Value a, Int32Value b) {
|
||||||
if (b.hasUnknownBits())
|
if (b.HasUnknownBits())
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
if (b.value == 0)
|
if (b.value == 0)
|
||||||
return a;
|
return a;
|
||||||
if (b.value < 0 || b.value >= sizeof(long) * 8)
|
if (b.value < 0 || b.value >= sizeof(long) * 8)
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
int shift = b.value;
|
int shift = b.value;
|
||||||
ulong validMask = (a.validMask << shift) | (ulong.MaxValue >> (sizeof(long) * 8 - shift));
|
ulong validMask = (a.validMask << shift) | (ulong.MaxValue >> (sizeof(long) * 8 - shift));
|
||||||
return new Int64Value(a.value << shift, validMask);
|
return new Int64Value(a.value << shift, validMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int64Value Shr(Int64Value a, Int32Value b) {
|
public static Int64Value Shr(Int64Value a, Int32Value b) {
|
||||||
if (b.hasUnknownBits())
|
if (b.HasUnknownBits())
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
if (b.value == 0)
|
if (b.value == 0)
|
||||||
return a;
|
return a;
|
||||||
if (b.value < 0 || b.value >= sizeof(long) * 8)
|
if (b.value < 0 || b.value >= sizeof(long) * 8)
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
int shift = b.value;
|
int shift = b.value;
|
||||||
ulong validMask = a.validMask >> shift;
|
ulong validMask = a.validMask >> shift;
|
||||||
if (a.isBitValid(sizeof(long) * 8 - 1))
|
if (a.IsBitValid(sizeof(long) * 8 - 1))
|
||||||
validMask |= (ulong.MaxValue << (sizeof(long) * 8 - shift));
|
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) {
|
public static Int64Value Shr_Un(Int64Value a, Int32Value b) {
|
||||||
if (b.hasUnknownBits())
|
if (b.HasUnknownBits())
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
if (b.value == 0)
|
if (b.value == 0)
|
||||||
return a;
|
return a;
|
||||||
if (b.value < 0 || b.value >= sizeof(long) * 8)
|
if (b.value < 0 || b.value >= sizeof(long) * 8)
|
||||||
return createUnknown();
|
return CreateUnknown();
|
||||||
int shift = b.value;
|
int shift = b.value;
|
||||||
ulong validMask = (a.validMask >> shift) | (ulong.MaxValue << (sizeof(long) * 8 - shift));
|
ulong validMask = (a.validMask >> shift) | (ulong.MaxValue << (sizeof(long) * 8 - shift));
|
||||||
return new Int64Value((long)((ulong)a.value >> shift), validMask);
|
return new Int64Value((long)((ulong)a.value >> shift), validMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Int32Value create(Bool3 b) {
|
static Int32Value Create(Bool3 b) {
|
||||||
switch (b) {
|
switch (b) {
|
||||||
case Bool3.False: return Int32Value.zero;
|
case Bool3.False: return Int32Value.zero;
|
||||||
case Bool3.True: return Int32Value.one;
|
case Bool3.True: return Int32Value.one;
|
||||||
default: return Int32Value.createUnknownBool();
|
default: return Int32Value.CreateUnknownBool();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int32Value Ceq(Int64Value a, Int64Value b) {
|
public static Int32Value Ceq(Int64Value a, Int64Value b) {
|
||||||
return create(compareEq(a, b));
|
return Create(CompareEq(a, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int32Value Cgt(Int64Value a, Int64Value b) {
|
public static Int32Value Cgt(Int64Value a, Int64Value b) {
|
||||||
return create(compareGt(a, b));
|
return Create(CompareGt(a, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int32Value Cgt_Un(Int64Value a, Int64Value b) {
|
public static Int32Value Cgt_Un(Int64Value a, Int64Value b) {
|
||||||
return create(compareGt_Un(a, b));
|
return Create(CompareGt_Un(a, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int32Value Clt(Int64Value a, Int64Value b) {
|
public static Int32Value Clt(Int64Value a, Int64Value b) {
|
||||||
return create(compareLt(a, b));
|
return Create(CompareLt(a, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int32Value Clt_Un(Int64Value a, Int64Value b) {
|
public static Int32Value Clt_Un(Int64Value a, Int64Value b) {
|
||||||
return create(compareLt_Un(a, b));
|
return Create(CompareLt_Un(a, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bool3 compareEq(Int64Value a, Int64Value b) {
|
public static Bool3 CompareEq(Int64Value a, Int64Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid())
|
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))
|
if (ReferenceEquals(a, b))
|
||||||
return Bool3.True;
|
return Bool3.True;
|
||||||
|
@ -302,8 +302,8 @@ namespace de4dot.blocks.cflow {
|
||||||
return Bool3.Unknown;
|
return Bool3.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bool3 compareNeq(Int64Value a, Int64Value b) {
|
public static Bool3 CompareNeq(Int64Value a, Int64Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid())
|
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))
|
if (ReferenceEquals(a, b))
|
||||||
return Bool3.False;
|
return Bool3.False;
|
||||||
|
@ -312,96 +312,96 @@ namespace de4dot.blocks.cflow {
|
||||||
return Bool3.Unknown;
|
return Bool3.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bool3 compareGt(Int64Value a, Int64Value b) {
|
public static Bool3 CompareGt(Int64Value a, Int64Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid())
|
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))
|
if (a.HasValue(long.MinValue))
|
||||||
return Bool3.False; // min > x => false
|
return Bool3.False; // min > x => false
|
||||||
if (b.hasValue(long.MaxValue))
|
if (b.HasValue(long.MaxValue))
|
||||||
return Bool3.False; // x > max => false
|
return Bool3.False; // x > max => false
|
||||||
return Bool3.Unknown;
|
return Bool3.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bool3 compareGt_Un(Int64Value a, Int64Value b) {
|
public static Bool3 CompareGt_Un(Int64Value a, Int64Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid())
|
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))
|
if (a.HasValue(ulong.MinValue))
|
||||||
return Bool3.False; // min > x => false
|
return Bool3.False; // min > x => false
|
||||||
if (b.hasValue(ulong.MaxValue))
|
if (b.HasValue(ulong.MaxValue))
|
||||||
return Bool3.False; // x > max => false
|
return Bool3.False; // x > max => false
|
||||||
return Bool3.Unknown;
|
return Bool3.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bool3 compareGe(Int64Value a, Int64Value b) {
|
public static Bool3 CompareGe(Int64Value a, Int64Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid())
|
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))
|
if (a.HasValue(long.MaxValue))
|
||||||
return Bool3.True; // max >= x => true
|
return Bool3.True; // max >= x => true
|
||||||
if (b.hasValue(long.MinValue))
|
if (b.HasValue(long.MinValue))
|
||||||
return Bool3.True; // x >= min => true
|
return Bool3.True; // x >= min => true
|
||||||
return Bool3.Unknown;
|
return Bool3.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bool3 compareGe_Un(Int64Value a, Int64Value b) {
|
public static Bool3 CompareGe_Un(Int64Value a, Int64Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid())
|
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))
|
if (a.HasValue(ulong.MaxValue))
|
||||||
return Bool3.True; // max >= x => true
|
return Bool3.True; // max >= x => true
|
||||||
if (b.hasValue(ulong.MinValue))
|
if (b.HasValue(ulong.MinValue))
|
||||||
return Bool3.True; // x >= min => true
|
return Bool3.True; // x >= min => true
|
||||||
return Bool3.Unknown;
|
return Bool3.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bool3 compareLe(Int64Value a, Int64Value b) {
|
public static Bool3 CompareLe(Int64Value a, Int64Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid())
|
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))
|
if (a.HasValue(long.MinValue))
|
||||||
return Bool3.True; // min <= x => true
|
return Bool3.True; // min <= x => true
|
||||||
if (b.hasValue(long.MaxValue))
|
if (b.HasValue(long.MaxValue))
|
||||||
return Bool3.True; // x <= max => true
|
return Bool3.True; // x <= max => true
|
||||||
return Bool3.Unknown;
|
return Bool3.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bool3 compareLe_Un(Int64Value a, Int64Value b) {
|
public static Bool3 CompareLe_Un(Int64Value a, Int64Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid())
|
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))
|
if (a.HasValue(ulong.MinValue))
|
||||||
return Bool3.True; // min <= x => true
|
return Bool3.True; // min <= x => true
|
||||||
if (b.hasValue(ulong.MaxValue))
|
if (b.HasValue(ulong.MaxValue))
|
||||||
return Bool3.True; // x <= max => true
|
return Bool3.True; // x <= max => true
|
||||||
return Bool3.Unknown;
|
return Bool3.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bool3 compareLt(Int64Value a, Int64Value b) {
|
public static Bool3 CompareLt(Int64Value a, Int64Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid())
|
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))
|
if (a.HasValue(long.MaxValue))
|
||||||
return Bool3.False; // max < x => false
|
return Bool3.False; // max < x => false
|
||||||
if (b.hasValue(long.MinValue))
|
if (b.HasValue(long.MinValue))
|
||||||
return Bool3.False; // x < min => false
|
return Bool3.False; // x < min => false
|
||||||
return Bool3.Unknown;
|
return Bool3.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bool3 compareLt_Un(Int64Value a, Int64Value b) {
|
public static Bool3 CompareLt_Un(Int64Value a, Int64Value b) {
|
||||||
if (a.allBitsValid() && b.allBitsValid())
|
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))
|
if (a.HasValue(ulong.MaxValue))
|
||||||
return Bool3.False; // max < x => false
|
return Bool3.False; // max < x => false
|
||||||
if (b.hasValue(ulong.MinValue))
|
if (b.HasValue(ulong.MinValue))
|
||||||
return Bool3.False; // x < min => false
|
return Bool3.False; // x < min => false
|
||||||
return Bool3.Unknown;
|
return Bool3.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bool3 compareTrue(Int64Value a) {
|
public static Bool3 CompareTrue(Int64Value a) {
|
||||||
if (a.allBitsValid())
|
if (a.AllBitsValid())
|
||||||
return a.value != 0 ? Bool3.True : Bool3.False;
|
return a.value != 0 ? Bool3.True : Bool3.False;
|
||||||
if (((ulong)a.value & a.validMask) != 0)
|
if (((ulong)a.value & a.validMask) != 0)
|
||||||
return Bool3.True;
|
return Bool3.True;
|
||||||
return Bool3.Unknown;
|
return Bool3.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bool3 compareFalse(Int64Value a) {
|
public static Bool3 CompareFalse(Int64Value a) {
|
||||||
if (a.allBitsValid())
|
if (a.AllBitsValid())
|
||||||
return a.value == 0 ? Bool3.True : Bool3.False;
|
return a.value == 0 ? Bool3.True : Bool3.False;
|
||||||
if (((ulong)a.value & a.validMask) != 0)
|
if (((ulong)a.value & a.validMask) != 0)
|
||||||
return Bool3.False;
|
return Bool3.False;
|
||||||
|
@ -409,7 +409,7 @@ namespace de4dot.blocks.cflow {
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() {
|
public override string ToString() {
|
||||||
if (allBitsValid())
|
if (AllBitsValid())
|
||||||
return value.ToString();
|
return value.ToString();
|
||||||
return string.Format("0x{0:X8}L({1:X8})", value, validMask);
|
return string.Format("0x{0:X8}L({1:X8})", value, validMask);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,18 +29,18 @@ namespace de4dot.blocks.cflow {
|
||||||
this.inlineInstanceMethods = inlineInstanceMethods;
|
this.inlineInstanceMethods = inlineInstanceMethods;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool deobfuscateInternal() {
|
protected override bool DeobfuscateInternal() {
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
var instructions = block.Instructions;
|
var instructions = block.Instructions;
|
||||||
for (int i = 0; i < instructions.Count; i++) {
|
for (int i = 0; i < instructions.Count; i++) {
|
||||||
var instr = instructions[i].Instruction;
|
var instr = instructions[i].Instruction;
|
||||||
if (instr.OpCode.Code == Code.Call)
|
if (instr.OpCode.Code == Code.Call)
|
||||||
changed |= inlineMethod(instr, i);
|
changed |= InlineMethod(instr, i);
|
||||||
}
|
}
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual bool canInline(MethodDef method) {
|
protected virtual bool CanInline(MethodDef method) {
|
||||||
if (method.GenericParameters.Count > 0)
|
if (method.GenericParameters.Count > 0)
|
||||||
return false;
|
return false;
|
||||||
if (method == blocks.Method)
|
if (method == blocks.Method)
|
||||||
|
@ -55,19 +55,19 @@ namespace de4dot.blocks.cflow {
|
||||||
return inlineInstanceMethods;
|
return inlineInstanceMethods;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool inlineMethod(Instruction callInstr, int instrIndex) {
|
bool InlineMethod(Instruction callInstr, int instrIndex) {
|
||||||
var methodToInline = callInstr.Operand as MethodDef;
|
var methodToInline = callInstr.Operand as MethodDef;
|
||||||
if (methodToInline == null)
|
if (methodToInline == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!canInline(methodToInline))
|
if (!CanInline(methodToInline))
|
||||||
return false;
|
return false;
|
||||||
var body = methodToInline.Body;
|
var body = methodToInline.Body;
|
||||||
if (body == null)
|
if (body == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
var instr = DotNetUtils.getInstruction(body.Instructions, ref index);
|
var instr = DotNetUtils.GetInstruction(body.Instructions, ref index);
|
||||||
if (instr == null)
|
if (instr == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ namespace de4dot.blocks.cflow {
|
||||||
case Code.Call:
|
case Code.Call:
|
||||||
case Code.Callvirt:
|
case Code.Callvirt:
|
||||||
case Code.Newobj:
|
case Code.Newobj:
|
||||||
return inlineOtherMethod(instrIndex, methodToInline, instr, index);
|
return InlineOtherMethod(instrIndex, methodToInline, instr, index);
|
||||||
|
|
||||||
case Code.Ldc_I4:
|
case Code.Ldc_I4:
|
||||||
case Code.Ldc_I4_0:
|
case Code.Ldc_I4_0:
|
||||||
|
@ -106,17 +106,17 @@ namespace de4dot.blocks.cflow {
|
||||||
case Code.Ldtoken:
|
case Code.Ldtoken:
|
||||||
case Code.Ldsfld:
|
case Code.Ldsfld:
|
||||||
case Code.Ldsflda:
|
case Code.Ldsflda:
|
||||||
return inlineLoadMethod(instrIndex, methodToInline, instr, index);
|
return InlineLoadMethod(instrIndex, methodToInline, instr, index);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool isCompatibleType(int paramIndex, IType origType, IType newType) {
|
protected override bool IsCompatibleType(int paramIndex, IType origType, IType newType) {
|
||||||
if (new SigComparer(SigComparerOptions.IgnoreModifiers).Equals(origType, newType))
|
if (new SigComparer(SigComparerOptions.IgnoreModifiers).Equals(origType, newType))
|
||||||
return true;
|
return true;
|
||||||
if (isValueType(newType) || isValueType(origType))
|
if (IsValueType(newType) || IsValueType(origType))
|
||||||
return false;
|
return false;
|
||||||
return newType.FullName == "System.Object";
|
return newType.FullName == "System.Object";
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,24 +33,24 @@ namespace de4dot.blocks.cflow {
|
||||||
|
|
||||||
public bool ExecuteOnNoChange { get; set; }
|
public bool ExecuteOnNoChange { get; set; }
|
||||||
|
|
||||||
public void deobfuscateBegin(Blocks blocks) {
|
public void DeobfuscateBegin(Blocks blocks) {
|
||||||
this.blocks = blocks;
|
this.blocks = blocks;
|
||||||
iteration = 0;
|
iteration = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool deobfuscate(List<Block> allBlocks) {
|
public bool Deobfuscate(List<Block> allBlocks) {
|
||||||
if (iteration++ >= MAX_ITERATIONS)
|
if (iteration++ >= MAX_ITERATIONS)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
foreach (var block in allBlocks) {
|
foreach (var block in allBlocks) {
|
||||||
this.block = block;
|
this.block = block;
|
||||||
changed |= deobfuscateInternal();
|
changed |= DeobfuscateInternal();
|
||||||
}
|
}
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract bool deobfuscateInternal();
|
protected abstract bool DeobfuscateInternal();
|
||||||
|
|
||||||
protected class InstructionPatcher {
|
protected class InstructionPatcher {
|
||||||
readonly int patchIndex;
|
readonly int patchIndex;
|
||||||
|
@ -64,53 +64,53 @@ namespace de4dot.blocks.cflow {
|
||||||
this.clonedInstr = new Instr(lastInstr.Clone());
|
this.clonedInstr = new Instr(lastInstr.Clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void patch(Block block) {
|
public void Patch(Block block) {
|
||||||
block.Instructions[patchIndex] = clonedInstr;
|
block.Instructions[patchIndex] = clonedInstr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool inlineLoadMethod(int patchIndex, MethodDef methodToInline, Instruction loadInstr, int instrIndex) {
|
protected bool InlineLoadMethod(int patchIndex, MethodDef methodToInline, Instruction loadInstr, int instrIndex) {
|
||||||
if (!isReturn(methodToInline, instrIndex))
|
if (!IsReturn(methodToInline, instrIndex))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
int methodArgsCount = DotNetUtils.getArgsCount(methodToInline);
|
int methodArgsCount = DotNetUtils.GetArgsCount(methodToInline);
|
||||||
for (int i = 0; i < methodArgsCount; i++)
|
for (int i = 0; i < methodArgsCount; i++)
|
||||||
block.insert(patchIndex++, OpCodes.Pop.ToInstruction());
|
block.Insert(patchIndex++, OpCodes.Pop.ToInstruction());
|
||||||
|
|
||||||
block.Instructions[patchIndex] = new Instr(loadInstr.Clone());
|
block.Instructions[patchIndex] = new Instr(loadInstr.Clone());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool inlineOtherMethod(int patchIndex, MethodDef methodToInline, Instruction instr, int instrIndex) {
|
protected bool InlineOtherMethod(int patchIndex, MethodDef methodToInline, Instruction instr, int instrIndex) {
|
||||||
return inlineOtherMethod(patchIndex, methodToInline, instr, instrIndex, 0);
|
return InlineOtherMethod(patchIndex, methodToInline, instr, instrIndex, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool inlineOtherMethod(int patchIndex, MethodDef methodToInline, Instruction instr, int instrIndex, int popLastArgs) {
|
protected bool InlineOtherMethod(int patchIndex, MethodDef methodToInline, Instruction instr, int instrIndex, int popLastArgs) {
|
||||||
return patchMethod(methodToInline, tryInlineOtherMethod(patchIndex, methodToInline, instr, instrIndex, popLastArgs));
|
return PatchMethod(methodToInline, TryInlineOtherMethod(patchIndex, methodToInline, instr, instrIndex, popLastArgs));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool patchMethod(MethodDef methodToInline, InstructionPatcher patcher) {
|
protected bool PatchMethod(MethodDef methodToInline, InstructionPatcher patcher) {
|
||||||
if (patcher == null)
|
if (patcher == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!isReturn(methodToInline, patcher.afterIndex))
|
if (!IsReturn(methodToInline, patcher.afterIndex))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
patcher.patch(block);
|
patcher.Patch(block);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected InstructionPatcher tryInlineOtherMethod(int patchIndex, MethodDef methodToInline, Instruction instr, int instrIndex) {
|
protected InstructionPatcher TryInlineOtherMethod(int patchIndex, MethodDef methodToInline, Instruction instr, int instrIndex) {
|
||||||
return tryInlineOtherMethod(patchIndex, methodToInline, instr, instrIndex, 0);
|
return TryInlineOtherMethod(patchIndex, methodToInline, instr, instrIndex, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual Instruction onAfterLoadArg(MethodDef methodToInline, Instruction instr, ref int instrIndex) {
|
protected virtual Instruction OnAfterLoadArg(MethodDef methodToInline, Instruction instr, ref int instrIndex) {
|
||||||
return instr;
|
return instr;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected InstructionPatcher tryInlineOtherMethod(int patchIndex, MethodDef methodToInline, Instruction instr, int instrIndex, int popLastArgs) {
|
protected InstructionPatcher TryInlineOtherMethod(int patchIndex, MethodDef methodToInline, Instruction instr, int instrIndex, int popLastArgs) {
|
||||||
int loadIndex = 0;
|
int loadIndex = 0;
|
||||||
int methodArgsCount = DotNetUtils.getArgsCount(methodToInline);
|
int methodArgsCount = DotNetUtils.GetArgsCount(methodToInline);
|
||||||
bool foundLdarga = false;
|
bool foundLdarga = false;
|
||||||
while (instr != null && loadIndex < methodArgsCount) {
|
while (instr != null && loadIndex < methodArgsCount) {
|
||||||
bool isLdarg = true;
|
bool isLdarg = true;
|
||||||
|
@ -136,8 +136,8 @@ namespace de4dot.blocks.cflow {
|
||||||
if (instr.GetParameterIndex() != loadIndex)
|
if (instr.GetParameterIndex() != loadIndex)
|
||||||
return null;
|
return null;
|
||||||
loadIndex++;
|
loadIndex++;
|
||||||
instr = DotNetUtils.getInstruction(methodToInline.Body.Instructions, ref instrIndex);
|
instr = DotNetUtils.GetInstruction(methodToInline.Body.Instructions, ref instrIndex);
|
||||||
instr = onAfterLoadArg(methodToInline, instr, ref instrIndex);
|
instr = OnAfterLoadArg(methodToInline, instr, ref instrIndex);
|
||||||
}
|
}
|
||||||
if (instr == null || loadIndex != methodArgsCount - popLastArgs)
|
if (instr == null || loadIndex != methodArgsCount - popLastArgs)
|
||||||
return null;
|
return null;
|
||||||
|
@ -150,13 +150,13 @@ namespace de4dot.blocks.cflow {
|
||||||
if (calledMethod == null)
|
if (calledMethod == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
if (!isCompatibleType(-1, calledMethod.MethodSig.RetType, methodToInline.MethodSig.RetType))
|
if (!IsCompatibleType(-1, calledMethod.MethodSig.RetType, methodToInline.MethodSig.RetType))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
if (!checkSameMethods(calledMethod, methodToInline, popLastArgs))
|
if (!CheckSameMethods(calledMethod, methodToInline, popLastArgs))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
if (!hasAccessTo(instr.Operand))
|
if (!HasAccessTo(instr.Operand))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return new InstructionPatcher(patchIndex, instrIndex, callInstr);
|
return new InstructionPatcher(patchIndex, instrIndex, callInstr);
|
||||||
|
@ -169,19 +169,19 @@ namespace de4dot.blocks.cflow {
|
||||||
if (ctor == null)
|
if (ctor == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
if (!isCompatibleType(-1, ctor.DeclaringType, methodToInline.MethodSig.RetType))
|
if (!IsCompatibleType(-1, ctor.DeclaringType, methodToInline.MethodSig.RetType))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var methodArgs = methodToInline.Parameters;
|
var methodArgs = methodToInline.Parameters;
|
||||||
var calledMethodArgs = DotNetUtils.getArgs(ctor);
|
var calledMethodArgs = DotNetUtils.GetArgs(ctor);
|
||||||
if (methodArgs.Count + 1 - popLastArgs != calledMethodArgs.Count)
|
if (methodArgs.Count + 1 - popLastArgs != calledMethodArgs.Count)
|
||||||
return null;
|
return null;
|
||||||
for (int i = 1; i < calledMethodArgs.Count; i++) {
|
for (int i = 1; i < calledMethodArgs.Count; i++) {
|
||||||
if (!isCompatibleType(i, calledMethodArgs[i], methodArgs[i - 1].Type))
|
if (!IsCompatibleType(i, calledMethodArgs[i], methodArgs[i - 1].Type))
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasAccessTo(instr.Operand))
|
if (!HasAccessTo(instr.Operand))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return new InstructionPatcher(patchIndex, instrIndex, newobjInstr);
|
return new InstructionPatcher(patchIndex, instrIndex, newobjInstr);
|
||||||
|
@ -192,7 +192,7 @@ namespace de4dot.blocks.cflow {
|
||||||
if (methodArgsCount != 1)
|
if (methodArgsCount != 1)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
if (!hasAccessTo(instr.Operand))
|
if (!HasAccessTo(instr.Operand))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return new InstructionPatcher(patchIndex, instrIndex, ldInstr);
|
return new InstructionPatcher(patchIndex, instrIndex, ldInstr);
|
||||||
|
@ -201,36 +201,36 @@ namespace de4dot.blocks.cflow {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasAccessTo(object operand) {
|
bool HasAccessTo(object operand) {
|
||||||
if (operand == null)
|
if (operand == null)
|
||||||
return false;
|
return false;
|
||||||
accessChecker.UserType = blocks.Method.DeclaringType;
|
accessChecker.UserType = blocks.Method.DeclaringType;
|
||||||
return accessChecker.CanAccess(operand) ?? getDefaultAccessResult();
|
return accessChecker.CanAccess(operand) ?? GetDefaultAccessResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual bool getDefaultAccessResult() {
|
protected virtual bool GetDefaultAccessResult() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual bool isReturn(MethodDef methodToInline, int instrIndex) {
|
protected virtual bool IsReturn(MethodDef methodToInline, int instrIndex) {
|
||||||
var instr = DotNetUtils.getInstruction(methodToInline.Body.Instructions, ref instrIndex);
|
var instr = DotNetUtils.GetInstruction(methodToInline.Body.Instructions, ref instrIndex);
|
||||||
return instr != null && instr.OpCode.Code == Code.Ret;
|
return instr != null && instr.OpCode.Code == Code.Ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool checkSameMethods(IMethod method, MethodDef methodToInline) {
|
protected bool CheckSameMethods(IMethod method, MethodDef methodToInline) {
|
||||||
return checkSameMethods(method, methodToInline, 0);
|
return CheckSameMethods(method, methodToInline, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool checkSameMethods(IMethod method, MethodDef methodToInline, int ignoreLastMethodToInlineArgs) {
|
protected bool CheckSameMethods(IMethod method, MethodDef methodToInline, int ignoreLastMethodToInlineArgs) {
|
||||||
var methodToInlineArgs = methodToInline.Parameters;
|
var methodToInlineArgs = methodToInline.Parameters;
|
||||||
var methodArgs = DotNetUtils.getArgs(method);
|
var methodArgs = DotNetUtils.GetArgs(method);
|
||||||
bool hasImplicitThis = method.MethodSig.ImplicitThis;
|
bool hasImplicitThis = method.MethodSig.ImplicitThis;
|
||||||
if (methodToInlineArgs.Count - ignoreLastMethodToInlineArgs != methodArgs.Count)
|
if (methodToInlineArgs.Count - ignoreLastMethodToInlineArgs != methodArgs.Count)
|
||||||
return false;
|
return false;
|
||||||
for (int i = 0; i < methodArgs.Count; i++) {
|
for (int i = 0; i < methodArgs.Count; i++) {
|
||||||
var methodArg = methodArgs[i];
|
var methodArg = methodArgs[i];
|
||||||
var methodToInlineArg = getArgType(methodToInline, methodToInlineArgs[i].Type);
|
var methodToInlineArg = GetArgType(methodToInline, methodToInlineArgs[i].Type);
|
||||||
if (!isCompatibleType(i, methodArg, methodToInlineArg)) {
|
if (!IsCompatibleType(i, methodArg, methodToInlineArg)) {
|
||||||
if (i != 0 || !hasImplicitThis)
|
if (i != 0 || !hasImplicitThis)
|
||||||
return false;
|
return false;
|
||||||
if (!isCompatibleValueThisPtr(methodArg, methodToInlineArg))
|
if (!isCompatibleValueThisPtr(methodArg, methodToInlineArg))
|
||||||
|
@ -241,7 +241,7 @@ namespace de4dot.blocks.cflow {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static TypeSig getArgType(MethodDef method, TypeSig arg) {
|
static TypeSig GetArgType(MethodDef method, TypeSig arg) {
|
||||||
if (arg.GetElementType() != ElementType.MVar)
|
if (arg.GetElementType() != ElementType.MVar)
|
||||||
return arg;
|
return arg;
|
||||||
var mvar = (GenericMVar)arg;
|
var mvar = (GenericMVar)arg;
|
||||||
|
@ -254,7 +254,7 @@ namespace de4dot.blocks.cflow {
|
||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual bool isCompatibleType(int paramIndex, IType origType, IType newType) {
|
protected virtual bool IsCompatibleType(int paramIndex, IType origType, IType newType) {
|
||||||
return new SigComparer().Equals(origType, newType);
|
return new SigComparer().Equals(origType, newType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,12 +262,12 @@ namespace de4dot.blocks.cflow {
|
||||||
var newByRef = newType as ByRefSig;
|
var newByRef = newType as ByRefSig;
|
||||||
if (newByRef == null)
|
if (newByRef == null)
|
||||||
return false;
|
return false;
|
||||||
if (!isValueType(newByRef.Next) || !isValueType(origType))
|
if (!IsValueType(newByRef.Next) || !IsValueType(origType))
|
||||||
return false;
|
return false;
|
||||||
return new SigComparer().Equals(origType, newByRef.Next);
|
return new SigComparer().Equals(origType, newByRef.Next);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static bool isValueType(IType type) {
|
protected static bool IsValueType(IType type) {
|
||||||
if (type == null)
|
if (type == null)
|
||||||
return false;
|
return false;
|
||||||
var ts = type as TypeSig;
|
var ts = type as TypeSig;
|
||||||
|
|
|
@ -26,12 +26,12 @@ namespace de4dot.blocks.cflow {
|
||||||
class StLdlocFixer : BlockDeobfuscator {
|
class StLdlocFixer : BlockDeobfuscator {
|
||||||
IList<Local> locals;
|
IList<Local> locals;
|
||||||
|
|
||||||
protected override void init(List<Block> allBlocks) {
|
protected override void Initialize(List<Block> allBlocks) {
|
||||||
base.init(allBlocks);
|
base.Initialize(allBlocks);
|
||||||
locals = blocks.Locals;
|
locals = blocks.Locals;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool deobfuscate(Block block) {
|
protected override bool Deobfuscate(Block block) {
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
var instructions = block.Instructions;
|
var instructions = block.Instructions;
|
||||||
for (int i = 0; i < instructions.Count; i++) {
|
for (int i = 0; i < instructions.Count; i++) {
|
||||||
|
@ -47,12 +47,12 @@ namespace de4dot.blocks.cflow {
|
||||||
case Code.Stloc_3:
|
case Code.Stloc_3:
|
||||||
if (i + 1 >= instructions.Count)
|
if (i + 1 >= instructions.Count)
|
||||||
break;
|
break;
|
||||||
if (!instructions[i + 1].isLdloc())
|
if (!instructions[i + 1].IsLdloc())
|
||||||
break;
|
break;
|
||||||
var local = Instr.getLocalVar(locals, instr);
|
var local = Instr.GetLocalVar(locals, instr);
|
||||||
if (local.Type.ElementType != ElementType.Boolean)
|
if (local.Type.ElementType != ElementType.Boolean)
|
||||||
continue;
|
continue;
|
||||||
if (local != Instr.getLocalVar(locals, instructions[i + 1]))
|
if (local != Instr.GetLocalVar(locals, instructions[i + 1]))
|
||||||
break;
|
break;
|
||||||
instructions[i] = new Instr(OpCodes.Dup.ToInstruction());
|
instructions[i] = new Instr(OpCodes.Dup.ToInstruction());
|
||||||
instructions[i + 1] = instr;
|
instructions[i + 1] = instr;
|
||||||
|
|
|
@ -26,50 +26,50 @@ namespace de4dot.blocks.cflow {
|
||||||
class SwitchCflowDeobfuscator : BlockDeobfuscator {
|
class SwitchCflowDeobfuscator : BlockDeobfuscator {
|
||||||
InstructionEmulator instructionEmulator = new InstructionEmulator();
|
InstructionEmulator instructionEmulator = new InstructionEmulator();
|
||||||
|
|
||||||
protected override bool deobfuscate(Block switchBlock) {
|
protected override bool Deobfuscate(Block switchBlock) {
|
||||||
if (switchBlock.LastInstr.OpCode.Code != Code.Switch)
|
if (switchBlock.LastInstr.OpCode.Code != Code.Switch)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (isSwitchTopOfStack(switchBlock) && deobfuscateTos(switchBlock))
|
if (IsSwitchTopOfStack(switchBlock) && DeobfuscateTOS(switchBlock))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (isLdlocBranch(switchBlock, true) && deobfuscateLdloc(switchBlock))
|
if (IsLdlocBranch(switchBlock, true) && DeobfuscateLdloc(switchBlock))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (isStLdlocBranch(switchBlock, true) && deobfuscateStLdloc(switchBlock))
|
if (IsStLdlocBranch(switchBlock, true) && DeobfuscateStLdloc(switchBlock))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (isSwitchType1(switchBlock) && deobfuscateType1(switchBlock))
|
if (IsSwitchType1(switchBlock) && DeobfuscateType1(switchBlock))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (isSwitchType2(switchBlock) && deobfuscateType2(switchBlock))
|
if (IsSwitchType2(switchBlock) && DeobfuscateType2(switchBlock))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (switchBlock.FirstInstr.isLdloc() && fixSwitchBranch(switchBlock))
|
if (switchBlock.FirstInstr.IsLdloc() && FixSwitchBranch(switchBlock))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isSwitchTopOfStack(Block switchBlock) {
|
static bool IsSwitchTopOfStack(Block switchBlock) {
|
||||||
return switchBlock.Instructions.Count == 1;
|
return switchBlock.Instructions.Count == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isLdlocBranch(Block switchBlock, bool isSwitch) {
|
static bool IsLdlocBranch(Block switchBlock, bool isSwitch) {
|
||||||
int numInstrs = 1 + (isSwitch ? 1 : 0);
|
int numInstrs = 1 + (isSwitch ? 1 : 0);
|
||||||
return switchBlock.Instructions.Count == numInstrs && switchBlock.Instructions[0].isLdloc();
|
return switchBlock.Instructions.Count == numInstrs && switchBlock.Instructions[0].IsLdloc();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isSwitchType1(Block switchBlock) {
|
static bool IsSwitchType1(Block switchBlock) {
|
||||||
return switchBlock.FirstInstr.isLdloc();
|
return switchBlock.FirstInstr.IsLdloc();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isSwitchType2(Block switchBlock) {
|
bool IsSwitchType2(Block switchBlock) {
|
||||||
Local local = null;
|
Local local = null;
|
||||||
foreach (var instr in switchBlock.Instructions) {
|
foreach (var instr in switchBlock.Instructions) {
|
||||||
if (!instr.isLdloc())
|
if (!instr.IsLdloc())
|
||||||
continue;
|
continue;
|
||||||
local = Instr.getLocalVar(blocks.Locals, instr);
|
local = Instr.GetLocalVar(blocks.Locals, instr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (local == null)
|
if (local == null)
|
||||||
|
@ -79,12 +79,12 @@ namespace de4dot.blocks.cflow {
|
||||||
var instrs = source.Instructions;
|
var instrs = source.Instructions;
|
||||||
for (int i = 1; i < instrs.Count; i++) {
|
for (int i = 1; i < instrs.Count; i++) {
|
||||||
var ldci4 = instrs[i - 1];
|
var ldci4 = instrs[i - 1];
|
||||||
if (!ldci4.isLdcI4())
|
if (!ldci4.IsLdcI4())
|
||||||
continue;
|
continue;
|
||||||
var stloc = instrs[i];
|
var stloc = instrs[i];
|
||||||
if (!stloc.isStloc())
|
if (!stloc.IsStloc())
|
||||||
continue;
|
continue;
|
||||||
if (Instr.getLocalVar(blocks.Locals, stloc) != local)
|
if (Instr.GetLocalVar(blocks.Locals, stloc) != local)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -94,29 +94,29 @@ namespace de4dot.blocks.cflow {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isStLdlocBranch(Block switchBlock, bool isSwitch) {
|
bool IsStLdlocBranch(Block switchBlock, bool isSwitch) {
|
||||||
int numInstrs = 2 + (isSwitch ? 1 : 0);
|
int numInstrs = 2 + (isSwitch ? 1 : 0);
|
||||||
return switchBlock.Instructions.Count == numInstrs &&
|
return switchBlock.Instructions.Count == numInstrs &&
|
||||||
switchBlock.Instructions[0].isStloc() &&
|
switchBlock.Instructions[0].IsStloc() &&
|
||||||
switchBlock.Instructions[1].isLdloc() &&
|
switchBlock.Instructions[1].IsLdloc() &&
|
||||||
Instr.getLocalVar(blocks.Locals, switchBlock.Instructions[0]) == Instr.getLocalVar(blocks.Locals, switchBlock.Instructions[1]);
|
Instr.GetLocalVar(blocks.Locals, switchBlock.Instructions[0]) == Instr.GetLocalVar(blocks.Locals, switchBlock.Instructions[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool deobfuscateTos(Block switchBlock) {
|
bool DeobfuscateTOS(Block switchBlock) {
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
if (switchBlock.Targets == null)
|
if (switchBlock.Targets == null)
|
||||||
return changed;
|
return changed;
|
||||||
var targets = new List<Block>(switchBlock.Targets);
|
var targets = new List<Block>(switchBlock.Targets);
|
||||||
|
|
||||||
changed |= deobfuscateTos(targets, switchBlock.FallThrough, switchBlock);
|
changed |= DeobfuscateTOS(targets, switchBlock.FallThrough, switchBlock);
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool deobfuscateLdloc(Block switchBlock) {
|
bool DeobfuscateLdloc(Block switchBlock) {
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
|
||||||
var switchVariable = Instr.getLocalVar(blocks.Locals, switchBlock.Instructions[0]);
|
var switchVariable = Instr.GetLocalVar(blocks.Locals, switchBlock.Instructions[0]);
|
||||||
if (switchVariable == null)
|
if (switchVariable == null)
|
||||||
return changed;
|
return changed;
|
||||||
|
|
||||||
|
@ -124,15 +124,15 @@ namespace de4dot.blocks.cflow {
|
||||||
return changed;
|
return changed;
|
||||||
var targets = new List<Block>(switchBlock.Targets);
|
var targets = new List<Block>(switchBlock.Targets);
|
||||||
|
|
||||||
changed |= deobfuscateLdloc(targets, switchBlock.FallThrough, switchBlock, switchVariable);
|
changed |= DeobfuscateLdloc(targets, switchBlock.FallThrough, switchBlock, switchVariable);
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool deobfuscateStLdloc(Block switchBlock) {
|
bool DeobfuscateStLdloc(Block switchBlock) {
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
|
||||||
var switchVariable = Instr.getLocalVar(blocks.Locals, switchBlock.Instructions[0]);
|
var switchVariable = Instr.GetLocalVar(blocks.Locals, switchBlock.Instructions[0]);
|
||||||
if (switchVariable == null)
|
if (switchVariable == null)
|
||||||
return changed;
|
return changed;
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@ namespace de4dot.blocks.cflow {
|
||||||
return changed;
|
return changed;
|
||||||
var targets = new List<Block>(switchBlock.Targets);
|
var targets = new List<Block>(switchBlock.Targets);
|
||||||
|
|
||||||
changed |= deobfuscateStLdloc(targets, switchBlock.FallThrough, switchBlock);
|
changed |= DeobfuscateStLdloc(targets, switchBlock.FallThrough, switchBlock);
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
@ -153,19 +153,19 @@ namespace de4dot.blocks.cflow {
|
||||||
// stloc N
|
// stloc N
|
||||||
// ldloc N
|
// ldloc N
|
||||||
// switch (......)
|
// switch (......)
|
||||||
bool deobfuscateStLdloc(IList<Block> switchTargets, Block switchFallThrough, Block block) {
|
bool DeobfuscateStLdloc(IList<Block> switchTargets, Block switchFallThrough, Block block) {
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
foreach (var source in new List<Block>(block.Sources)) {
|
foreach (var source in new List<Block>(block.Sources)) {
|
||||||
if (!isBranchBlock(source))
|
if (!isBranchBlock(source))
|
||||||
continue;
|
continue;
|
||||||
instructionEmulator.init(blocks);
|
instructionEmulator.Initialize(blocks);
|
||||||
instructionEmulator.emulate(source.Instructions);
|
instructionEmulator.Emulate(source.Instructions);
|
||||||
|
|
||||||
var target = getSwitchTarget(switchTargets, switchFallThrough, instructionEmulator.pop());
|
var target = GetSwitchTarget(switchTargets, switchFallThrough, instructionEmulator.Pop());
|
||||||
if (target == null)
|
if (target == null)
|
||||||
continue;
|
continue;
|
||||||
source.replaceLastNonBranchWithBranch(0, target);
|
source.ReplaceLastNonBranchWithBranch(0, target);
|
||||||
source.add(new Instr(OpCodes.Pop.ToInstruction()));
|
source.Add(new Instr(OpCodes.Pop.ToInstruction()));
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
return changed;
|
return changed;
|
||||||
|
@ -179,32 +179,32 @@ namespace de4dot.blocks.cflow {
|
||||||
// swblk:
|
// swblk:
|
||||||
// ldloc N
|
// ldloc N
|
||||||
// switch (......)
|
// switch (......)
|
||||||
bool deobfuscateLdloc(IList<Block> switchTargets, Block switchFallThrough, Block block, Local switchVariable) {
|
bool DeobfuscateLdloc(IList<Block> switchTargets, Block switchFallThrough, Block block, Local switchVariable) {
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
foreach (var source in new List<Block>(block.Sources)) {
|
foreach (var source in new List<Block>(block.Sources)) {
|
||||||
if (isBranchBlock(source)) {
|
if (isBranchBlock(source)) {
|
||||||
instructionEmulator.init(blocks);
|
instructionEmulator.Initialize(blocks);
|
||||||
instructionEmulator.emulate(source.Instructions);
|
instructionEmulator.Emulate(source.Instructions);
|
||||||
|
|
||||||
var target = getSwitchTarget(switchTargets, switchFallThrough, instructionEmulator.getLocal(switchVariable));
|
var target = GetSwitchTarget(switchTargets, switchFallThrough, instructionEmulator.GetLocal(switchVariable));
|
||||||
if (target == null)
|
if (target == null)
|
||||||
continue;
|
continue;
|
||||||
source.replaceLastNonBranchWithBranch(0, target);
|
source.ReplaceLastNonBranchWithBranch(0, target);
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
else if (isBccBlock(source)) {
|
else if (IsBccBlock(source)) {
|
||||||
instructionEmulator.init(blocks);
|
instructionEmulator.Initialize(blocks);
|
||||||
instructionEmulator.emulate(source.Instructions);
|
instructionEmulator.Emulate(source.Instructions);
|
||||||
|
|
||||||
var target = getSwitchTarget(switchTargets, switchFallThrough, instructionEmulator.getLocal(switchVariable));
|
var target = GetSwitchTarget(switchTargets, switchFallThrough, instructionEmulator.GetLocal(switchVariable));
|
||||||
if (target == null)
|
if (target == null)
|
||||||
continue;
|
continue;
|
||||||
if (source.Targets[0] == block) {
|
if (source.Targets[0] == block) {
|
||||||
source.setNewTarget(0, target);
|
source.SetNewTarget(0, target);
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
if (source.FallThrough == block) {
|
if (source.FallThrough == block) {
|
||||||
source.setNewFallThrough(target);
|
source.SetNewFallThrough(target);
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -218,21 +218,21 @@ namespace de4dot.blocks.cflow {
|
||||||
// br swblk
|
// br swblk
|
||||||
// swblk:
|
// swblk:
|
||||||
// switch (......)
|
// switch (......)
|
||||||
bool deobfuscateTos(IList<Block> switchTargets, Block switchFallThrough, Block block) {
|
bool DeobfuscateTOS(IList<Block> switchTargets, Block switchFallThrough, Block block) {
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
foreach (var source in new List<Block>(block.Sources)) {
|
foreach (var source in new List<Block>(block.Sources)) {
|
||||||
if (!isBranchBlock(source))
|
if (!isBranchBlock(source))
|
||||||
continue;
|
continue;
|
||||||
instructionEmulator.init(blocks);
|
instructionEmulator.Initialize(blocks);
|
||||||
instructionEmulator.emulate(source.Instructions);
|
instructionEmulator.Emulate(source.Instructions);
|
||||||
|
|
||||||
var target = getSwitchTarget(switchTargets, switchFallThrough, instructionEmulator.pop());
|
var target = GetSwitchTarget(switchTargets, switchFallThrough, instructionEmulator.Pop());
|
||||||
if (target == null) {
|
if (target == null) {
|
||||||
changed |= deobfuscateTos_Ldloc(switchTargets, switchFallThrough, source);
|
changed |= DeobfuscateTos_Ldloc(switchTargets, switchFallThrough, source);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
source.replaceLastNonBranchWithBranch(0, target);
|
source.ReplaceLastNonBranchWithBranch(0, target);
|
||||||
source.add(new Instr(OpCodes.Pop.ToInstruction()));
|
source.Add(new Instr(OpCodes.Pop.ToInstruction()));
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -245,15 +245,15 @@ namespace de4dot.blocks.cflow {
|
||||||
// stloc N
|
// stloc N
|
||||||
// ldloc N
|
// ldloc N
|
||||||
// br swblk
|
// br swblk
|
||||||
bool deobfuscateTos_Ldloc(IList<Block> switchTargets, Block switchFallThrough, Block block) {
|
bool DeobfuscateTos_Ldloc(IList<Block> switchTargets, Block switchFallThrough, Block block) {
|
||||||
if (isLdlocBranch(block, false)) {
|
if (IsLdlocBranch(block, false)) {
|
||||||
var switchVariable = Instr.getLocalVar(blocks.Locals, block.Instructions[0]);
|
var switchVariable = Instr.GetLocalVar(blocks.Locals, block.Instructions[0]);
|
||||||
if (switchVariable == null)
|
if (switchVariable == null)
|
||||||
return false;
|
return false;
|
||||||
return deobfuscateLdloc(switchTargets, switchFallThrough, block, switchVariable);
|
return DeobfuscateLdloc(switchTargets, switchFallThrough, block, switchVariable);
|
||||||
}
|
}
|
||||||
else if (isStLdlocBranch(block, false))
|
else if (IsStLdlocBranch(block, false))
|
||||||
return deobfuscateStLdloc(switchTargets, switchFallThrough, block);
|
return DeobfuscateStLdloc(switchTargets, switchFallThrough, block);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -273,7 +273,7 @@ namespace de4dot.blocks.cflow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isBccBlock(Block block) {
|
static bool IsBccBlock(Block block) {
|
||||||
if (block.Targets == null || block.Targets.Count != 1)
|
if (block.Targets == null || block.Targets.Count != 1)
|
||||||
return false;
|
return false;
|
||||||
if (block.FallThrough == null)
|
if (block.FallThrough == null)
|
||||||
|
@ -309,91 +309,91 @@ namespace de4dot.blocks.cflow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool deobfuscateType1(Block switchBlock) {
|
bool DeobfuscateType1(Block switchBlock) {
|
||||||
Block target;
|
Block target;
|
||||||
if (!emulateGetTarget(switchBlock, out target) || target != null)
|
if (!EmulateGetTarget(switchBlock, out target) || target != null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
|
||||||
foreach (var source in new List<Block>(switchBlock.Sources)) {
|
foreach (var source in new List<Block>(switchBlock.Sources)) {
|
||||||
if (!source.canAppend(switchBlock))
|
if (!source.CanAppend(switchBlock))
|
||||||
continue;
|
continue;
|
||||||
if (!willHaveKnownTarget(switchBlock, source))
|
if (!WillHaveKnownTarget(switchBlock, source))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
source.append(switchBlock);
|
source.Append(switchBlock);
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool deobfuscateType2(Block switchBlock) {
|
bool DeobfuscateType2(Block switchBlock) {
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
|
||||||
var bccSources = new List<Block>();
|
var bccSources = new List<Block>();
|
||||||
foreach (var source in new List<Block>(switchBlock.Sources)) {
|
foreach (var source in new List<Block>(switchBlock.Sources)) {
|
||||||
if (source.LastInstr.isConditionalBranch()) {
|
if (source.LastInstr.IsConditionalBranch()) {
|
||||||
bccSources.Add(source);
|
bccSources.Add(source);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!source.canAppend(switchBlock))
|
if (!source.CanAppend(switchBlock))
|
||||||
continue;
|
continue;
|
||||||
if (!willHaveKnownTarget(switchBlock, source))
|
if (!WillHaveKnownTarget(switchBlock, source))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
source.append(switchBlock);
|
source.Append(switchBlock);
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var bccSource in bccSources) {
|
foreach (var bccSource in bccSources) {
|
||||||
if (!willHaveKnownTarget(switchBlock, bccSource))
|
if (!WillHaveKnownTarget(switchBlock, bccSource))
|
||||||
continue;
|
continue;
|
||||||
var consts = getBccLocalConstants(bccSource);
|
var consts = GetBccLocalConstants(bccSource);
|
||||||
if (consts.Count == 0)
|
if (consts.Count == 0)
|
||||||
continue;
|
continue;
|
||||||
var newFallThrough = createBlock(consts, bccSource.FallThrough);
|
var newFallThrough = CreateBlock(consts, bccSource.FallThrough);
|
||||||
var newTarget = createBlock(consts, bccSource.Targets[0]);
|
var newTarget = CreateBlock(consts, bccSource.Targets[0]);
|
||||||
var oldFallThrough = bccSource.FallThrough;
|
var oldFallThrough = bccSource.FallThrough;
|
||||||
var oldTarget = bccSource.Targets[0];
|
var oldTarget = bccSource.Targets[0];
|
||||||
bccSource.setNewFallThrough(newFallThrough);
|
bccSource.SetNewFallThrough(newFallThrough);
|
||||||
bccSource.setNewTarget(0, newTarget);
|
bccSource.SetNewTarget(0, newTarget);
|
||||||
newFallThrough.setNewFallThrough(oldFallThrough);
|
newFallThrough.SetNewFallThrough(oldFallThrough);
|
||||||
newTarget.setNewFallThrough(oldTarget);
|
newTarget.SetNewFallThrough(oldTarget);
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Block createBlock(Dictionary<Local, int> consts, Block fallThrough) {
|
static Block CreateBlock(Dictionary<Local, int> consts, Block fallThrough) {
|
||||||
var block = new Block();
|
var block = new Block();
|
||||||
foreach (var kv in consts) {
|
foreach (var kv in consts) {
|
||||||
block.Instructions.Add(new Instr(Instruction.CreateLdcI4(kv.Value)));
|
block.Instructions.Add(new Instr(Instruction.CreateLdcI4(kv.Value)));
|
||||||
block.Instructions.Add(new Instr(OpCodes.Stloc.ToInstruction(kv.Key)));
|
block.Instructions.Add(new Instr(OpCodes.Stloc.ToInstruction(kv.Key)));
|
||||||
}
|
}
|
||||||
fallThrough.Parent.add(block);
|
fallThrough.Parent.Add(block);
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary<Local, int> getBccLocalConstants(Block block) {
|
Dictionary<Local, int> GetBccLocalConstants(Block block) {
|
||||||
var dict = new Dictionary<Local, int>();
|
var dict = new Dictionary<Local, int>();
|
||||||
var instrs = block.Instructions;
|
var instrs = block.Instructions;
|
||||||
for (int i = 0; i < instrs.Count; i++) {
|
for (int i = 0; i < instrs.Count; i++) {
|
||||||
var instr = instrs[i];
|
var instr = instrs[i];
|
||||||
if (instr.isStloc()) {
|
if (instr.IsStloc()) {
|
||||||
var local = Instr.getLocalVar(blocks.Locals, instr);
|
var local = Instr.GetLocalVar(blocks.Locals, instr);
|
||||||
if (local == null)
|
if (local == null)
|
||||||
continue;
|
continue;
|
||||||
var ldci4 = i == 0 ? null : instrs[i - 1];
|
var ldci4 = i == 0 ? null : instrs[i - 1];
|
||||||
if (ldci4 == null || !ldci4.isLdcI4())
|
if (ldci4 == null || !ldci4.IsLdcI4())
|
||||||
dict.Remove(local);
|
dict.Remove(local);
|
||||||
else
|
else
|
||||||
dict[local] = ldci4.getLdcI4Value();
|
dict[local] = ldci4.GetLdcI4Value();
|
||||||
}
|
}
|
||||||
else if (instr.isLdloc()) {
|
else if (instr.IsLdloc()) {
|
||||||
var local = Instr.getLocalVar(blocks.Locals, instr);
|
var local = Instr.GetLocalVar(blocks.Locals, instr);
|
||||||
if (local != null)
|
if (local != null)
|
||||||
dict.Remove(local);
|
dict.Remove(local);
|
||||||
}
|
}
|
||||||
|
@ -406,47 +406,47 @@ namespace de4dot.blocks.cflow {
|
||||||
return dict;
|
return dict;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool emulateGetTarget(Block switchBlock, out Block target) {
|
bool EmulateGetTarget(Block switchBlock, out Block target) {
|
||||||
instructionEmulator.init(blocks);
|
instructionEmulator.Initialize(blocks);
|
||||||
try {
|
try {
|
||||||
instructionEmulator.emulate(switchBlock.Instructions, 0, switchBlock.Instructions.Count - 1);
|
instructionEmulator.Emulate(switchBlock.Instructions, 0, switchBlock.Instructions.Count - 1);
|
||||||
}
|
}
|
||||||
catch (NullReferenceException) {
|
catch (NullReferenceException) {
|
||||||
// Here if eg. invalid metadata token in a call instruction (operand is null)
|
// Here if eg. invalid metadata token in a call instruction (operand is null)
|
||||||
target = null;
|
target = null;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
target = getTarget(switchBlock);
|
target = GetTarget(switchBlock);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool willHaveKnownTarget(Block switchBlock, Block source) {
|
bool WillHaveKnownTarget(Block switchBlock, Block source) {
|
||||||
instructionEmulator.init(blocks);
|
instructionEmulator.Initialize(blocks);
|
||||||
try {
|
try {
|
||||||
instructionEmulator.emulate(source.Instructions);
|
instructionEmulator.Emulate(source.Instructions);
|
||||||
instructionEmulator.emulate(switchBlock.Instructions, 0, switchBlock.Instructions.Count - 1);
|
instructionEmulator.Emulate(switchBlock.Instructions, 0, switchBlock.Instructions.Count - 1);
|
||||||
}
|
}
|
||||||
catch (NullReferenceException) {
|
catch (NullReferenceException) {
|
||||||
// Here if eg. invalid metadata token in a call instruction (operand is null)
|
// Here if eg. invalid metadata token in a call instruction (operand is null)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return getTarget(switchBlock) != null;
|
return GetTarget(switchBlock) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Block getTarget(Block switchBlock) {
|
Block GetTarget(Block switchBlock) {
|
||||||
var val1 = instructionEmulator.pop();
|
var val1 = instructionEmulator.Pop();
|
||||||
if (!val1.isInt32())
|
if (!val1.IsInt32())
|
||||||
return null;
|
return null;
|
||||||
return CflowUtils.getSwitchTarget(switchBlock.Targets, switchBlock.FallThrough, (Int32Value)val1);
|
return CflowUtils.GetSwitchTarget(switchBlock.Targets, switchBlock.FallThrough, (Int32Value)val1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Block getSwitchTarget(IList<Block> targets, Block fallThrough, Value value) {
|
static Block GetSwitchTarget(IList<Block> targets, Block fallThrough, Value value) {
|
||||||
if (!value.isInt32())
|
if (!value.IsInt32())
|
||||||
return null;
|
return null;
|
||||||
return CflowUtils.getSwitchTarget(targets, fallThrough, (Int32Value)value);
|
return CflowUtils.GetSwitchTarget(targets, fallThrough, (Int32Value)value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool fixSwitchBranch(Block switchBlock) {
|
static bool FixSwitchBranch(Block switchBlock) {
|
||||||
// Code:
|
// Code:
|
||||||
// blk1:
|
// blk1:
|
||||||
// ldc.i4 XXX
|
// ldc.i4 XXX
|
||||||
|
@ -467,11 +467,11 @@ namespace de4dot.blocks.cflow {
|
||||||
foreach (var commonSource in new List<Block>(switchBlock.Sources)) {
|
foreach (var commonSource in new List<Block>(switchBlock.Sources)) {
|
||||||
if (commonSource.Instructions.Count != 1)
|
if (commonSource.Instructions.Count != 1)
|
||||||
continue;
|
continue;
|
||||||
if (!commonSource.FirstInstr.isStloc())
|
if (!commonSource.FirstInstr.IsStloc())
|
||||||
continue;
|
continue;
|
||||||
foreach (var blk in new List<Block>(commonSource.Sources)) {
|
foreach (var blk in new List<Block>(commonSource.Sources)) {
|
||||||
if (blk.canAppend(commonSource)) {
|
if (blk.CanAppend(commonSource)) {
|
||||||
blk.append(commonSource);
|
blk.Append(commonSource);
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,35 +38,35 @@ namespace de4dot.blocks.cflow {
|
||||||
public abstract class Value {
|
public abstract class Value {
|
||||||
public readonly ValueType valueType;
|
public readonly ValueType valueType;
|
||||||
|
|
||||||
public bool isUnknown() {
|
public bool IsUnknown() {
|
||||||
return valueType == ValueType.Unknown;
|
return valueType == ValueType.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isNull() {
|
public bool IsNull() {
|
||||||
return valueType == ValueType.Null;
|
return valueType == ValueType.Null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isObject() {
|
public bool IsObject() {
|
||||||
return valueType == ValueType.Object;
|
return valueType == ValueType.Object;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isBoxed() {
|
public bool IsBoxed() {
|
||||||
return valueType == ValueType.Boxed;
|
return valueType == ValueType.Boxed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isInt32() {
|
public bool IsInt32() {
|
||||||
return valueType == ValueType.Int32;
|
return valueType == ValueType.Int32;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isInt64() {
|
public bool IsInt64() {
|
||||||
return valueType == ValueType.Int64;
|
return valueType == ValueType.Int64;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isReal8() {
|
public bool IsReal8() {
|
||||||
return valueType == ValueType.Real8;
|
return valueType == ValueType.Real8;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isString() {
|
public bool IsString() {
|
||||||
return valueType == ValueType.String;
|
return valueType == ValueType.String;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,43 +29,43 @@ namespace de4dot.blocks.cflow {
|
||||||
get { return stack.Count; }
|
get { return stack.Count; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init() {
|
public void Initialize() {
|
||||||
stack.Clear();
|
stack.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clear() {
|
public void Clear() {
|
||||||
stack.Clear();
|
stack.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void push(Value value) {
|
public void Push(Value value) {
|
||||||
stack.Add(value);
|
stack.Add(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Value peek() {
|
public Value Peek() {
|
||||||
if (stack.Count == 0)
|
if (stack.Count == 0)
|
||||||
return new UnknownValue();
|
return new UnknownValue();
|
||||||
return stack[stack.Count - 1];
|
return stack[stack.Count - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
public Value pop() {
|
public Value Pop() {
|
||||||
Value value = peek();
|
Value value = Peek();
|
||||||
if (stack.Count != 0)
|
if (stack.Count != 0)
|
||||||
stack.RemoveAt(stack.Count - 1);
|
stack.RemoveAt(stack.Count - 1);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void push(int count) {
|
public void Push(int count) {
|
||||||
if (count < 0)
|
if (count < 0)
|
||||||
throw new ArgumentOutOfRangeException("count");
|
throw new ArgumentOutOfRangeException("count");
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
pushUnknown();
|
PushUnknown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void pushUnknown() {
|
public void PushUnknown() {
|
||||||
push(new UnknownValue());
|
Push(new UnknownValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void pop(int count) {
|
public void Pop(int count) {
|
||||||
if (count < 0)
|
if (count < 0)
|
||||||
throw new ArgumentOutOfRangeException("count");
|
throw new ArgumentOutOfRangeException("count");
|
||||||
if (count >= stack.Count)
|
if (count >= stack.Count)
|
||||||
|
@ -74,8 +74,8 @@ namespace de4dot.blocks.cflow {
|
||||||
stack.RemoveRange(stack.Count - count, count);
|
stack.RemoveRange(stack.Count - count, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void copyTop() {
|
public void CopyTop() {
|
||||||
push(peek());
|
Push(Peek());
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() {
|
public override string ToString() {
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
namespace de4dot_x64 {
|
namespace de4dot_x64 {
|
||||||
class Program {
|
class Program {
|
||||||
static int Main(string[] args) {
|
static int Main(string[] args) {
|
||||||
return de4dot.cui.Program.main(args);
|
return de4dot.cui.Program.Main2(args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
[assembly: AssemblyVersion("2.0.2.3405")]
|
[assembly: AssemblyVersion("2.0.3.3405")]
|
||||||
[assembly: AssemblyFileVersion("2.0.2.3405")]
|
[assembly: AssemblyFileVersion("2.0.3.3405")]
|
||||||
|
|
|
@ -43,13 +43,13 @@ namespace de4dot.code.AssemblyClient {
|
||||||
this.loader = loader;
|
this.loader = loader;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void connect() {
|
public void Connect() {
|
||||||
loader.loadServer();
|
loader.LoadServer();
|
||||||
service = loader.createService();
|
service = loader.CreateService();
|
||||||
serverLoadedTime = DateTime.UtcNow;
|
serverLoadedTime = DateTime.UtcNow;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void waitConnected() {
|
public void WaitConnected() {
|
||||||
// If we don't wait here, we'll sometimes get stuck in doNothing(). Make sure the
|
// If we don't wait here, we'll sometimes get stuck in doNothing(). Make sure the
|
||||||
// server has had time to start... This only seems to be needed when starting a
|
// server has had time to start... This only seems to be needed when starting a
|
||||||
// server in a different process, though.
|
// server in a different process, though.
|
||||||
|
@ -61,7 +61,7 @@ namespace de4dot.code.AssemblyClient {
|
||||||
var startTime = DateTime.UtcNow;
|
var startTime = DateTime.UtcNow;
|
||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
service.doNothing();
|
service.DoNothing();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
catch (RemotingException) {
|
catch (RemotingException) {
|
||||||
|
@ -77,7 +77,7 @@ namespace de4dot.code.AssemblyClient {
|
||||||
public void Dispose() {
|
public void Dispose() {
|
||||||
if (service != null) {
|
if (service != null) {
|
||||||
try {
|
try {
|
||||||
service.exit();
|
service.Exit();
|
||||||
}
|
}
|
||||||
catch (RemotingException) {
|
catch (RemotingException) {
|
||||||
// Couldn't connect
|
// Couldn't connect
|
||||||
|
|
|
@ -21,17 +21,17 @@ using dnlib.DotNet;
|
||||||
|
|
||||||
namespace de4dot.code.AssemblyClient {
|
namespace de4dot.code.AssemblyClient {
|
||||||
public interface IAssemblyClientFactory {
|
public interface IAssemblyClientFactory {
|
||||||
IAssemblyClient create();
|
IAssemblyClient Create();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SameAppDomainAssemblyClientFactory : IAssemblyClientFactory {
|
public class SameAppDomainAssemblyClientFactory : IAssemblyClientFactory {
|
||||||
public IAssemblyClient create() {
|
public IAssemblyClient Create() {
|
||||||
return new AssemblyClient(new SameAppDomainAssemblyServerLoader());
|
return new AssemblyClient(new SameAppDomainAssemblyServerLoader());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class NewAppDomainAssemblyClientFactory : IAssemblyClientFactory {
|
public class NewAppDomainAssemblyClientFactory : IAssemblyClientFactory {
|
||||||
public IAssemblyClient create() {
|
public IAssemblyClient Create() {
|
||||||
return new AssemblyClient(new NewAppDomainAssemblyServerLoader());
|
return new AssemblyClient(new NewAppDomainAssemblyServerLoader());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,15 +47,15 @@ namespace de4dot.code.AssemblyClient {
|
||||||
this.serverVersion = serverVersion;
|
this.serverVersion = serverVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IAssemblyClient create(ModuleDef module) {
|
public IAssemblyClient Create(ModuleDef module) {
|
||||||
return new AssemblyClient(new NewProcessAssemblyServerLoader(getServerClrVersion(module)));
|
return new AssemblyClient(new NewProcessAssemblyServerLoader(GetServerClrVersion(module)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public IAssemblyClient create() {
|
public IAssemblyClient Create() {
|
||||||
return new AssemblyClient(new NewProcessAssemblyServerLoader(serverVersion));
|
return new AssemblyClient(new NewProcessAssemblyServerLoader(serverVersion));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static ServerClrVersion getServerClrVersion(ModuleDef module) {
|
internal static ServerClrVersion GetServerClrVersion(ModuleDef module) {
|
||||||
switch (module.GetPointerSize()) {
|
switch (module.GetPointerSize()) {
|
||||||
default:
|
default:
|
||||||
case 4:
|
case 4:
|
||||||
|
|
|
@ -23,7 +23,7 @@ using AssemblyData;
|
||||||
namespace de4dot.code.AssemblyClient {
|
namespace de4dot.code.AssemblyClient {
|
||||||
public interface IAssemblyClient : IDisposable {
|
public interface IAssemblyClient : IDisposable {
|
||||||
IAssemblyService Service { get; }
|
IAssemblyService Service { get; }
|
||||||
void connect();
|
void Connect();
|
||||||
void waitConnected();
|
void WaitConnected();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ using AssemblyData;
|
||||||
|
|
||||||
namespace de4dot.code.AssemblyClient {
|
namespace de4dot.code.AssemblyClient {
|
||||||
interface IAssemblyServerLoader : IDisposable {
|
interface IAssemblyServerLoader : IDisposable {
|
||||||
void loadServer();
|
void LoadServer();
|
||||||
IAssemblyService createService();
|
IAssemblyService CreateService();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,13 +42,13 @@ namespace de4dot.code.AssemblyClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IpcAssemblyServerLoader(ServerClrVersion serverVersion) {
|
protected IpcAssemblyServerLoader(ServerClrVersion serverVersion) {
|
||||||
assemblyServerFilename = getServerName(serverVersion);
|
assemblyServerFilename = GetServerName(serverVersion);
|
||||||
ipcName = Utils.randomName(15, 20);
|
ipcName = Utils.RandomName(15, 20);
|
||||||
ipcUri = Utils.randomName(15, 20);
|
ipcUri = Utils.RandomName(15, 20);
|
||||||
url = string.Format("ipc://{0}/{1}", ipcName, ipcUri);
|
url = string.Format("ipc://{0}/{1}", ipcName, ipcUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
static string getServerName(ServerClrVersion serverVersion) {
|
static string GetServerName(ServerClrVersion serverVersion) {
|
||||||
if (serverVersion == ServerClrVersion.CLR_ANY_ANYCPU)
|
if (serverVersion == ServerClrVersion.CLR_ANY_ANYCPU)
|
||||||
serverVersion = IntPtr.Size == 4 ? ServerClrVersion.CLR_ANY_x86 : ServerClrVersion.CLR_ANY_x64;
|
serverVersion = IntPtr.Size == 4 ? ServerClrVersion.CLR_ANY_x86 : ServerClrVersion.CLR_ANY_x64;
|
||||||
switch (serverVersion) {
|
switch (serverVersion) {
|
||||||
|
@ -62,13 +62,13 @@ namespace de4dot.code.AssemblyClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadServer() {
|
public void LoadServer() {
|
||||||
loadServer(Utils.getPathOfOurFile(assemblyServerFilename));
|
LoadServer(Utils.GetPathOfOurFile(assemblyServerFilename));
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void loadServer(string filename);
|
public abstract void LoadServer(string filename);
|
||||||
|
|
||||||
public IAssemblyService createService() {
|
public IAssemblyService CreateService() {
|
||||||
return (IAssemblyService)Activator.GetObject(typeof(AssemblyService), url);
|
return (IAssemblyService)Activator.GetObject(typeof(AssemblyService), url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,11 +26,11 @@ namespace de4dot.code.AssemblyClient {
|
||||||
AppDomain appDomain;
|
AppDomain appDomain;
|
||||||
Thread thread;
|
Thread thread;
|
||||||
|
|
||||||
public override void loadServer(string filename) {
|
public override void LoadServer(string filename) {
|
||||||
if (appDomain != null)
|
if (appDomain != null)
|
||||||
throw new ApplicationException("Server is already loaded");
|
throw new ApplicationException("Server is already loaded");
|
||||||
|
|
||||||
appDomain = AppDomain.CreateDomain(Utils.randomName(15, 20));
|
appDomain = AppDomain.CreateDomain(Utils.RandomName(15, 20));
|
||||||
thread = new Thread(new ThreadStart(() => {
|
thread = new Thread(new ThreadStart(() => {
|
||||||
try {
|
try {
|
||||||
appDomain.ExecuteAssembly(filename, null, new string[] { ipcName, ipcUri });
|
appDomain.ExecuteAssembly(filename, null, new string[] { ipcName, ipcUri });
|
||||||
|
@ -41,14 +41,14 @@ namespace de4dot.code.AssemblyClient {
|
||||||
catch (AppDomainUnloadedException) {
|
catch (AppDomainUnloadedException) {
|
||||||
// Here if it was unloaded by Dispose()
|
// Here if it was unloaded by Dispose()
|
||||||
}
|
}
|
||||||
unloadAppDomain(appDomain);
|
UnloadAppDomain(appDomain);
|
||||||
appDomain = null;
|
appDomain = null;
|
||||||
}));
|
}));
|
||||||
thread.Start();
|
thread.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Dispose() {
|
public override void Dispose() {
|
||||||
unloadAppDomain(appDomain);
|
UnloadAppDomain(appDomain);
|
||||||
if (thread != null) {
|
if (thread != null) {
|
||||||
try {
|
try {
|
||||||
if (!thread.Join(100))
|
if (!thread.Join(100))
|
||||||
|
@ -60,11 +60,11 @@ namespace de4dot.code.AssemblyClient {
|
||||||
thread = null;
|
thread = null;
|
||||||
}
|
}
|
||||||
// It could still be loaded if the thread was aborted so do it again
|
// It could still be loaded if the thread was aborted so do it again
|
||||||
unloadAppDomain(appDomain);
|
UnloadAppDomain(appDomain);
|
||||||
appDomain = null;
|
appDomain = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void unloadAppDomain(AppDomain appDomain) {
|
static void UnloadAppDomain(AppDomain appDomain) {
|
||||||
if (appDomain != null) {
|
if (appDomain != null) {
|
||||||
try {
|
try {
|
||||||
AppDomain.Unload(appDomain);
|
AppDomain.Unload(appDomain);
|
||||||
|
|
|
@ -32,18 +32,18 @@ namespace de4dot.code.AssemblyClient {
|
||||||
: base(version) {
|
: base(version) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void loadServer(string filename) {
|
public override void LoadServer(string filename) {
|
||||||
if (process != null)
|
if (process != null)
|
||||||
throw new ApplicationException("Server is already loaded");
|
throw new ApplicationException("Server is already loaded");
|
||||||
|
|
||||||
var psi = new ProcessStartInfo {
|
var psi = new ProcessStartInfo {
|
||||||
Arguments = string.Format("{0} {1}", Utils.shellEscape(ipcName), Utils.shellEscape(ipcUri)),
|
Arguments = string.Format("{0} {1}", Utils.ShellEscape(ipcName), Utils.ShellEscape(ipcUri)),
|
||||||
CreateNoWindow = true,
|
CreateNoWindow = true,
|
||||||
ErrorDialog = false,
|
ErrorDialog = false,
|
||||||
FileName = filename,
|
FileName = filename,
|
||||||
LoadUserProfile = false,
|
LoadUserProfile = false,
|
||||||
UseShellExecute = false,
|
UseShellExecute = false,
|
||||||
WorkingDirectory = Utils.getOurBaseDir(),
|
WorkingDirectory = Utils.GetOurBaseDir(),
|
||||||
};
|
};
|
||||||
process = Process.Start(psi);
|
process = Process.Start(psi);
|
||||||
if (process == null)
|
if (process == null)
|
||||||
|
|
|
@ -25,13 +25,13 @@ namespace de4dot.code.AssemblyClient {
|
||||||
class SameAppDomainAssemblyServerLoader : IAssemblyServerLoader {
|
class SameAppDomainAssemblyServerLoader : IAssemblyServerLoader {
|
||||||
IAssemblyService service;
|
IAssemblyService service;
|
||||||
|
|
||||||
public void loadServer() {
|
public void LoadServer() {
|
||||||
if (service != null)
|
if (service != null)
|
||||||
throw new ApplicationException("Server already loaded");
|
throw new ApplicationException("Server already loaded");
|
||||||
service = new AssemblyService();
|
service = new AssemblyService();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IAssemblyService createService() {
|
public IAssemblyService CreateService() {
|
||||||
return service;
|
return service;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,27 +31,27 @@ namespace de4dot.code {
|
||||||
ModuleContext moduleContext;
|
ModuleContext moduleContext;
|
||||||
|
|
||||||
public AssemblyModule(string filename, ModuleContext moduleContext) {
|
public AssemblyModule(string filename, ModuleContext moduleContext) {
|
||||||
this.filename = Utils.getFullPath(filename);
|
this.filename = Utils.GetFullPath(filename);
|
||||||
this.moduleContext = moduleContext;
|
this.moduleContext = moduleContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ModuleDefMD load() {
|
public ModuleDefMD Load() {
|
||||||
return setModule(ModuleDefMD.Load(filename, moduleContext));
|
return SetModule(ModuleDefMD.Load(filename, moduleContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ModuleDefMD load(byte[] fileData) {
|
public ModuleDefMD Load(byte[] fileData) {
|
||||||
return setModule(ModuleDefMD.Load(fileData, moduleContext));
|
return SetModule(ModuleDefMD.Load(fileData, moduleContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
ModuleDefMD setModule(ModuleDefMD newModule) {
|
ModuleDefMD SetModule(ModuleDefMD newModule) {
|
||||||
module = newModule;
|
module = newModule;
|
||||||
TheAssemblyResolver.Instance.addModule(module);
|
TheAssemblyResolver.Instance.AddModule(module);
|
||||||
module.EnableTypeDefFindCache = true;
|
module.EnableTypeDefFindCache = true;
|
||||||
module.Location = filename;
|
module.Location = filename;
|
||||||
return module;
|
return module;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void save(string newFilename, MetaDataFlags mdFlags, IModuleWriterListener writerListener) {
|
public void Save(string newFilename, MetaDataFlags mdFlags, IModuleWriterListener writerListener) {
|
||||||
if (module.IsILOnly) {
|
if (module.IsILOnly) {
|
||||||
var writerOptions = new ModuleWriterOptions(module, writerListener);
|
var writerOptions = new ModuleWriterOptions(module, writerListener);
|
||||||
writerOptions.MetaDataOptions.Flags |= mdFlags;
|
writerOptions.MetaDataOptions.Flags |= mdFlags;
|
||||||
|
@ -68,7 +68,7 @@ namespace de4dot.code {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ModuleDefMD reload(byte[] newModuleData, DumpedMethodsRestorer dumpedMethodsRestorer, IStringDecrypter stringDecrypter) {
|
public ModuleDefMD Reload(byte[] newModuleData, DumpedMethodsRestorer dumpedMethodsRestorer, IStringDecrypter stringDecrypter) {
|
||||||
TheAssemblyResolver.Instance.Remove(module);
|
TheAssemblyResolver.Instance.Remove(module);
|
||||||
var mod = ModuleDefMD.Load(newModuleData, moduleContext);
|
var mod = ModuleDefMD.Load(newModuleData, moduleContext);
|
||||||
if (dumpedMethodsRestorer != null)
|
if (dumpedMethodsRestorer != null)
|
||||||
|
@ -77,7 +77,7 @@ namespace de4dot.code {
|
||||||
mod.MethodDecrypter = dumpedMethodsRestorer;
|
mod.MethodDecrypter = dumpedMethodsRestorer;
|
||||||
mod.TablesStream.ColumnReader = dumpedMethodsRestorer;
|
mod.TablesStream.ColumnReader = dumpedMethodsRestorer;
|
||||||
mod.TablesStream.MethodRowReader = dumpedMethodsRestorer;
|
mod.TablesStream.MethodRowReader = dumpedMethodsRestorer;
|
||||||
return setModule(mod);
|
return SetModule(mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() {
|
public override string ToString() {
|
||||||
|
|
|
@ -27,16 +27,16 @@ namespace de4dot.code {
|
||||||
EnableTypeDefCache = true;
|
EnableTypeDefCache = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addSearchDirectory(string dir) {
|
public void AddSearchDirectory(string dir) {
|
||||||
if (!PostSearchPaths.Contains(dir))
|
if (!PostSearchPaths.Contains(dir))
|
||||||
PostSearchPaths.Add(dir);
|
PostSearchPaths.Add(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addModule(ModuleDef module) {
|
public void AddModule(ModuleDef module) {
|
||||||
AddToCache(module.Assembly);
|
AddToCache(module.Assembly);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeModule(ModuleDef module) {
|
public void RemoveModule(ModuleDef module) {
|
||||||
var assembly = module.Assembly;
|
var assembly = module.Assembly;
|
||||||
if (assembly == null)
|
if (assembly == null)
|
||||||
return;
|
return;
|
||||||
|
@ -44,7 +44,7 @@ namespace de4dot.code {
|
||||||
Remove(module.Assembly);
|
Remove(module.Assembly);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearAll() {
|
public void ClearAll() {
|
||||||
//TODO: cache.Clear();
|
//TODO: cache.Clear();
|
||||||
//TODO: resetSearchPaths();
|
//TODO: resetSearchPaths();
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,25 +28,25 @@ namespace de4dot.code {
|
||||||
public class DeobfuscatorContext : IDeobfuscatorContext {
|
public class DeobfuscatorContext : IDeobfuscatorContext {
|
||||||
Dictionary<string, object> dataDict = new Dictionary<string, object>(StringComparer.Ordinal);
|
Dictionary<string, object> dataDict = new Dictionary<string, object>(StringComparer.Ordinal);
|
||||||
|
|
||||||
public void clear() {
|
public void Clear() {
|
||||||
dataDict.Clear();
|
dataDict.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setData(string name, object data) {
|
public void SetData(string name, object data) {
|
||||||
dataDict[name] = data;
|
dataDict[name] = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public object getData(string name) {
|
public object GetData(string name) {
|
||||||
object value;
|
object value;
|
||||||
dataDict.TryGetValue(name, out value);
|
dataDict.TryGetValue(name, out value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearData(string name) {
|
public void ClearData(string name) {
|
||||||
dataDict.Remove(name);
|
dataDict.Remove(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ITypeDefOrRef getNonGenericTypeRef(ITypeDefOrRef typeRef) {
|
static ITypeDefOrRef GetNonGenericTypeRef(ITypeDefOrRef typeRef) {
|
||||||
var ts = typeRef as TypeSpec;
|
var ts = typeRef as TypeSpec;
|
||||||
if (ts == null)
|
if (ts == null)
|
||||||
return typeRef;
|
return typeRef;
|
||||||
|
@ -56,10 +56,10 @@ namespace de4dot.code {
|
||||||
return gis.GenericType.TypeDefOrRef;
|
return gis.GenericType.TypeDefOrRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TypeDef resolveType(ITypeDefOrRef type) {
|
public TypeDef ResolveType(ITypeDefOrRef type) {
|
||||||
if (type == null)
|
if (type == null)
|
||||||
return null;
|
return null;
|
||||||
type = getNonGenericTypeRef(type);
|
type = GetNonGenericTypeRef(type);
|
||||||
|
|
||||||
var typeDef = type as TypeDef;
|
var typeDef = type as TypeDef;
|
||||||
if (typeDef != null)
|
if (typeDef != null)
|
||||||
|
@ -72,7 +72,7 @@ namespace de4dot.code {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodDef resolveMethod(IMethod method) {
|
public MethodDef ResolveMethod(IMethod method) {
|
||||||
if (method == null)
|
if (method == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
@ -84,14 +84,14 @@ namespace de4dot.code {
|
||||||
if (mr == null || !mr.IsMethodRef)
|
if (mr == null || !mr.IsMethodRef)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var type = resolveType(mr.DeclaringType);
|
var type = ResolveType(mr.DeclaringType);
|
||||||
if (type == null)
|
if (type == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return type.Resolve(mr) as MethodDef;
|
return type.Resolve(mr) as MethodDef;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FieldDef resolveField(IField field) {
|
public FieldDef ResolveField(IField field) {
|
||||||
if (field == null)
|
if (field == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ namespace de4dot.code {
|
||||||
if (mr == null || !mr.IsFieldRef)
|
if (mr == null || !mr.IsFieldRef)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var type = resolveType(mr.DeclaringType);
|
var type = ResolveType(mr.DeclaringType);
|
||||||
if (type == null)
|
if (type == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
|
|
@ -37,12 +37,12 @@ namespace de4dot.code {
|
||||||
this.dumpedMethods = dumpedMethods;
|
this.dumpedMethods = dumpedMethods;
|
||||||
}
|
}
|
||||||
|
|
||||||
DumpedMethod getDumpedMethod(uint rid) {
|
DumpedMethod GetDumpedMethod(uint rid) {
|
||||||
return dumpedMethods.get(0x06000000 | rid);
|
return dumpedMethods.Get(0x06000000 | rid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RawMethodRow ReadRow(uint rid) {
|
public RawMethodRow ReadRow(uint rid) {
|
||||||
var dm = getDumpedMethod(rid);
|
var dm = GetDumpedMethod(rid);
|
||||||
if (dm == null)
|
if (dm == null)
|
||||||
return null;
|
return null;
|
||||||
return new RawMethodRow(dm.mdRVA, dm.mdImplFlags, dm.mdFlags, dm.mdName, dm.mdSignature, dm.mdParamList);
|
return new RawMethodRow(dm.mdRVA, dm.mdImplFlags, dm.mdFlags, dm.mdName, dm.mdSignature, dm.mdParamList);
|
||||||
|
@ -62,11 +62,11 @@ namespace de4dot.code {
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasMethodBody(uint rid) {
|
public bool HasMethodBody(uint rid) {
|
||||||
return getDumpedMethod(rid) != null;
|
return GetDumpedMethod(rid) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodBody GetMethodBody(uint rid, RVA rva, IList<Parameter> parameters) {
|
public MethodBody GetMethodBody(uint rid, RVA rva, IList<Parameter> parameters) {
|
||||||
var dm = getDumpedMethod(rid);
|
var dm = GetDumpedMethod(rid);
|
||||||
if (dm == null)
|
if (dm == null)
|
||||||
return null;
|
return null;
|
||||||
return MethodBodyReader.Create(module, dm.code, dm.extraSections, parameters, dm.mhFlags, dm.mhMaxStack, dm.mhCodeSize, dm.mhLocalVarSigTok);
|
return MethodBodyReader.Create(module, dm.code, dm.extraSections, parameters, dm.mhFlags, dm.mhMaxStack, dm.mhCodeSize, dm.mhLocalVarSigTok);
|
||||||
|
|
|
@ -21,12 +21,12 @@ using dnlib.DotNet;
|
||||||
|
|
||||||
namespace de4dot.code {
|
namespace de4dot.code {
|
||||||
public interface IDeobfuscatorContext {
|
public interface IDeobfuscatorContext {
|
||||||
void clear();
|
void Clear();
|
||||||
void setData(string name, object data);
|
void SetData(string name, object data);
|
||||||
object getData(string name);
|
object GetData(string name);
|
||||||
void clearData(string name);
|
void ClearData(string name);
|
||||||
TypeDef resolveType(ITypeDefOrRef type);
|
TypeDef ResolveType(ITypeDefOrRef type);
|
||||||
MethodDef resolveMethod(IMethod method);
|
MethodDef ResolveMethod(IMethod method);
|
||||||
FieldDef resolveField(IField field);
|
FieldDef ResolveField(IField field);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,12 +35,12 @@ namespace de4dot.code {
|
||||||
bool RemoveNamespaceWithOneType { get; }
|
bool RemoveNamespaceWithOneType { get; }
|
||||||
bool RenameResourceKeys { get; }
|
bool RenameResourceKeys { get; }
|
||||||
|
|
||||||
void deobfuscateBegin();
|
void DeobfuscateBegin();
|
||||||
void deobfuscate();
|
void Deobfuscate();
|
||||||
void deobfuscateEnd();
|
void DeobfuscateEnd();
|
||||||
void deobfuscateCleanUp();
|
void DeobfuscateCleanUp();
|
||||||
|
|
||||||
void load(IList<IDeobfuscator> deobfuscators);
|
void Load(IList<IDeobfuscator> deobfuscators);
|
||||||
void save();
|
void Save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ namespace de4dot.code {
|
||||||
if (indentLevel == value)
|
if (indentLevel == value)
|
||||||
return;
|
return;
|
||||||
indentLevel = value;
|
indentLevel = value;
|
||||||
initIndentString();
|
InitIndentString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,20 +66,20 @@ namespace de4dot.code {
|
||||||
this.canIgnoreMessages = canIgnoreMessages;
|
this.canIgnoreMessages = canIgnoreMessages;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initIndentString() {
|
void InitIndentString() {
|
||||||
if (indentLevel < 0)
|
if (indentLevel < 0)
|
||||||
indentLevel = 0;
|
indentLevel = 0;
|
||||||
indentString = new string(' ', indentLevel * indentSize);
|
indentString = new string(' ', indentLevel * indentSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void indent() {
|
public void Indent() {
|
||||||
indentLevel++;
|
indentLevel++;
|
||||||
initIndentString();
|
InitIndentString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deIndent() {
|
public void DeIndent() {
|
||||||
indentLevel--;
|
indentLevel--;
|
||||||
initIndentString();
|
InitIndentString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Log(object sender, LoggerEvent loggerEvent, string format, params object[] args) {
|
public void Log(object sender, LoggerEvent loggerEvent, string format, params object[] args) {
|
||||||
|
@ -93,7 +93,7 @@ namespace de4dot.code {
|
||||||
public void Log(bool canIgnore, object sender, LoggerEvent loggerEvent, string format, params object[] args) {
|
public void Log(bool canIgnore, object sender, LoggerEvent loggerEvent, string format, params object[] args) {
|
||||||
if (IgnoresEvent(loggerEvent))
|
if (IgnoresEvent(loggerEvent))
|
||||||
return;
|
return;
|
||||||
if (canIgnore && ignoreMessage(loggerEvent, format, args))
|
if (canIgnore && IgnoreMessage(loggerEvent, format, args))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (loggerEvent) {
|
switch (loggerEvent) {
|
||||||
|
@ -114,7 +114,7 @@ namespace de4dot.code {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ignoreMessage(LoggerEvent loggerEvent, string format, object[] args) {
|
bool IgnoreMessage(LoggerEvent loggerEvent, string format, object[] args) {
|
||||||
if (loggerEvent != LoggerEvent.Error && loggerEvent != LoggerEvent.Warning)
|
if (loggerEvent != LoggerEvent.Error && loggerEvent != LoggerEvent.Warning)
|
||||||
return false;
|
return false;
|
||||||
if (!canIgnoreMessages)
|
if (!canIgnoreMessages)
|
||||||
|
@ -138,7 +138,7 @@ namespace de4dot.code {
|
||||||
return loggerEvent > maxLoggerEvent;
|
return loggerEvent > maxLoggerEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void log(LoggerEvent loggerEvent, string format, params object[] args) {
|
public static void Log(LoggerEvent loggerEvent, string format, params object[] args) {
|
||||||
Instance.Log(null, loggerEvent, format, args);
|
Instance.Log(null, loggerEvent, format, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,13 +41,13 @@ namespace de4dot.code {
|
||||||
Dictionary<Instruction, ExInfo> exInfos = new Dictionary<Instruction, ExInfo>();
|
Dictionary<Instruction, ExInfo> exInfos = new Dictionary<Instruction, ExInfo>();
|
||||||
ExInfo lastExInfo;
|
ExInfo lastExInfo;
|
||||||
|
|
||||||
public void print(LoggerEvent loggerEvent, IList<Instruction> allInstructions, IList<ExceptionHandler> allExceptionHandlers) {
|
public void Print(LoggerEvent loggerEvent, IList<Instruction> allInstructions, IList<ExceptionHandler> allExceptionHandlers) {
|
||||||
try {
|
try {
|
||||||
this.loggerEvent = loggerEvent;
|
this.loggerEvent = loggerEvent;
|
||||||
this.allInstructions = allInstructions;
|
this.allInstructions = allInstructions;
|
||||||
this.allExceptionHandlers = allExceptionHandlers;
|
this.allExceptionHandlers = allExceptionHandlers;
|
||||||
lastExInfo = new ExInfo();
|
lastExInfo = new ExInfo();
|
||||||
print();
|
Print();
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
this.allInstructions = null;
|
this.allInstructions = null;
|
||||||
|
@ -59,27 +59,27 @@ namespace de4dot.code {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void initTargets() {
|
void InitTargets() {
|
||||||
foreach (var instr in allInstructions) {
|
foreach (var instr in allInstructions) {
|
||||||
switch (instr.OpCode.OperandType) {
|
switch (instr.OpCode.OperandType) {
|
||||||
case OperandType.ShortInlineBrTarget:
|
case OperandType.ShortInlineBrTarget:
|
||||||
case OperandType.InlineBrTarget:
|
case OperandType.InlineBrTarget:
|
||||||
setTarget(instr.Operand as Instruction);
|
SetTarget(instr.Operand as Instruction);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OperandType.InlineSwitch:
|
case OperandType.InlineSwitch:
|
||||||
foreach (var targetInstr in (Instruction[])instr.Operand)
|
foreach (var targetInstr in (Instruction[])instr.Operand)
|
||||||
setTarget(targetInstr);
|
SetTarget(targetInstr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var ex in allExceptionHandlers) {
|
foreach (var ex in allExceptionHandlers) {
|
||||||
setTarget(ex.TryStart);
|
SetTarget(ex.TryStart);
|
||||||
setTarget(ex.TryEnd);
|
SetTarget(ex.TryEnd);
|
||||||
setTarget(ex.FilterStart);
|
SetTarget(ex.FilterStart);
|
||||||
setTarget(ex.HandlerStart);
|
SetTarget(ex.HandlerStart);
|
||||||
setTarget(ex.HandlerEnd);
|
SetTarget(ex.HandlerEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
var sortedTargets = new List<Instruction>(targets.Keys);
|
var sortedTargets = new List<Instruction>(targets.Keys);
|
||||||
|
@ -88,27 +88,27 @@ namespace de4dot.code {
|
||||||
labels[sortedTargets[i]] = string.Format("label_{0}", i);
|
labels[sortedTargets[i]] = string.Format("label_{0}", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setTarget(Instruction instr) {
|
void SetTarget(Instruction instr) {
|
||||||
if (instr != null)
|
if (instr != null)
|
||||||
targets[instr] = true;
|
targets[instr] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initExHandlers() {
|
void InitExHandlers() {
|
||||||
foreach (var ex in allExceptionHandlers) {
|
foreach (var ex in allExceptionHandlers) {
|
||||||
if (ex.TryStart != null) {
|
if (ex.TryStart != null) {
|
||||||
getExInfo(ex.TryStart).tryStarts.Add(ex);
|
GetExInfo(ex.TryStart).tryStarts.Add(ex);
|
||||||
getExInfo(ex.TryEnd).tryEnds.Add(ex);
|
GetExInfo(ex.TryEnd).tryEnds.Add(ex);
|
||||||
}
|
}
|
||||||
if (ex.FilterStart != null)
|
if (ex.FilterStart != null)
|
||||||
getExInfo(ex.FilterStart).filterStarts.Add(ex);
|
GetExInfo(ex.FilterStart).filterStarts.Add(ex);
|
||||||
if (ex.HandlerStart != null) {
|
if (ex.HandlerStart != null) {
|
||||||
getExInfo(ex.HandlerStart).handlerStarts.Add(ex);
|
GetExInfo(ex.HandlerStart).handlerStarts.Add(ex);
|
||||||
getExInfo(ex.HandlerEnd).handlerEnds.Add(ex);
|
GetExInfo(ex.HandlerEnd).handlerEnds.Add(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ExInfo getExInfo(Instruction instruction) {
|
ExInfo GetExInfo(Instruction instruction) {
|
||||||
if (instruction == null)
|
if (instruction == null)
|
||||||
return lastExInfo;
|
return lastExInfo;
|
||||||
ExInfo exInfo;
|
ExInfo exInfo;
|
||||||
|
@ -117,49 +117,49 @@ namespace de4dot.code {
|
||||||
return exInfo;
|
return exInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
void print() {
|
void Print() {
|
||||||
initTargets();
|
InitTargets();
|
||||||
initExHandlers();
|
InitExHandlers();
|
||||||
|
|
||||||
Logger.Instance.indent();
|
Logger.Instance.Indent();
|
||||||
foreach (var instr in allInstructions) {
|
foreach (var instr in allInstructions) {
|
||||||
if (targets.ContainsKey(instr)) {
|
if (targets.ContainsKey(instr)) {
|
||||||
Logger.Instance.deIndent();
|
Logger.Instance.DeIndent();
|
||||||
Logger.log(loggerEvent, "{0}:", getLabel(instr));
|
Logger.Log(loggerEvent, "{0}:", GetLabel(instr));
|
||||||
Logger.Instance.indent();
|
Logger.Instance.Indent();
|
||||||
}
|
}
|
||||||
ExInfo exInfo;
|
ExInfo exInfo;
|
||||||
if (exInfos.TryGetValue(instr, out exInfo))
|
if (exInfos.TryGetValue(instr, out exInfo))
|
||||||
printExInfo(exInfo);
|
PrintExInfo(exInfo);
|
||||||
var instrString = instr.OpCode.Name;
|
var instrString = instr.OpCode.Name;
|
||||||
var operandString = getOperandString(instr);
|
var operandString = GetOperandString(instr);
|
||||||
var memberRef = instr.Operand as ITokenOperand;
|
var memberRef = instr.Operand as ITokenOperand;
|
||||||
if (operandString == "")
|
if (operandString == "")
|
||||||
Logger.log(loggerEvent, "{0}", instrString);
|
Logger.Log(loggerEvent, "{0}", instrString);
|
||||||
else if (memberRef != null)
|
else if (memberRef != null)
|
||||||
Logger.log(loggerEvent, "{0,-9} {1} // {2:X8}", instrString, Utils.removeNewlines(operandString), memberRef.MDToken.ToUInt32());
|
Logger.Log(loggerEvent, "{0,-9} {1} // {2:X8}", instrString, Utils.RemoveNewlines(operandString), memberRef.MDToken.ToUInt32());
|
||||||
else
|
else
|
||||||
Logger.log(loggerEvent, "{0,-9} {1}", instrString, Utils.removeNewlines(operandString));
|
Logger.Log(loggerEvent, "{0,-9} {1}", instrString, Utils.RemoveNewlines(operandString));
|
||||||
}
|
}
|
||||||
printExInfo(lastExInfo);
|
PrintExInfo(lastExInfo);
|
||||||
Logger.Instance.deIndent();
|
Logger.Instance.DeIndent();
|
||||||
}
|
}
|
||||||
|
|
||||||
string getOperandString(Instruction instr) {
|
string GetOperandString(Instruction instr) {
|
||||||
if (instr.Operand is Instruction)
|
if (instr.Operand is Instruction)
|
||||||
return getLabel((Instruction)instr.Operand);
|
return GetLabel((Instruction)instr.Operand);
|
||||||
else if (instr.Operand is Instruction[]) {
|
else if (instr.Operand is Instruction[]) {
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
var targets = (Instruction[])instr.Operand;
|
var targets = (Instruction[])instr.Operand;
|
||||||
for (int i = 0; i < targets.Length; i++) {
|
for (int i = 0; i < targets.Length; i++) {
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
sb.Append(',');
|
sb.Append(',');
|
||||||
sb.Append(getLabel(targets[i]));
|
sb.Append(GetLabel(targets[i]));
|
||||||
}
|
}
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
else if (instr.Operand is string)
|
else if (instr.Operand is string)
|
||||||
return Utils.toCsharpString((string)instr.Operand);
|
return Utils.ToCsharpString((string)instr.Operand);
|
||||||
else if (instr.Operand is Parameter) {
|
else if (instr.Operand is Parameter) {
|
||||||
var arg = (Parameter)instr.Operand;
|
var arg = (Parameter)instr.Operand;
|
||||||
var s = InstructionPrinter.GetOperandString(instr);
|
var s = InstructionPrinter.GetOperandString(instr);
|
||||||
|
@ -171,36 +171,36 @@ namespace de4dot.code {
|
||||||
return InstructionPrinter.GetOperandString(instr);
|
return InstructionPrinter.GetOperandString(instr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void printExInfo(ExInfo exInfo) {
|
void PrintExInfo(ExInfo exInfo) {
|
||||||
Logger.Instance.deIndent();
|
Logger.Instance.DeIndent();
|
||||||
foreach (var ex in exInfo.tryStarts)
|
foreach (var ex in exInfo.tryStarts)
|
||||||
Logger.log(loggerEvent, "// try start: {0}", getExceptionString(ex));
|
Logger.Log(loggerEvent, "// try start: {0}", GetExceptionString(ex));
|
||||||
foreach (var ex in exInfo.tryEnds)
|
foreach (var ex in exInfo.tryEnds)
|
||||||
Logger.log(loggerEvent, "// try end: {0}", getExceptionString(ex));
|
Logger.Log(loggerEvent, "// try end: {0}", GetExceptionString(ex));
|
||||||
foreach (var ex in exInfo.filterStarts)
|
foreach (var ex in exInfo.filterStarts)
|
||||||
Logger.log(loggerEvent, "// filter start: {0}", getExceptionString(ex));
|
Logger.Log(loggerEvent, "// filter start: {0}", GetExceptionString(ex));
|
||||||
foreach (var ex in exInfo.handlerStarts)
|
foreach (var ex in exInfo.handlerStarts)
|
||||||
Logger.log(loggerEvent, "// handler start: {0}", getExceptionString(ex));
|
Logger.Log(loggerEvent, "// handler start: {0}", GetExceptionString(ex));
|
||||||
foreach (var ex in exInfo.handlerEnds)
|
foreach (var ex in exInfo.handlerEnds)
|
||||||
Logger.log(loggerEvent, "// handler end: {0}", getExceptionString(ex));
|
Logger.Log(loggerEvent, "// handler end: {0}", GetExceptionString(ex));
|
||||||
Logger.Instance.indent();
|
Logger.Instance.Indent();
|
||||||
}
|
}
|
||||||
|
|
||||||
string getExceptionString(ExceptionHandler ex) {
|
string GetExceptionString(ExceptionHandler ex) {
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
if (ex.TryStart != null)
|
if (ex.TryStart != null)
|
||||||
sb.Append(string.Format("TRY: {0}-{1}", getLabel(ex.TryStart), getLabel(ex.TryEnd)));
|
sb.Append(string.Format("TRY: {0}-{1}", GetLabel(ex.TryStart), GetLabel(ex.TryEnd)));
|
||||||
if (ex.FilterStart != null)
|
if (ex.FilterStart != null)
|
||||||
sb.Append(string.Format(", FILTER: {0}", getLabel(ex.FilterStart)));
|
sb.Append(string.Format(", FILTER: {0}", GetLabel(ex.FilterStart)));
|
||||||
if (ex.HandlerStart != null)
|
if (ex.HandlerStart != null)
|
||||||
sb.Append(string.Format(", HANDLER: {0}-{1}", getLabel(ex.HandlerStart), getLabel(ex.HandlerEnd)));
|
sb.Append(string.Format(", HANDLER: {0}-{1}", GetLabel(ex.HandlerStart), GetLabel(ex.HandlerEnd)));
|
||||||
sb.Append(string.Format(", TYPE: {0}", ex.HandlerType));
|
sb.Append(string.Format(", TYPE: {0}", ex.HandlerType));
|
||||||
if (ex.CatchType != null)
|
if (ex.CatchType != null)
|
||||||
sb.Append(string.Format(", CATCH: {0}", ex.CatchType));
|
sb.Append(string.Format(", CATCH: {0}", ex.CatchType));
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
string getLabel(Instruction instr) {
|
string GetLabel(Instruction instr) {
|
||||||
if (instr == null)
|
if (instr == null)
|
||||||
return "<end>";
|
return "<end>";
|
||||||
return labels[instr];
|
return labels[instr];
|
||||||
|
|
|
@ -35,24 +35,24 @@ namespace de4dot.code {
|
||||||
object value;
|
object value;
|
||||||
bool unknownValue = false;
|
bool unknownValue = false;
|
||||||
|
|
||||||
public bool isValid() {
|
public bool IsValid() {
|
||||||
return !unknownValue && writes == 1;
|
return !unknownValue && writes == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Value {
|
public object Value {
|
||||||
get {
|
get {
|
||||||
if (!isValid())
|
if (!IsValid())
|
||||||
throw new ApplicationException("Unknown variable value");
|
throw new ApplicationException("Unknown variable value");
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
set { this.value = value; }
|
set { this.value = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addWrite() {
|
public void AddWrite() {
|
||||||
writes++;
|
writes++;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUnknown() {
|
public void SetUnknown() {
|
||||||
unknownValue = true;
|
unknownValue = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,10 +60,10 @@ namespace de4dot.code {
|
||||||
public VariableValues(IList<Local> locals, IList<Block> allBlocks) {
|
public VariableValues(IList<Local> locals, IList<Block> allBlocks) {
|
||||||
this.locals = locals;
|
this.locals = locals;
|
||||||
this.allBlocks = allBlocks;
|
this.allBlocks = allBlocks;
|
||||||
init();
|
Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void init() {
|
void Initialize() {
|
||||||
foreach (var variable in locals)
|
foreach (var variable in locals)
|
||||||
variableToValue[variable] = new Variable();
|
variableToValue[variable] = new Variable();
|
||||||
|
|
||||||
|
@ -78,12 +78,12 @@ namespace de4dot.code {
|
||||||
case Code.Stloc_1:
|
case Code.Stloc_1:
|
||||||
case Code.Stloc_2:
|
case Code.Stloc_2:
|
||||||
case Code.Stloc_3:
|
case Code.Stloc_3:
|
||||||
var variable = Instr.getLocalVar(locals, instr);
|
var variable = Instr.GetLocalVar(locals, instr);
|
||||||
var val = variableToValue[variable];
|
var val = variableToValue[variable];
|
||||||
val.addWrite();
|
val.AddWrite();
|
||||||
object obj;
|
object obj;
|
||||||
if (!getValue(block, i, out obj))
|
if (!GetValue(block, i, out obj))
|
||||||
val.setUnknown();
|
val.SetUnknown();
|
||||||
val.Value = obj;
|
val.Value = obj;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ namespace de4dot.code {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool getValue(Block block, int index, out object obj) {
|
bool GetValue(Block block, int index, out object obj) {
|
||||||
while (true) {
|
while (true) {
|
||||||
if (index <= 0) {
|
if (index <= 0) {
|
||||||
obj = null;
|
obj = null;
|
||||||
|
@ -135,7 +135,7 @@ namespace de4dot.code {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Variable getValue(Local variable) {
|
public Variable GetValue(Local variable) {
|
||||||
return variableToValue[variable];
|
return variableToValue[variable];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -165,7 +165,7 @@ namespace de4dot.code {
|
||||||
this.callEndIndex = callEndIndex;
|
this.callEndIndex = callEndIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IMethod getMethodRef() {
|
public IMethod GetMethodRef() {
|
||||||
return (IMethod)block.Instructions[callEndIndex].Operand;
|
return (IMethod)block.Instructions[callEndIndex].Operand;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,18 +180,18 @@ namespace de4dot.code {
|
||||||
get { return theMethod; }
|
get { return theMethod; }
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void inlineAllCalls();
|
protected abstract void InlineAllCalls();
|
||||||
|
|
||||||
// Returns null if method is not a method we should inline
|
// Returns null if method is not a method we should inline
|
||||||
protected abstract CallResult createCallResult(IMethod method, MethodSpec gim, Block block, int callInstrIndex);
|
protected abstract CallResult CreateCallResult(IMethod method, MethodSpec gim, Block block, int callInstrIndex);
|
||||||
|
|
||||||
public int decrypt(Blocks blocks) {
|
public int Decrypt(Blocks blocks) {
|
||||||
if (!HasHandlers)
|
if (!HasHandlers)
|
||||||
return 0;
|
return 0;
|
||||||
return decrypt(blocks.Method, blocks.MethodBlocks.getAllBlocks());
|
return Decrypt(blocks.Method, blocks.MethodBlocks.GetAllBlocks());
|
||||||
}
|
}
|
||||||
|
|
||||||
public int decrypt(MethodDef method, List<Block> allBlocks) {
|
public int Decrypt(MethodDef method, List<Block> allBlocks) {
|
||||||
if (!HasHandlers)
|
if (!HasHandlers)
|
||||||
return 0;
|
return 0;
|
||||||
try {
|
try {
|
||||||
|
@ -199,9 +199,9 @@ namespace de4dot.code {
|
||||||
callResults = new List<CallResult>();
|
callResults = new List<CallResult>();
|
||||||
this.allBlocks = allBlocks;
|
this.allBlocks = allBlocks;
|
||||||
|
|
||||||
findAllCallResults();
|
FindAllCallResults();
|
||||||
inlineAllCalls();
|
InlineAllCalls();
|
||||||
inlineReturnValues();
|
InlineReturnValues();
|
||||||
return callResults.Count;
|
return callResults.Count;
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
|
@ -216,11 +216,11 @@ namespace de4dot.code {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool getLocalVariableValue(Local variable, out object value) {
|
bool GetLocalVariableValue(Local variable, out object value) {
|
||||||
if (variableValues == null)
|
if (variableValues == null)
|
||||||
variableValues = new VariableValues(theMethod.Body.Variables, allBlocks);
|
variableValues = new VariableValues(theMethod.Body.Variables, allBlocks);
|
||||||
var val = variableValues.getValue(variable);
|
var val = variableValues.GetValue(variable);
|
||||||
if (!val.isValid()) {
|
if (!val.IsValid()) {
|
||||||
value = null;
|
value = null;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -228,12 +228,12 @@ namespace de4dot.code {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void findAllCallResults() {
|
void FindAllCallResults() {
|
||||||
foreach (var block in allBlocks)
|
foreach (var block in allBlocks)
|
||||||
findCallResults(block);
|
FindCallResults(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
void findCallResults(Block block) {
|
void FindCallResults(Block block) {
|
||||||
for (int i = 0; i < block.Instructions.Count; i++) {
|
for (int i = 0; i < block.Instructions.Count; i++) {
|
||||||
var instr = block.Instructions[i];
|
var instr = block.Instructions[i];
|
||||||
if (instr.OpCode != OpCodes.Call)
|
if (instr.OpCode != OpCodes.Call)
|
||||||
|
@ -246,31 +246,31 @@ namespace de4dot.code {
|
||||||
var gim = method as MethodSpec;
|
var gim = method as MethodSpec;
|
||||||
if (gim != null)
|
if (gim != null)
|
||||||
elementMethod = gim.Method;
|
elementMethod = gim.Method;
|
||||||
var callResult = createCallResult(elementMethod, gim, block, i);
|
var callResult = CreateCallResult(elementMethod, gim, block, i);
|
||||||
if (callResult == null)
|
if (callResult == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (findArgs(callResult))
|
if (FindArgs(callResult))
|
||||||
callResults.Add(callResult);
|
callResults.Add(callResult);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool findArgs(CallResult callResult) {
|
bool FindArgs(CallResult callResult) {
|
||||||
var block = callResult.block;
|
var block = callResult.block;
|
||||||
var method = callResult.getMethodRef();
|
var method = callResult.GetMethodRef();
|
||||||
var methodArgs = DotNetUtils.getArgs(method);
|
var methodArgs = DotNetUtils.GetArgs(method);
|
||||||
int numArgs = methodArgs.Count;
|
int numArgs = methodArgs.Count;
|
||||||
var args = new object[numArgs];
|
var args = new object[numArgs];
|
||||||
|
|
||||||
int instrIndex = callResult.callEndIndex - 1;
|
int instrIndex = callResult.callEndIndex - 1;
|
||||||
for (int i = numArgs - 1; i >= 0; i--) {
|
for (int i = numArgs - 1; i >= 0; i--) {
|
||||||
object arg = null;
|
object arg = null;
|
||||||
if (!getArg(method, block, ref arg, ref instrIndex))
|
if (!GetArg(method, block, ref arg, ref instrIndex))
|
||||||
return false;
|
return false;
|
||||||
if (arg is int)
|
if (arg is int)
|
||||||
arg = fixIntArg(methodArgs[i], (int)arg);
|
arg = FixIntArg(methodArgs[i], (int)arg);
|
||||||
else if (arg is long)
|
else if (arg is long)
|
||||||
arg = fixIntArg(methodArgs[i], (long)arg);
|
arg = FixIntArg(methodArgs[i], (long)arg);
|
||||||
args[i] = arg;
|
args[i] = arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,7 +279,7 @@ namespace de4dot.code {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
object fixIntArg(TypeSig type, long value) {
|
object FixIntArg(TypeSig type, long value) {
|
||||||
switch (type.ElementType) {
|
switch (type.ElementType) {
|
||||||
case ElementType.Boolean: return value != 0;
|
case ElementType.Boolean: return value != 0;
|
||||||
case ElementType.Char: return (char)value;
|
case ElementType.Char: return (char)value;
|
||||||
|
@ -295,14 +295,14 @@ namespace de4dot.code {
|
||||||
throw new ApplicationException(string.Format("Wrong type {0}", type));
|
throw new ApplicationException(string.Format("Wrong type {0}", type));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool getArg(IMethod method, Block block, ref object arg, ref int instrIndex) {
|
bool GetArg(IMethod method, Block block, ref object arg, ref int instrIndex) {
|
||||||
while (true) {
|
while (true) {
|
||||||
if (instrIndex < 0) {
|
if (instrIndex < 0) {
|
||||||
// We're here if there were no cflow deobfuscation, or if there are two or
|
// We're here if there were no cflow deobfuscation, or if there are two or
|
||||||
// more blocks branching to the decrypter method, or the two blocks can't be
|
// more blocks branching to the decrypter method, or the two blocks can't be
|
||||||
// merged because one is outside the exception handler (eg. buggy obfuscator).
|
// merged because one is outside the exception handler (eg. buggy obfuscator).
|
||||||
Logger.w("Could not find all arguments to method {0} ({1:X8})",
|
Logger.w("Could not find all arguments to method {0} ({1:X8})",
|
||||||
Utils.removeNewlines(method),
|
Utils.RemoveNewlines(method),
|
||||||
method.MDToken.ToInt32());
|
method.MDToken.ToInt32());
|
||||||
errors++;
|
errors++;
|
||||||
return false;
|
return false;
|
||||||
|
@ -342,7 +342,7 @@ namespace de4dot.code {
|
||||||
case Code.Ldloc_1:
|
case Code.Ldloc_1:
|
||||||
case Code.Ldloc_2:
|
case Code.Ldloc_2:
|
||||||
case Code.Ldloc_3:
|
case Code.Ldloc_3:
|
||||||
getLocalVariableValue(instr.Instruction.GetLocal(theMethod.Body.Variables), out arg);
|
GetLocalVariableValue(instr.Instruction.GetLocal(theMethod.Body.Variables), out arg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Code.Ldfld:
|
case Code.Ldfld:
|
||||||
|
@ -355,7 +355,7 @@ namespace de4dot.code {
|
||||||
instr.Instruction.CalculateStackUsage(false, out pushes, out pops);
|
instr.Instruction.CalculateStackUsage(false, out pushes, out pops);
|
||||||
if (!useUnknownArgs || pushes != 1) {
|
if (!useUnknownArgs || pushes != 1) {
|
||||||
Logger.w("Could not find all arguments to method {0} ({1:X8}), instr: {2}",
|
Logger.w("Could not find all arguments to method {0} ({1:X8}), instr: {2}",
|
||||||
Utils.removeNewlines(method),
|
Utils.RemoveNewlines(method),
|
||||||
method.MDToken.ToInt32(),
|
method.MDToken.ToInt32(),
|
||||||
instr);
|
instr);
|
||||||
errors++;
|
errors++;
|
||||||
|
@ -363,7 +363,7 @@ namespace de4dot.code {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < pops; i++) {
|
for (int i = 0; i < pops; i++) {
|
||||||
if (!getArg(method, block, ref arg, ref instrIndex))
|
if (!GetArg(method, block, ref arg, ref instrIndex))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
arg = null;
|
arg = null;
|
||||||
|
@ -375,8 +375,8 @@ namespace de4dot.code {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void inlineReturnValues() {
|
void InlineReturnValues() {
|
||||||
callResults = removeNulls(callResults);
|
callResults = RemoveNulls(callResults);
|
||||||
callResults.Sort((a, b) => {
|
callResults.Sort((a, b) => {
|
||||||
int i1 = allBlocks.FindIndex((x) => a.block == x);
|
int i1 = allBlocks.FindIndex((x) => a.block == x);
|
||||||
int i2 = allBlocks.FindIndex((x) => b.block == x);
|
int i2 = allBlocks.FindIndex((x) => b.block == x);
|
||||||
|
@ -386,10 +386,10 @@ namespace de4dot.code {
|
||||||
return a.callStartIndex.CompareTo(b.callStartIndex);
|
return a.callStartIndex.CompareTo(b.callStartIndex);
|
||||||
});
|
});
|
||||||
callResults.Reverse();
|
callResults.Reverse();
|
||||||
inlineReturnValues(callResults);
|
InlineReturnValues(callResults);
|
||||||
}
|
}
|
||||||
|
|
||||||
static List<CallResult> removeNulls(List<CallResult> inList) {
|
static List<CallResult> RemoveNulls(List<CallResult> inList) {
|
||||||
var outList = new List<CallResult>(inList.Count);
|
var outList = new List<CallResult>(inList.Count);
|
||||||
foreach (var callResult in inList) {
|
foreach (var callResult in inList) {
|
||||||
if (callResult.returnValue != null)
|
if (callResult.returnValue != null)
|
||||||
|
@ -398,6 +398,6 @@ namespace de4dot.code {
|
||||||
return outList;
|
return outList;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void inlineReturnValues(IList<CallResult> callResults);
|
protected abstract void InlineReturnValues(IList<CallResult> callResults);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ namespace de4dot.code {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the regex matches. Use MatchValue to get result.
|
// Returns true if the regex matches. Use MatchValue to get result.
|
||||||
public bool isMatch(string s) {
|
public bool IsMatch(string s) {
|
||||||
return regex.IsMatch(s);
|
return regex.IsMatch(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,10 +60,10 @@ namespace de4dot.code {
|
||||||
}
|
}
|
||||||
|
|
||||||
public NameRegexes(string regex) {
|
public NameRegexes(string regex) {
|
||||||
set(regex);
|
Set(regex);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void set(string regexesString) {
|
public void Set(string regexesString) {
|
||||||
regexes = new List<NameRegex>();
|
regexes = new List<NameRegex>();
|
||||||
if (regexesString != "") {
|
if (regexesString != "") {
|
||||||
foreach (var regex in regexesString.Split(new char[] { regexSeparatorChar }))
|
foreach (var regex in regexesString.Split(new char[] { regexSeparatorChar }))
|
||||||
|
@ -71,9 +71,9 @@ namespace de4dot.code {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isMatch(string s) {
|
public bool IsMatch(string s) {
|
||||||
foreach (var regex in regexes) {
|
foreach (var regex in regexes) {
|
||||||
if (regex.isMatch(s))
|
if (regex.IsMatch(s))
|
||||||
return regex.MatchValue;
|
return regex.MatchValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,27 +55,27 @@ namespace de4dot.code {
|
||||||
|
|
||||||
public SavedMethodBody(MethodDef method) {
|
public SavedMethodBody(MethodDef method) {
|
||||||
this.method = method;
|
this.method = method;
|
||||||
DotNetUtils.copyBody(method, out instructions, out exceptionHandlers);
|
DotNetUtils.CopyBody(method, out instructions, out exceptionHandlers);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void restore() {
|
public void Restore() {
|
||||||
DotNetUtils.restoreBody(method, instructions, exceptionHandlers);
|
DotNetUtils.RestoreBody(method, instructions, exceptionHandlers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void save(MethodDef method) {
|
public void Save(MethodDef method) {
|
||||||
if (isSaved(method))
|
if (IsSaved(method))
|
||||||
return;
|
return;
|
||||||
savedMethodBodies[method] = new SavedMethodBody(method);
|
savedMethodBodies[method] = new SavedMethodBody(method);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void restoreAll() {
|
public void RestoreAll() {
|
||||||
foreach (var smb in savedMethodBodies.Values)
|
foreach (var smb in savedMethodBodies.Values)
|
||||||
smb.restore();
|
smb.Restore();
|
||||||
savedMethodBodies.Clear();
|
savedMethodBodies.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isSaved(MethodDef method) {
|
public bool IsSaved(MethodDef method) {
|
||||||
return savedMethodBodies.ContainsKey(method);
|
return savedMethodBodies.ContainsKey(method);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,17 +139,17 @@ namespace de4dot.code {
|
||||||
this.assemblyClientFactory = assemblyClientFactory;
|
this.assemblyClientFactory = assemblyClientFactory;
|
||||||
this.options = options;
|
this.options = options;
|
||||||
userStringDecrypterMethods = options.StringDecrypterMethods.Count > 0;
|
userStringDecrypterMethods = options.StringDecrypterMethods.Count > 0;
|
||||||
options.Filename = Utils.getFullPath(options.Filename);
|
options.Filename = Utils.GetFullPath(options.Filename);
|
||||||
assemblyModule = new AssemblyModule(options.Filename, moduleContext);
|
assemblyModule = new AssemblyModule(options.Filename, moduleContext);
|
||||||
|
|
||||||
if (options.NewFilename == null)
|
if (options.NewFilename == null)
|
||||||
options.NewFilename = getDefaultNewFilename();
|
options.NewFilename = GetDefaultNewFilename();
|
||||||
|
|
||||||
if (string.Equals(options.Filename, options.NewFilename, StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(options.Filename, options.NewFilename, StringComparison.OrdinalIgnoreCase))
|
||||||
throw new UserException(string.Format("filename is same as new filename! ({0})", options.Filename));
|
throw new UserException(string.Format("filename is same as new filename! ({0})", options.Filename));
|
||||||
}
|
}
|
||||||
|
|
||||||
string getDefaultNewFilename() {
|
string GetDefaultNewFilename() {
|
||||||
int dotIndex = options.Filename.LastIndexOf('.');
|
int dotIndex = options.Filename.LastIndexOf('.');
|
||||||
string noExt, ext;
|
string noExt, ext;
|
||||||
if (dotIndex != -1) {
|
if (dotIndex != -1) {
|
||||||
|
@ -163,15 +163,15 @@ namespace de4dot.code {
|
||||||
return noExt + "-cleaned" + ext;
|
return noExt + "-cleaned" + ext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void load(IList<IDeobfuscator> deobfuscators) {
|
public void Load(IList<IDeobfuscator> deobfuscators) {
|
||||||
try {
|
try {
|
||||||
loadModule(deobfuscators);
|
LoadModule(deobfuscators);
|
||||||
TheAssemblyResolver.Instance.addSearchDirectory(Utils.getDirName(Filename));
|
TheAssemblyResolver.Instance.AddSearchDirectory(Utils.GetDirName(Filename));
|
||||||
TheAssemblyResolver.Instance.addSearchDirectory(Utils.getDirName(NewFilename));
|
TheAssemblyResolver.Instance.AddSearchDirectory(Utils.GetDirName(NewFilename));
|
||||||
detectObfuscator(deobfuscators);
|
DetectObfuscator(deobfuscators);
|
||||||
if (deob == null)
|
if (deob == null)
|
||||||
throw new ApplicationException("Could not detect obfuscator!");
|
throw new ApplicationException("Could not detect obfuscator!");
|
||||||
initializeDeobfuscator();
|
InitializeDeobfuscator();
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
foreach (var d in deobfuscators) {
|
foreach (var d in deobfuscators) {
|
||||||
|
@ -181,13 +181,13 @@ namespace de4dot.code {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadModule(IEnumerable<IDeobfuscator> deobfuscators) {
|
void LoadModule(IEnumerable<IDeobfuscator> deobfuscators) {
|
||||||
ModuleDefMD oldModule = module;
|
ModuleDefMD oldModule = module;
|
||||||
try {
|
try {
|
||||||
module = assemblyModule.load();
|
module = assemblyModule.Load();
|
||||||
}
|
}
|
||||||
catch (BadImageFormatException) {
|
catch (BadImageFormatException) {
|
||||||
if (!unpackNativeImage(deobfuscators))
|
if (!UnpackNativeImage(deobfuscators))
|
||||||
throw new BadImageFormatException();
|
throw new BadImageFormatException();
|
||||||
Logger.v("Unpacked native file");
|
Logger.v("Unpacked native file");
|
||||||
}
|
}
|
||||||
|
@ -197,12 +197,12 @@ namespace de4dot.code {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool unpackNativeImage(IEnumerable<IDeobfuscator> deobfuscators) {
|
bool UnpackNativeImage(IEnumerable<IDeobfuscator> deobfuscators) {
|
||||||
using (var peImage = new PEImage(Filename)) {
|
using (var peImage = new PEImage(Filename)) {
|
||||||
foreach (var deob in deobfuscators) {
|
foreach (var deob in deobfuscators) {
|
||||||
byte[] unpackedData = null;
|
byte[] unpackedData = null;
|
||||||
try {
|
try {
|
||||||
unpackedData = deob.unpackNativeFile(peImage);
|
unpackedData = deob.UnpackNativeFile(peImage);
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
}
|
}
|
||||||
|
@ -211,7 +211,7 @@ namespace de4dot.code {
|
||||||
|
|
||||||
var oldModule = module;
|
var oldModule = module;
|
||||||
try {
|
try {
|
||||||
module = assemblyModule.load(unpackedData);
|
module = assemblyModule.Load(unpackedData);
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
Logger.w("Could not load unpacked data. File: {0}, deobfuscator: {0}", peImage.FileName ?? "(unknown filename)", deob.TypeLong);
|
Logger.w("Could not load unpacked data. File: {0}, deobfuscator: {0}", peImage.FileName ?? "(unknown filename)", deob.TypeLong);
|
||||||
|
@ -229,16 +229,16 @@ namespace de4dot.code {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initializeDeobfuscator() {
|
void InitializeDeobfuscator() {
|
||||||
if (options.StringDecrypterType == DecrypterType.Default)
|
if (options.StringDecrypterType == DecrypterType.Default)
|
||||||
options.StringDecrypterType = deob.DefaultDecrypterType;
|
options.StringDecrypterType = deob.DefaultDecrypterType;
|
||||||
if (options.StringDecrypterType == DecrypterType.Default)
|
if (options.StringDecrypterType == DecrypterType.Default)
|
||||||
options.StringDecrypterType = DecrypterType.Static;
|
options.StringDecrypterType = DecrypterType.Static;
|
||||||
|
|
||||||
deob.Operations = createOperations();
|
deob.Operations = CreateOperations();
|
||||||
}
|
}
|
||||||
|
|
||||||
IOperations createOperations() {
|
IOperations CreateOperations() {
|
||||||
var op = new Operations();
|
var op = new Operations();
|
||||||
|
|
||||||
switch (options.StringDecrypterType) {
|
switch (options.StringDecrypterType) {
|
||||||
|
@ -260,7 +260,7 @@ namespace de4dot.code {
|
||||||
return op;
|
return op;
|
||||||
}
|
}
|
||||||
|
|
||||||
void detectObfuscator(IEnumerable<IDeobfuscator> deobfuscators) {
|
void DetectObfuscator(IEnumerable<IDeobfuscator> deobfuscators) {
|
||||||
|
|
||||||
// The deobfuscators may call methods to deobfuscate control flow and decrypt
|
// The deobfuscators may call methods to deobfuscate control flow and decrypt
|
||||||
// strings (statically) in order to detect the obfuscator.
|
// strings (statically) in order to detect the obfuscator.
|
||||||
|
@ -269,14 +269,14 @@ namespace de4dot.code {
|
||||||
|
|
||||||
// It's not null if it unpacked a native file
|
// It's not null if it unpacked a native file
|
||||||
if (this.deob != null) {
|
if (this.deob != null) {
|
||||||
deob.init(module);
|
deob.Initialize(module);
|
||||||
deob.DeobfuscatedFile = this;
|
deob.DeobfuscatedFile = this;
|
||||||
deob.detect();
|
deob.Detect();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var deob in deobfuscators) {
|
foreach (var deob in deobfuscators) {
|
||||||
deob.init(module);
|
deob.Initialize(module);
|
||||||
deob.DeobfuscatedFile = this;
|
deob.DeobfuscatedFile = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,16 +284,16 @@ namespace de4dot.code {
|
||||||
foreach (var deob in deobfuscators) {
|
foreach (var deob in deobfuscators) {
|
||||||
if (string.Equals(options.ForcedObfuscatorType, deob.Type, StringComparison.OrdinalIgnoreCase)) {
|
if (string.Equals(options.ForcedObfuscatorType, deob.Type, StringComparison.OrdinalIgnoreCase)) {
|
||||||
this.deob = deob;
|
this.deob = deob;
|
||||||
deob.detect();
|
deob.Detect();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
this.deob = detectObfuscator2(deobfuscators);
|
this.deob = DetectObfuscator2(deobfuscators);
|
||||||
}
|
}
|
||||||
|
|
||||||
IDeobfuscator detectObfuscator2(IEnumerable<IDeobfuscator> deobfuscators) {
|
IDeobfuscator DetectObfuscator2(IEnumerable<IDeobfuscator> deobfuscators) {
|
||||||
var allDetected = new List<IDeobfuscator>();
|
var allDetected = new List<IDeobfuscator>();
|
||||||
IDeobfuscator detected = null;
|
IDeobfuscator detected = null;
|
||||||
int detectVal = 0;
|
int detectVal = 0;
|
||||||
|
@ -301,7 +301,7 @@ namespace de4dot.code {
|
||||||
this.deob = deob; // So we can call deob.CanInlineMethods in deobfuscate()
|
this.deob = deob; // So we can call deob.CanInlineMethods in deobfuscate()
|
||||||
int val;
|
int val;
|
||||||
try {
|
try {
|
||||||
val = deob.detect();
|
val = deob.Detect();
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
val = deob.Type == "un" ? 1 : 0;
|
val = deob.Type == "un" ? 1 : 0;
|
||||||
|
@ -318,16 +318,16 @@ namespace de4dot.code {
|
||||||
|
|
||||||
if (allDetected.Count > 1) {
|
if (allDetected.Count > 1) {
|
||||||
Logger.n("More than one obfuscator detected:");
|
Logger.n("More than one obfuscator detected:");
|
||||||
Logger.Instance.indent();
|
Logger.Instance.Indent();
|
||||||
foreach (var deob in allDetected)
|
foreach (var deob in allDetected)
|
||||||
Logger.n("{0} (use: -p {1})", deob.Name, deob.Type);
|
Logger.n("{0} (use: -p {1})", deob.Name, deob.Type);
|
||||||
Logger.Instance.deIndent();
|
Logger.Instance.DeIndent();
|
||||||
}
|
}
|
||||||
|
|
||||||
return detected;
|
return detected;
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaDataFlags getMetaDataFlags() {
|
MetaDataFlags GetMetaDataFlags() {
|
||||||
var mdFlags = options.MetaDataFlags | deob.MetaDataFlags;
|
var mdFlags = options.MetaDataFlags | deob.MetaDataFlags;
|
||||||
|
|
||||||
// Always preserve tokens if it's an unknown obfuscator
|
// Always preserve tokens if it's an unknown obfuscator
|
||||||
|
@ -341,15 +341,15 @@ namespace de4dot.code {
|
||||||
return mdFlags;
|
return mdFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void save() {
|
public void Save() {
|
||||||
Logger.n("Saving {0}", options.NewFilename);
|
Logger.n("Saving {0}", options.NewFilename);
|
||||||
var mdFlags = getMetaDataFlags();
|
var mdFlags = GetMetaDataFlags();
|
||||||
if (!options.ControlFlowDeobfuscation)
|
if (!options.ControlFlowDeobfuscation)
|
||||||
mdFlags |= MetaDataFlags.KeepOldMaxStack;
|
mdFlags |= MetaDataFlags.KeepOldMaxStack;
|
||||||
assemblyModule.save(options.NewFilename, mdFlags, deob as IModuleWriterListener);
|
assemblyModule.Save(options.NewFilename, mdFlags, deob as IModuleWriterListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
IList<MethodDef> getAllMethods() {
|
IList<MethodDef> GetAllMethods() {
|
||||||
var list = new List<MethodDef>();
|
var list = new List<MethodDef>();
|
||||||
|
|
||||||
foreach (var type in module.GetTypes()) {
|
foreach (var type in module.GetTypes()) {
|
||||||
|
@ -360,25 +360,25 @@ namespace de4dot.code {
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deobfuscateBegin() {
|
public void DeobfuscateBegin() {
|
||||||
switch (options.StringDecrypterType) {
|
switch (options.StringDecrypterType) {
|
||||||
case DecrypterType.None:
|
case DecrypterType.None:
|
||||||
checkSupportedStringDecrypter(StringFeatures.AllowNoDecryption);
|
CheckSupportedStringDecrypter(StringFeatures.AllowNoDecryption);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DecrypterType.Static:
|
case DecrypterType.Static:
|
||||||
checkSupportedStringDecrypter(StringFeatures.AllowStaticDecryption);
|
CheckSupportedStringDecrypter(StringFeatures.AllowStaticDecryption);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DecrypterType.Delegate:
|
case DecrypterType.Delegate:
|
||||||
case DecrypterType.Emulate:
|
case DecrypterType.Emulate:
|
||||||
checkSupportedStringDecrypter(StringFeatures.AllowDynamicDecryption);
|
CheckSupportedStringDecrypter(StringFeatures.AllowDynamicDecryption);
|
||||||
var newProcFactory = assemblyClientFactory as NewProcessAssemblyClientFactory;
|
var newProcFactory = assemblyClientFactory as NewProcessAssemblyClientFactory;
|
||||||
if (newProcFactory != null)
|
if (newProcFactory != null)
|
||||||
assemblyClient = newProcFactory.create(module);
|
assemblyClient = newProcFactory.Create(module);
|
||||||
else
|
else
|
||||||
assemblyClient = assemblyClientFactory.create();
|
assemblyClient = assemblyClientFactory.Create();
|
||||||
assemblyClient.connect();
|
assemblyClient.Connect();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -386,73 +386,73 @@ namespace de4dot.code {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void checkSupportedStringDecrypter(StringFeatures feature) {
|
public void CheckSupportedStringDecrypter(StringFeatures feature) {
|
||||||
if ((deob.StringFeatures & feature) == feature)
|
if ((deob.StringFeatures & feature) == feature)
|
||||||
return;
|
return;
|
||||||
throw new UserException(string.Format("Deobfuscator {0} does not support this string decryption type", deob.TypeLong));
|
throw new UserException(string.Format("Deobfuscator {0} does not support this string decryption type", deob.TypeLong));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deobfuscate() {
|
public void Deobfuscate() {
|
||||||
Logger.n("Cleaning {0}", options.Filename);
|
Logger.n("Cleaning {0}", options.Filename);
|
||||||
initAssemblyClient();
|
InitAssemblyClient();
|
||||||
|
|
||||||
for (int i = 0; ; i++) {
|
for (int i = 0; ; i++) {
|
||||||
byte[] fileData = null;
|
byte[] fileData = null;
|
||||||
DumpedMethods dumpedMethods = null;
|
DumpedMethods dumpedMethods = null;
|
||||||
if (!deob.getDecryptedModule(i, ref fileData, ref dumpedMethods))
|
if (!deob.GetDecryptedModule(i, ref fileData, ref dumpedMethods))
|
||||||
break;
|
break;
|
||||||
reloadModule(fileData, dumpedMethods);
|
ReloadModule(fileData, dumpedMethods);
|
||||||
}
|
}
|
||||||
|
|
||||||
deob.deobfuscateBegin();
|
deob.DeobfuscateBegin();
|
||||||
deobfuscateMethods();
|
DeobfuscateMethods();
|
||||||
deob.deobfuscateEnd();
|
deob.DeobfuscateEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
void reloadModule(byte[] newModuleData, DumpedMethods dumpedMethods) {
|
void ReloadModule(byte[] newModuleData, DumpedMethods dumpedMethods) {
|
||||||
Logger.v("Reloading decrypted assembly (original filename: {0})", Filename);
|
Logger.v("Reloading decrypted assembly (original filename: {0})", Filename);
|
||||||
simpleDeobfuscatorFlags.Clear();
|
simpleDeobfuscatorFlags.Clear();
|
||||||
using (var oldModule = module) {
|
using (var oldModule = module) {
|
||||||
module = assemblyModule.reload(newModuleData, createDumpedMethodsRestorer(dumpedMethods), deob as IStringDecrypter);
|
module = assemblyModule.Reload(newModuleData, CreateDumpedMethodsRestorer(dumpedMethods), deob as IStringDecrypter);
|
||||||
deob = deob.moduleReloaded(module);
|
deob = deob.ModuleReloaded(module);
|
||||||
}
|
}
|
||||||
initializeDeobfuscator();
|
InitializeDeobfuscator();
|
||||||
deob.DeobfuscatedFile = this;
|
deob.DeobfuscatedFile = this;
|
||||||
updateDynamicStringInliner();
|
UpdateDynamicStringInliner();
|
||||||
}
|
}
|
||||||
|
|
||||||
DumpedMethodsRestorer createDumpedMethodsRestorer(DumpedMethods dumpedMethods) {
|
DumpedMethodsRestorer CreateDumpedMethodsRestorer(DumpedMethods dumpedMethods) {
|
||||||
if (dumpedMethods == null || dumpedMethods.Count == 0)
|
if (dumpedMethods == null || dumpedMethods.Count == 0)
|
||||||
return null;
|
return null;
|
||||||
return new DumpedMethodsRestorer(dumpedMethods);
|
return new DumpedMethodsRestorer(dumpedMethods);
|
||||||
}
|
}
|
||||||
|
|
||||||
void initAssemblyClient() {
|
void InitAssemblyClient() {
|
||||||
if (assemblyClient == null)
|
if (assemblyClient == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
assemblyClient.waitConnected();
|
assemblyClient.WaitConnected();
|
||||||
assemblyClient.Service.loadAssembly(options.Filename);
|
assemblyClient.Service.LoadAssembly(options.Filename);
|
||||||
|
|
||||||
if (options.StringDecrypterType == DecrypterType.Delegate)
|
if (options.StringDecrypterType == DecrypterType.Delegate)
|
||||||
assemblyClient.Service.setStringDecrypterType(AssemblyData.StringDecrypterType.Delegate);
|
assemblyClient.Service.SetStringDecrypterType(AssemblyData.StringDecrypterType.Delegate);
|
||||||
else if (options.StringDecrypterType == DecrypterType.Emulate)
|
else if (options.StringDecrypterType == DecrypterType.Emulate)
|
||||||
assemblyClient.Service.setStringDecrypterType(AssemblyData.StringDecrypterType.Emulate);
|
assemblyClient.Service.SetStringDecrypterType(AssemblyData.StringDecrypterType.Emulate);
|
||||||
else
|
else
|
||||||
throw new ApplicationException(string.Format("Invalid string decrypter type '{0}'", options.StringDecrypterType));
|
throw new ApplicationException(string.Format("Invalid string decrypter type '{0}'", options.StringDecrypterType));
|
||||||
|
|
||||||
dynamicStringInliner = new DynamicStringInliner(assemblyClient);
|
dynamicStringInliner = new DynamicStringInliner(assemblyClient);
|
||||||
updateDynamicStringInliner();
|
UpdateDynamicStringInliner();
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateDynamicStringInliner() {
|
void UpdateDynamicStringInliner() {
|
||||||
if (dynamicStringInliner != null)
|
if (dynamicStringInliner != null)
|
||||||
dynamicStringInliner.init(getMethodTokens());
|
dynamicStringInliner.Initialize(GetMethodTokens());
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerable<int> getMethodTokens() {
|
IEnumerable<int> GetMethodTokens() {
|
||||||
if (!userStringDecrypterMethods)
|
if (!userStringDecrypterMethods)
|
||||||
return deob.getStringDecrypterMethods();
|
return deob.GetStringDecrypterMethods();
|
||||||
|
|
||||||
var tokens = new List<int>();
|
var tokens = new List<int>();
|
||||||
|
|
||||||
|
@ -464,18 +464,18 @@ namespace de4dot.code {
|
||||||
if (int.TryParse(tokenStr, NumberStyles.HexNumber, null, out methodToken))
|
if (int.TryParse(tokenStr, NumberStyles.HexNumber, null, out methodToken))
|
||||||
tokens.Add(methodToken);
|
tokens.Add(methodToken);
|
||||||
else
|
else
|
||||||
tokens.AddRange(findMethodTokens(val));
|
tokens.AddRange(FindMethodTokens(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
return tokens;
|
return tokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerable<int> findMethodTokens(string methodDesc) {
|
IEnumerable<int> FindMethodTokens(string methodDesc) {
|
||||||
var tokens = new List<int>();
|
var tokens = new List<int>();
|
||||||
|
|
||||||
string typeString, methodName;
|
string typeString, methodName;
|
||||||
string[] argsStrings;
|
string[] argsStrings;
|
||||||
splitMethodDesc(methodDesc, out typeString, out methodName, out argsStrings);
|
SplitMethodDesc(methodDesc, out typeString, out methodName, out argsStrings);
|
||||||
|
|
||||||
foreach (var type in module.GetTypes()) {
|
foreach (var type in module.GetTypes()) {
|
||||||
if (typeString != null && typeString != type.FullName)
|
if (typeString != null && typeString != type.FullName)
|
||||||
|
@ -502,7 +502,7 @@ namespace de4dot.code {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.v("Adding string decrypter; token: {0:X8}, method: {1}", method.MDToken.ToInt32(), Utils.removeNewlines(method.FullName));
|
Logger.v("Adding string decrypter; token: {0:X8}, method: {1}", method.MDToken.ToInt32(), Utils.RemoveNewlines(method.FullName));
|
||||||
tokens.Add(method.MDToken.ToInt32());
|
tokens.Add(method.MDToken.ToInt32());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -510,7 +510,7 @@ namespace de4dot.code {
|
||||||
return tokens;
|
return tokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void splitMethodDesc(string methodDesc, out string type, out string name, out string[] args) {
|
static void SplitMethodDesc(string methodDesc, out string type, out string name, out string[] args) {
|
||||||
string stringArgs = null;
|
string stringArgs = null;
|
||||||
args = null;
|
args = null;
|
||||||
type = null;
|
type = null;
|
||||||
|
@ -555,20 +555,20 @@ namespace de4dot.code {
|
||||||
name = null;
|
name = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deobfuscateEnd() {
|
public void DeobfuscateEnd() {
|
||||||
deobfuscateCleanUp();
|
DeobfuscateCleanUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deobfuscateCleanUp() {
|
public void DeobfuscateCleanUp() {
|
||||||
if (assemblyClient != null) {
|
if (assemblyClient != null) {
|
||||||
assemblyClient.Dispose();
|
assemblyClient.Dispose();
|
||||||
assemblyClient = null;
|
assemblyClient = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void deobfuscateMethods() {
|
void DeobfuscateMethods() {
|
||||||
if (savedMethodBodies != null) {
|
if (savedMethodBodies != null) {
|
||||||
savedMethodBodies.restoreAll();
|
savedMethodBodies.RestoreAll();
|
||||||
savedMethodBodies = null;
|
savedMethodBodies = null;
|
||||||
}
|
}
|
||||||
deob.DeobfuscatedFile = null;
|
deob.DeobfuscatedFile = null;
|
||||||
|
@ -584,21 +584,21 @@ namespace de4dot.code {
|
||||||
Logger.v("Deobfuscating methods");
|
Logger.v("Deobfuscating methods");
|
||||||
var methodPrinter = new MethodPrinter();
|
var methodPrinter = new MethodPrinter();
|
||||||
var cflowDeobfuscator = new BlocksCflowDeobfuscator(deob.BlocksDeobfuscators);
|
var cflowDeobfuscator = new BlocksCflowDeobfuscator(deob.BlocksDeobfuscators);
|
||||||
foreach (var method in getAllMethods()) {
|
foreach (var method in GetAllMethods()) {
|
||||||
if (isVerbose) {
|
if (isVerbose) {
|
||||||
Logger.v("Deobfuscating {0} ({1:X8})", Utils.removeNewlines(method), method.MDToken.ToUInt32());
|
Logger.v("Deobfuscating {0} ({1:X8})", Utils.RemoveNewlines(method), method.MDToken.ToUInt32());
|
||||||
Logger.Instance.indent();
|
Logger.Instance.Indent();
|
||||||
}
|
}
|
||||||
|
|
||||||
int oldIndentLevel = Logger.Instance.IndentLevel;
|
int oldIndentLevel = Logger.Instance.IndentLevel;
|
||||||
try {
|
try {
|
||||||
deobfuscate(method, cflowDeobfuscator, methodPrinter, isVerbose, isVV);
|
Deobfuscate(method, cflowDeobfuscator, methodPrinter, isVerbose, isVV);
|
||||||
}
|
}
|
||||||
catch (ApplicationException) {
|
catch (ApplicationException) {
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
if (!canLoadMethodBody(method)) {
|
if (!CanLoadMethodBody(method)) {
|
||||||
if (isVerbose)
|
if (isVerbose)
|
||||||
Logger.v("Invalid method body. {0:X8}", method.MDToken.ToInt32());
|
Logger.v("Invalid method body. {0:X8}", method.MDToken.ToInt32());
|
||||||
method.Body = new CilBody();
|
method.Body = new CilBody();
|
||||||
|
@ -612,14 +612,14 @@ namespace de4dot.code {
|
||||||
finally {
|
finally {
|
||||||
Logger.Instance.IndentLevel = oldIndentLevel;
|
Logger.Instance.IndentLevel = oldIndentLevel;
|
||||||
}
|
}
|
||||||
removeNoInliningAttribute(method);
|
RemoveNoInliningAttribute(method);
|
||||||
|
|
||||||
if (isVerbose)
|
if (isVerbose)
|
||||||
Logger.Instance.deIndent();
|
Logger.Instance.DeIndent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool canLoadMethodBody(MethodDef method) {
|
static bool CanLoadMethodBody(MethodDef method) {
|
||||||
try {
|
try {
|
||||||
var body = method.Body;
|
var body = method.Body;
|
||||||
return true;
|
return true;
|
||||||
|
@ -631,39 +631,39 @@ namespace de4dot.code {
|
||||||
|
|
||||||
bool CanOptimizeLocals() {
|
bool CanOptimizeLocals() {
|
||||||
// Don't remove any locals if we must preserve StandAloneSig table
|
// Don't remove any locals if we must preserve StandAloneSig table
|
||||||
return (getMetaDataFlags() & MetaDataFlags.PreserveStandAloneSigRids) == 0;
|
return (GetMetaDataFlags() & MetaDataFlags.PreserveStandAloneSigRids) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void deobfuscate(MethodDef method, BlocksCflowDeobfuscator cflowDeobfuscator, MethodPrinter methodPrinter, bool isVerbose, bool isVV) {
|
void Deobfuscate(MethodDef method, BlocksCflowDeobfuscator cflowDeobfuscator, MethodPrinter methodPrinter, bool isVerbose, bool isVV) {
|
||||||
if (!hasNonEmptyBody(method))
|
if (!HasNonEmptyBody(method))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var blocks = new Blocks(method);
|
var blocks = new Blocks(method);
|
||||||
int numRemovedLocals = 0;
|
int numRemovedLocals = 0;
|
||||||
int oldNumInstructions = method.Body.Instructions.Count;
|
int oldNumInstructions = method.Body.Instructions.Count;
|
||||||
|
|
||||||
deob.deobfuscateMethodBegin(blocks);
|
deob.DeobfuscateMethodBegin(blocks);
|
||||||
if (options.ControlFlowDeobfuscation) {
|
if (options.ControlFlowDeobfuscation) {
|
||||||
cflowDeobfuscator.init(blocks);
|
cflowDeobfuscator.Initialize(blocks);
|
||||||
cflowDeobfuscator.deobfuscate();
|
cflowDeobfuscator.Deobfuscate();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deob.deobfuscateOther(blocks) && options.ControlFlowDeobfuscation)
|
if (deob.DeobfuscateOther(blocks) && options.ControlFlowDeobfuscation)
|
||||||
cflowDeobfuscator.deobfuscate();
|
cflowDeobfuscator.Deobfuscate();
|
||||||
|
|
||||||
if (options.ControlFlowDeobfuscation) {
|
if (options.ControlFlowDeobfuscation) {
|
||||||
if (CanOptimizeLocals())
|
if (CanOptimizeLocals())
|
||||||
numRemovedLocals = blocks.optimizeLocals();
|
numRemovedLocals = blocks.OptimizeLocals();
|
||||||
blocks.repartitionBlocks();
|
blocks.RepartitionBlocks();
|
||||||
}
|
}
|
||||||
|
|
||||||
deobfuscateStrings(blocks);
|
DeobfuscateStrings(blocks);
|
||||||
deob.deobfuscateMethodEnd(blocks);
|
deob.DeobfuscateMethodEnd(blocks);
|
||||||
|
|
||||||
IList<Instruction> allInstructions;
|
IList<Instruction> allInstructions;
|
||||||
IList<ExceptionHandler> allExceptionHandlers;
|
IList<ExceptionHandler> allExceptionHandlers;
|
||||||
blocks.getCode(out allInstructions, out allExceptionHandlers);
|
blocks.GetCode(out allInstructions, out allExceptionHandlers);
|
||||||
DotNetUtils.restoreBody(method, allInstructions, allExceptionHandlers);
|
DotNetUtils.RestoreBody(method, allInstructions, allExceptionHandlers);
|
||||||
|
|
||||||
if (isVerbose && numRemovedLocals > 0)
|
if (isVerbose && numRemovedLocals > 0)
|
||||||
Logger.v("Removed {0} unused local(s)", numRemovedLocals);
|
Logger.v("Removed {0} unused local(s)", numRemovedLocals);
|
||||||
|
@ -672,29 +672,29 @@ namespace de4dot.code {
|
||||||
Logger.v("Removed {0} dead instruction(s)", numRemovedInstructions);
|
Logger.v("Removed {0} dead instruction(s)", numRemovedInstructions);
|
||||||
|
|
||||||
if (isVV) {
|
if (isVV) {
|
||||||
Logger.log(LoggerEvent.VeryVerbose, "Deobfuscated code:");
|
Logger.Log(LoggerEvent.VeryVerbose, "Deobfuscated code:");
|
||||||
Logger.Instance.indent();
|
Logger.Instance.Indent();
|
||||||
methodPrinter.print(LoggerEvent.VeryVerbose, allInstructions, allExceptionHandlers);
|
methodPrinter.Print(LoggerEvent.VeryVerbose, allInstructions, allExceptionHandlers);
|
||||||
Logger.Instance.deIndent();
|
Logger.Instance.DeIndent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasNonEmptyBody(MethodDef method) {
|
bool HasNonEmptyBody(MethodDef method) {
|
||||||
return method.HasBody && method.Body.Instructions.Count > 0;
|
return method.HasBody && method.Body.Instructions.Count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void deobfuscateStrings(Blocks blocks) {
|
void DeobfuscateStrings(Blocks blocks) {
|
||||||
switch (options.StringDecrypterType) {
|
switch (options.StringDecrypterType) {
|
||||||
case DecrypterType.None:
|
case DecrypterType.None:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DecrypterType.Static:
|
case DecrypterType.Static:
|
||||||
deob.deobfuscateStrings(blocks);
|
deob.DeobfuscateStrings(blocks);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DecrypterType.Delegate:
|
case DecrypterType.Delegate:
|
||||||
case DecrypterType.Emulate:
|
case DecrypterType.Emulate:
|
||||||
dynamicStringInliner.decrypt(blocks);
|
dynamicStringInliner.Decrypt(blocks);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -702,14 +702,14 @@ namespace de4dot.code {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeNoInliningAttribute(MethodDef method) {
|
void RemoveNoInliningAttribute(MethodDef method) {
|
||||||
method.IsNoInlining = false;
|
method.IsNoInlining = false;
|
||||||
for (int i = 0; i < method.CustomAttributes.Count; i++) {
|
for (int i = 0; i < method.CustomAttributes.Count; i++) {
|
||||||
var cattr = method.CustomAttributes[i];
|
var cattr = method.CustomAttributes[i];
|
||||||
if (cattr.TypeFullName != "System.Runtime.CompilerServices.MethodImplAttribute")
|
if (cattr.TypeFullName != "System.Runtime.CompilerServices.MethodImplAttribute")
|
||||||
continue;
|
continue;
|
||||||
int options = 0;
|
int options = 0;
|
||||||
if (!getMethodImplOptions(cattr, ref options))
|
if (!GetMethodImplOptions(cattr, ref options))
|
||||||
continue;
|
continue;
|
||||||
if (options != 0 && options != (int)MethodImplAttributes.NoInlining)
|
if (options != 0 && options != (int)MethodImplAttributes.NoInlining)
|
||||||
continue;
|
continue;
|
||||||
|
@ -718,7 +718,7 @@ namespace de4dot.code {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool getMethodImplOptions(CustomAttribute cattr, ref int value) {
|
static bool GetMethodImplOptions(CustomAttribute cattr, ref int value) {
|
||||||
if (cattr.IsRawBlob)
|
if (cattr.IsRawBlob)
|
||||||
return false;
|
return false;
|
||||||
if (cattr.ConstructorArguments.Count != 1)
|
if (cattr.ConstructorArguments.Count != 1)
|
||||||
|
@ -751,21 +751,21 @@ namespace de4dot.code {
|
||||||
HasDeobfuscated = 0x1,
|
HasDeobfuscated = 0x1,
|
||||||
}
|
}
|
||||||
Dictionary<MethodDef, SimpleDeobFlags> simpleDeobfuscatorFlags = new Dictionary<MethodDef, SimpleDeobFlags>();
|
Dictionary<MethodDef, SimpleDeobFlags> simpleDeobfuscatorFlags = new Dictionary<MethodDef, SimpleDeobFlags>();
|
||||||
bool check(MethodDef method, SimpleDeobFlags flag) {
|
bool Check(MethodDef method, SimpleDeobFlags flag) {
|
||||||
SimpleDeobFlags oldFlags;
|
SimpleDeobFlags oldFlags;
|
||||||
simpleDeobfuscatorFlags.TryGetValue(method, out oldFlags);
|
simpleDeobfuscatorFlags.TryGetValue(method, out oldFlags);
|
||||||
simpleDeobfuscatorFlags[method] = oldFlags | flag;
|
simpleDeobfuscatorFlags[method] = oldFlags | flag;
|
||||||
return (oldFlags & flag) == flag;
|
return (oldFlags & flag) == flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
void deobfuscate(MethodDef method, string msg, Action<Blocks> handler) {
|
void Deobfuscate(MethodDef method, string msg, Action<Blocks> handler) {
|
||||||
if (savedMethodBodies != null)
|
if (savedMethodBodies != null)
|
||||||
savedMethodBodies.save(method);
|
savedMethodBodies.Save(method);
|
||||||
|
|
||||||
Logger.v("{0}: {1} ({2:X8})", msg, Utils.removeNewlines(method), method.MDToken.ToUInt32());
|
Logger.v("{0}: {1} ({2:X8})", msg, Utils.RemoveNewlines(method), method.MDToken.ToUInt32());
|
||||||
Logger.Instance.indent();
|
Logger.Instance.Indent();
|
||||||
|
|
||||||
if (hasNonEmptyBody(method)) {
|
if (HasNonEmptyBody(method)) {
|
||||||
try {
|
try {
|
||||||
var blocks = new Blocks(method);
|
var blocks = new Blocks(method);
|
||||||
|
|
||||||
|
@ -773,55 +773,55 @@ namespace de4dot.code {
|
||||||
|
|
||||||
IList<Instruction> allInstructions;
|
IList<Instruction> allInstructions;
|
||||||
IList<ExceptionHandler> allExceptionHandlers;
|
IList<ExceptionHandler> allExceptionHandlers;
|
||||||
blocks.getCode(out allInstructions, out allExceptionHandlers);
|
blocks.GetCode(out allInstructions, out allExceptionHandlers);
|
||||||
DotNetUtils.restoreBody(method, allInstructions, allExceptionHandlers);
|
DotNetUtils.RestoreBody(method, allInstructions, allExceptionHandlers);
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
Logger.v("Could not deobfuscate {0:X8}", method.MDToken.ToInt32());
|
Logger.v("Could not deobfuscate {0:X8}", method.MDToken.ToInt32());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.Instance.deIndent();
|
Logger.Instance.DeIndent();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ISimpleDeobfuscator.deobfuscate(MethodDef method) {
|
void ISimpleDeobfuscator.Deobfuscate(MethodDef method) {
|
||||||
((ISimpleDeobfuscator)this).deobfuscate(method, false);
|
((ISimpleDeobfuscator)this).Deobfuscate(method, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ISimpleDeobfuscator.deobfuscate(MethodDef method, bool force) {
|
void ISimpleDeobfuscator.Deobfuscate(MethodDef method, bool force) {
|
||||||
if (!force && check(method, SimpleDeobFlags.HasDeobfuscated))
|
if (!force && Check(method, SimpleDeobFlags.HasDeobfuscated))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
deobfuscate(method, "Deobfuscating control flow", (blocks) => {
|
Deobfuscate(method, "Deobfuscating control flow", (blocks) => {
|
||||||
var cflowDeobfuscator = new BlocksCflowDeobfuscator(deob.BlocksDeobfuscators);
|
var cflowDeobfuscator = new BlocksCflowDeobfuscator(deob.BlocksDeobfuscators);
|
||||||
cflowDeobfuscator.init(blocks);
|
cflowDeobfuscator.Initialize(blocks);
|
||||||
cflowDeobfuscator.deobfuscate();
|
cflowDeobfuscator.Deobfuscate();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void ISimpleDeobfuscator.decryptStrings(MethodDef method, IDeobfuscator theDeob) {
|
void ISimpleDeobfuscator.DecryptStrings(MethodDef method, IDeobfuscator theDeob) {
|
||||||
deobfuscate(method, "Static string decryption", (blocks) => theDeob.deobfuscateStrings(blocks));
|
Deobfuscate(method, "Static string decryption", (blocks) => theDeob.DeobfuscateStrings(blocks));
|
||||||
}
|
}
|
||||||
|
|
||||||
void IDeobfuscatedFile.createAssemblyFile(byte[] data, string assemblyName, string extension) {
|
void IDeobfuscatedFile.CreateAssemblyFile(byte[] data, string assemblyName, string extension) {
|
||||||
if (extension == null)
|
if (extension == null)
|
||||||
extension = ".dll";
|
extension = ".dll";
|
||||||
var baseDir = Utils.getDirName(options.NewFilename);
|
var baseDir = Utils.GetDirName(options.NewFilename);
|
||||||
var newName = Path.Combine(baseDir, assemblyName + extension);
|
var newName = Path.Combine(baseDir, assemblyName + extension);
|
||||||
Logger.n("Creating file {0}", newName);
|
Logger.n("Creating file {0}", newName);
|
||||||
File.WriteAllBytes(newName, data);
|
File.WriteAllBytes(newName, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IDeobfuscatedFile.stringDecryptersAdded() {
|
void IDeobfuscatedFile.StringDecryptersAdded() {
|
||||||
updateDynamicStringInliner();
|
UpdateDynamicStringInliner();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IDeobfuscatedFile.setDeobfuscator(IDeobfuscator deob) {
|
void IDeobfuscatedFile.SetDeobfuscator(IDeobfuscator deob) {
|
||||||
this.deob = deob;
|
this.deob = deob;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose() {
|
public void Dispose() {
|
||||||
deobfuscateCleanUp();
|
DeobfuscateCleanUp();
|
||||||
if (module != null)
|
if (module != null)
|
||||||
module.Dispose();
|
module.Dispose();
|
||||||
if (deob != null)
|
if (deob != null)
|
||||||
|
|
|
@ -57,7 +57,7 @@ namespace de4dot.code {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the new value is set, or false on error. error string is also updated.
|
// Returns true if the new value is set, or false on error. error string is also updated.
|
||||||
public abstract bool set(string val, out string error);
|
public abstract bool Set(string val, out string error);
|
||||||
|
|
||||||
public Option(string shortName, string longName, string description) {
|
public Option(string shortName, string longName, string description) {
|
||||||
if (shortName != null)
|
if (shortName != null)
|
||||||
|
@ -79,7 +79,7 @@ namespace de4dot.code {
|
||||||
get { return "bool"; }
|
get { return "bool"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool set(string newVal, out string error) {
|
public override bool Set(string newVal, out string error) {
|
||||||
if (string.Equals(newVal, "false", StringComparison.OrdinalIgnoreCase) ||
|
if (string.Equals(newVal, "false", StringComparison.OrdinalIgnoreCase) ||
|
||||||
string.Equals(newVal, "off", StringComparison.OrdinalIgnoreCase) ||
|
string.Equals(newVal, "off", StringComparison.OrdinalIgnoreCase) ||
|
||||||
string.Equals(newVal, "0", StringComparison.OrdinalIgnoreCase)) {
|
string.Equals(newVal, "0", StringComparison.OrdinalIgnoreCase)) {
|
||||||
|
@ -107,7 +107,7 @@ namespace de4dot.code {
|
||||||
get { return "int"; }
|
get { return "int"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool set(string newVal, out string error) {
|
public override bool Set(string newVal, out string error) {
|
||||||
int newInt;
|
int newInt;
|
||||||
if (!int.TryParse(newVal, out newInt)) {
|
if (!int.TryParse(newVal, out newInt)) {
|
||||||
error = string.Format("Not an integer: '{0}'", newVal);
|
error = string.Format("Not an integer: '{0}'", newVal);
|
||||||
|
@ -135,7 +135,7 @@ namespace de4dot.code {
|
||||||
Default = this.val = val;
|
Default = this.val = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool set(string newVal, out string error) {
|
public override bool Set(string newVal, out string error) {
|
||||||
val = newVal;
|
val = newVal;
|
||||||
error = "";
|
error = "";
|
||||||
return true;
|
return true;
|
||||||
|
@ -158,10 +158,10 @@ namespace de4dot.code {
|
||||||
Default = this.val = new NameRegexes(val);
|
Default = this.val = new NameRegexes(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool set(string newVal, out string error) {
|
public override bool Set(string newVal, out string error) {
|
||||||
try {
|
try {
|
||||||
var regexes = new NameRegexes();
|
var regexes = new NameRegexes();
|
||||||
regexes.set(newVal);
|
regexes.Set(newVal);
|
||||||
val = regexes;
|
val = regexes;
|
||||||
}
|
}
|
||||||
catch (ArgumentException) {
|
catch (ArgumentException) {
|
||||||
|
@ -189,7 +189,7 @@ namespace de4dot.code {
|
||||||
Default = this.val = new Regex(val);
|
Default = this.val = new Regex(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool set(string newVal, out string error) {
|
public override bool Set(string newVal, out string error) {
|
||||||
try {
|
try {
|
||||||
val = new Regex(newVal);
|
val = new Regex(newVal);
|
||||||
}
|
}
|
||||||
|
@ -223,7 +223,7 @@ namespace de4dot.code {
|
||||||
this.action = action;
|
this.action = action;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool set(string val, out string error) {
|
public override bool Set(string val, out string error) {
|
||||||
triggered = true;
|
triggered = true;
|
||||||
if (action != null)
|
if (action != null)
|
||||||
action();
|
action();
|
||||||
|
@ -251,7 +251,7 @@ namespace de4dot.code {
|
||||||
Default = null;
|
Default = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool set(string val, out string error) {
|
public override bool Set(string val, out string error) {
|
||||||
action(val);
|
action(val);
|
||||||
error = "";
|
error = "";
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
[assembly: AssemblyVersion("2.0.2.3405")]
|
[assembly: AssemblyVersion("2.0.3.3405")]
|
||||||
[assembly: AssemblyFileVersion("2.0.2.3405")]
|
[assembly: AssemblyFileVersion("2.0.3.3405")]
|
||||||
|
|
|
@ -26,7 +26,7 @@ using de4dot.blocks;
|
||||||
|
|
||||||
namespace de4dot.code {
|
namespace de4dot.code {
|
||||||
abstract class StringInlinerBase : MethodReturnValueInliner {
|
abstract class StringInlinerBase : MethodReturnValueInliner {
|
||||||
protected override void inlineReturnValues(IList<CallResult> callResults) {
|
protected override void InlineReturnValues(IList<CallResult> callResults) {
|
||||||
foreach (var callResult in callResults) {
|
foreach (var callResult in callResults) {
|
||||||
var block = callResult.block;
|
var block = callResult.block;
|
||||||
int num = callResult.callEndIndex - callResult.callStartIndex + 1;
|
int num = callResult.callEndIndex - callResult.callStartIndex + 1;
|
||||||
|
@ -36,13 +36,13 @@ namespace de4dot.code {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int ldstrIndex = callResult.callStartIndex;
|
int ldstrIndex = callResult.callStartIndex;
|
||||||
block.replace(ldstrIndex, num, OpCodes.Ldstr.ToInstruction(decryptedString));
|
block.Replace(ldstrIndex, num, OpCodes.Ldstr.ToInstruction(decryptedString));
|
||||||
|
|
||||||
// If it's followed by castclass string, remove it
|
// If it's followed by castclass string, remove it
|
||||||
if (ldstrIndex + 1 < block.Instructions.Count) {
|
if (ldstrIndex + 1 < block.Instructions.Count) {
|
||||||
var instr = block.Instructions[ldstrIndex + 1];
|
var instr = block.Instructions[ldstrIndex + 1];
|
||||||
if (instr.OpCode.Code == Code.Castclass && instr.Operand.ToString() == "System.String")
|
if (instr.OpCode.Code == Code.Castclass && instr.Operand.ToString() == "System.String")
|
||||||
block.remove(ldstrIndex + 1, 1);
|
block.Remove(ldstrIndex + 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it's followed by String.Intern(), then nop out that call
|
// If it's followed by String.Intern(), then nop out that call
|
||||||
|
@ -52,12 +52,12 @@ namespace de4dot.code {
|
||||||
var calledMethod = instr.Operand as IMethod;
|
var calledMethod = instr.Operand as IMethod;
|
||||||
if (calledMethod != null &&
|
if (calledMethod != null &&
|
||||||
calledMethod.FullName == "System.String System.String::Intern(System.String)") {
|
calledMethod.FullName == "System.String System.String::Intern(System.String)") {
|
||||||
block.remove(ldstrIndex + 1, 1);
|
block.Remove(ldstrIndex + 1, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.v("Decrypted string: {0}", Utils.toCsharpString(decryptedString));
|
Logger.v("Decrypted string: {0}", Utils.ToCsharpString(decryptedString));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,23 +84,23 @@ namespace de4dot.code {
|
||||||
this.assemblyClient = assemblyClient;
|
this.assemblyClient = assemblyClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init(IEnumerable<int> methodTokens) {
|
public void Initialize(IEnumerable<int> methodTokens) {
|
||||||
methodTokenToId.Clear();
|
methodTokenToId.Clear();
|
||||||
foreach (var methodToken in methodTokens) {
|
foreach (var methodToken in methodTokens) {
|
||||||
if (methodTokenToId.ContainsKey(methodToken))
|
if (methodTokenToId.ContainsKey(methodToken))
|
||||||
continue;
|
continue;
|
||||||
methodTokenToId[methodToken] = assemblyClient.Service.defineStringDecrypter(methodToken);
|
methodTokenToId[methodToken] = assemblyClient.Service.DefineStringDecrypter(methodToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override CallResult createCallResult(IMethod method, MethodSpec gim, Block block, int callInstrIndex) {
|
protected override CallResult CreateCallResult(IMethod method, MethodSpec gim, Block block, int callInstrIndex) {
|
||||||
int methodId;
|
int methodId;
|
||||||
if (!methodTokenToId.TryGetValue(method.MDToken.ToInt32(), out methodId))
|
if (!methodTokenToId.TryGetValue(method.MDToken.ToInt32(), out methodId))
|
||||||
return null;
|
return null;
|
||||||
return new MyCallResult(block, callInstrIndex, methodId, gim);
|
return new MyCallResult(block, callInstrIndex, methodId, gim);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void inlineAllCalls() {
|
protected override void InlineAllCalls() {
|
||||||
var sortedCalls = new Dictionary<int, List<MyCallResult>>();
|
var sortedCalls = new Dictionary<int, List<MyCallResult>>();
|
||||||
foreach (var tmp in callResults) {
|
foreach (var tmp in callResults) {
|
||||||
var callResult = (MyCallResult)tmp;
|
var callResult = (MyCallResult)tmp;
|
||||||
|
@ -114,13 +114,13 @@ namespace de4dot.code {
|
||||||
var list = sortedCalls[methodId];
|
var list = sortedCalls[methodId];
|
||||||
var args = new object[list.Count];
|
var args = new object[list.Count];
|
||||||
for (int i = 0; i < list.Count; i++) {
|
for (int i = 0; i < list.Count; i++) {
|
||||||
AssemblyData.SimpleData.pack(list[i].args);
|
AssemblyData.SimpleData.Pack(list[i].args);
|
||||||
args[i] = list[i].args;
|
args[i] = list[i].args;
|
||||||
}
|
}
|
||||||
var decryptedStrings = assemblyClient.Service.decryptStrings(methodId, args, Method.MDToken.ToInt32());
|
var decryptedStrings = assemblyClient.Service.DecryptStrings(methodId, args, Method.MDToken.ToInt32());
|
||||||
if (decryptedStrings.Length != args.Length)
|
if (decryptedStrings.Length != args.Length)
|
||||||
throw new ApplicationException("Invalid decrypted strings array length");
|
throw new ApplicationException("Invalid decrypted strings array length");
|
||||||
AssemblyData.SimpleData.unpack(decryptedStrings);
|
AssemblyData.SimpleData.Unpack(decryptedStrings);
|
||||||
for (int i = 0; i < list.Count; i++)
|
for (int i = 0; i < list.Count; i++)
|
||||||
list[i].returnValue = (string)decryptedStrings[i];
|
list[i].returnValue = (string)decryptedStrings[i];
|
||||||
}
|
}
|
||||||
|
@ -135,7 +135,7 @@ namespace de4dot.code {
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<MethodDef> Methods {
|
public IEnumerable<MethodDef> Methods {
|
||||||
get { return stringDecrypters.getKeys(); }
|
get { return stringDecrypters.GetKeys(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyCallResult : CallResult {
|
class MyCallResult : CallResult {
|
||||||
|
@ -148,21 +148,21 @@ namespace de4dot.code {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(MethodDef method, Func<MethodDef, MethodSpec, object[], string> handler) {
|
public void Add(MethodDef method, Func<MethodDef, MethodSpec, object[], string> handler) {
|
||||||
if (method != null)
|
if (method != null)
|
||||||
stringDecrypters.add(method, handler);
|
stringDecrypters.Add(method, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void inlineAllCalls() {
|
protected override void InlineAllCalls() {
|
||||||
foreach (var tmp in callResults) {
|
foreach (var tmp in callResults) {
|
||||||
var callResult = (MyCallResult)tmp;
|
var callResult = (MyCallResult)tmp;
|
||||||
var handler = stringDecrypters.find(callResult.IMethod);
|
var handler = stringDecrypters.Find(callResult.IMethod);
|
||||||
callResult.returnValue = handler((MethodDef)callResult.IMethod, callResult.gim, callResult.args);
|
callResult.returnValue = handler((MethodDef)callResult.IMethod, callResult.gim, callResult.args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override CallResult createCallResult(IMethod method, MethodSpec gim, Block block, int callInstrIndex) {
|
protected override CallResult CreateCallResult(IMethod method, MethodSpec gim, Block block, int callInstrIndex) {
|
||||||
if (stringDecrypters.find(method) == null)
|
if (stringDecrypters.Find(method) == null)
|
||||||
return null;
|
return null;
|
||||||
return new MyCallResult(block, callInstrIndex, method, gim);
|
return new MyCallResult(block, callInstrIndex, method, gim);
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ namespace de4dot.code {
|
||||||
public static class Utils {
|
public static class Utils {
|
||||||
static Random random = new Random();
|
static Random random = new Random();
|
||||||
|
|
||||||
public static IEnumerable<T> unique<T>(IEnumerable<T> values) {
|
public static IEnumerable<T> Unique<T>(IEnumerable<T> values) {
|
||||||
// HashSet is only available in .NET 3.5 and later.
|
// HashSet is only available in .NET 3.5 and later.
|
||||||
var dict = new Dictionary<T, bool>();
|
var dict = new Dictionary<T, bool>();
|
||||||
foreach (var val in values)
|
foreach (var val in values)
|
||||||
|
@ -63,30 +63,30 @@ namespace de4dot.code {
|
||||||
return dict.Keys;
|
return dict.Keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string toCsharpString(UTF8String s) {
|
public static string ToCsharpString(UTF8String s) {
|
||||||
return toCsharpString(UTF8String.ToSystemStringOrEmpty(s));
|
return ToCsharpString(UTF8String.ToSystemStringOrEmpty(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string toCsharpString(string s) {
|
public static string ToCsharpString(string s) {
|
||||||
var sb = new StringBuilder(s.Length + 2);
|
var sb = new StringBuilder(s.Length + 2);
|
||||||
sb.Append('"');
|
sb.Append('"');
|
||||||
foreach (var c in s) {
|
foreach (var c in s) {
|
||||||
if ((int)c < 0x20) {
|
if ((int)c < 0x20) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '\a': appendEscape(sb, 'a'); break;
|
case '\a': AppendEscape(sb, 'a'); break;
|
||||||
case '\b': appendEscape(sb, 'b'); break;
|
case '\b': AppendEscape(sb, 'b'); break;
|
||||||
case '\f': appendEscape(sb, 'f'); break;
|
case '\f': AppendEscape(sb, 'f'); break;
|
||||||
case '\n': appendEscape(sb, 'n'); break;
|
case '\n': AppendEscape(sb, 'n'); break;
|
||||||
case '\r': appendEscape(sb, 'r'); break;
|
case '\r': AppendEscape(sb, 'r'); break;
|
||||||
case '\t': appendEscape(sb, 't'); break;
|
case '\t': AppendEscape(sb, 't'); break;
|
||||||
case '\v': appendEscape(sb, 'v'); break;
|
case '\v': AppendEscape(sb, 'v'); break;
|
||||||
default:
|
default:
|
||||||
sb.Append(string.Format(@"\u{0:X4}", (int)c));
|
sb.Append(string.Format(@"\u{0:X4}", (int)c));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (c == '\\' || c == '"') {
|
else if (c == '\\' || c == '"') {
|
||||||
appendEscape(sb, c);
|
AppendEscape(sb, c);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
sb.Append(c);
|
sb.Append(c);
|
||||||
|
@ -95,12 +95,12 @@ namespace de4dot.code {
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string shellEscape(string s) {
|
public static string ShellEscape(string s) {
|
||||||
var sb = new StringBuilder(s.Length + 2);
|
var sb = new StringBuilder(s.Length + 2);
|
||||||
sb.Append('"');
|
sb.Append('"');
|
||||||
foreach (var c in s) {
|
foreach (var c in s) {
|
||||||
if (c == '"')
|
if (c == '"')
|
||||||
appendEscape(sb, c);
|
AppendEscape(sb, c);
|
||||||
else
|
else
|
||||||
sb.Append(c);
|
sb.Append(c);
|
||||||
}
|
}
|
||||||
|
@ -108,20 +108,20 @@ namespace de4dot.code {
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void appendEscape(StringBuilder sb, char c) {
|
static void AppendEscape(StringBuilder sb, char c) {
|
||||||
sb.Append('\\');
|
sb.Append('\\');
|
||||||
sb.Append(c);
|
sb.Append(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string removeNewlines(object o) {
|
public static string RemoveNewlines(object o) {
|
||||||
return removeNewlines(o.ToString());
|
return RemoveNewlines(o.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string removeNewlines(string s) {
|
public static string RemoveNewlines(string s) {
|
||||||
return s.Replace('\n', ' ').Replace('\r', ' ');
|
return s.Replace('\n', ' ').Replace('\r', ' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string getFullPath(string path) {
|
public static string GetFullPath(string path) {
|
||||||
try {
|
try {
|
||||||
return Path.GetFullPath(path);
|
return Path.GetFullPath(path);
|
||||||
}
|
}
|
||||||
|
@ -130,7 +130,7 @@ namespace de4dot.code {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string randomName(int min, int max) {
|
public static string RandomName(int min, int max) {
|
||||||
int numChars = random.Next(min, max + 1);
|
int numChars = random.Next(min, max + 1);
|
||||||
var sb = new StringBuilder(numChars);
|
var sb = new StringBuilder(numChars);
|
||||||
int numLower = 0;
|
int numLower = 0;
|
||||||
|
@ -150,26 +150,26 @@ namespace de4dot.code {
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string getBaseName(string name) {
|
public static string GetBaseName(string name) {
|
||||||
int index = name.LastIndexOf(Path.DirectorySeparatorChar);
|
int index = name.LastIndexOf(Path.DirectorySeparatorChar);
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
return name;
|
return name;
|
||||||
return name.Substring(index + 1);
|
return name.Substring(index + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string getDirName(string name) {
|
public static string GetDirName(string name) {
|
||||||
return Path.GetDirectoryName(name);
|
return Path.GetDirectoryName(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static string ourBaseDir = null;
|
static string ourBaseDir = null;
|
||||||
public static string getOurBaseDir() {
|
public static string GetOurBaseDir() {
|
||||||
if (ourBaseDir != null)
|
if (ourBaseDir != null)
|
||||||
return ourBaseDir;
|
return ourBaseDir;
|
||||||
return ourBaseDir = getDirName(typeof(Utils).Assembly.Location);
|
return ourBaseDir = GetDirName(typeof(Utils).Assembly.Location);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string getPathOfOurFile(string filename) {
|
public static string GetPathOfOurFile(string filename) {
|
||||||
return Path.Combine(getOurBaseDir(), filename);
|
return Path.Combine(GetOurBaseDir(), filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This fixes a mono (tested 2.10.5) String.StartsWith() bug. NB: stringComparison must be
|
// This fixes a mono (tested 2.10.5) String.StartsWith() bug. NB: stringComparison must be
|
||||||
|
@ -180,14 +180,14 @@ namespace de4dot.code {
|
||||||
return left.Substring(0, right.Length).Equals(right, stringComparison);
|
return left.Substring(0, right.Length).Equals(right, stringComparison);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string getAssemblySimpleName(string name) {
|
public static string GetAssemblySimpleName(string name) {
|
||||||
int i = name.IndexOf(',');
|
int i = name.IndexOf(',');
|
||||||
if (i < 0)
|
if (i < 0)
|
||||||
return name;
|
return name;
|
||||||
return name.Substring(0, i);
|
return name.Substring(0, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool pathExists(string path) {
|
public static bool PathExists(string path) {
|
||||||
try {
|
try {
|
||||||
return new DirectoryInfo(path).Exists;
|
return new DirectoryInfo(path).Exists;
|
||||||
}
|
}
|
||||||
|
@ -196,7 +196,7 @@ namespace de4dot.code {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool fileExists(string path) {
|
public static bool FileExists(string path) {
|
||||||
try {
|
try {
|
||||||
return new FileInfo(path).Exists;
|
return new FileInfo(path).Exists;
|
||||||
}
|
}
|
||||||
|
@ -205,7 +205,7 @@ namespace de4dot.code {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool compare(byte[] a, byte[] b) {
|
public static bool Compare(byte[] a, byte[] b) {
|
||||||
if (a.Length != b.Length)
|
if (a.Length != b.Length)
|
||||||
return false;
|
return false;
|
||||||
for (int i = 0; i < a.Length; i++) {
|
for (int i = 0; i < a.Length; i++) {
|
||||||
|
@ -215,7 +215,7 @@ namespace de4dot.code {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] readFile(string filename) {
|
public static byte[] ReadFile(string filename) {
|
||||||
// If the file is on the network, and we read more than 2MB, we'll read from the wrong
|
// If the file is on the network, and we read more than 2MB, we'll read from the wrong
|
||||||
// offset in the file! Tested: VMware 8, Win7 x64.
|
// offset in the file! Tested: VMware 8, Win7 x64.
|
||||||
const int MAX_BYTES_READ = 0x200000;
|
const int MAX_BYTES_READ = 0x200000;
|
||||||
|
|
|
@ -63,26 +63,26 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
||||||
|
|
||||||
public CliSecureRtType(ModuleDefMD module, CliSecureRtType oldOne) {
|
public CliSecureRtType(ModuleDefMD module, CliSecureRtType oldOne) {
|
||||||
this.module = module;
|
this.module = module;
|
||||||
cliSecureRtType = lookup(oldOne.cliSecureRtType, "Could not find CliSecureRt type");
|
cliSecureRtType = Lookup(oldOne.cliSecureRtType, "Could not find CliSecureRt type");
|
||||||
postInitializeMethod = lookup(oldOne.postInitializeMethod, "Could not find postInitializeMethod method");
|
postInitializeMethod = Lookup(oldOne.postInitializeMethod, "Could not find postInitializeMethod method");
|
||||||
initializeMethod = lookup(oldOne.initializeMethod, "Could not find initializeMethod method");
|
initializeMethod = Lookup(oldOne.initializeMethod, "Could not find initializeMethod method");
|
||||||
stringDecrypterMethod = lookup(oldOne.stringDecrypterMethod, "Could not find stringDecrypterMethod method");
|
stringDecrypterMethod = Lookup(oldOne.stringDecrypterMethod, "Could not find stringDecrypterMethod method");
|
||||||
loadMethod = lookup(oldOne.loadMethod, "Could not find loadMethod method");
|
loadMethod = Lookup(oldOne.loadMethod, "Could not find loadMethod method");
|
||||||
foundSig = oldOne.foundSig;
|
foundSig = oldOne.foundSig;
|
||||||
}
|
}
|
||||||
|
|
||||||
T lookup<T>(T def, string errorMessage) where T : class, ICodedToken {
|
T Lookup<T>(T def, string errorMessage) where T : class, ICodedToken {
|
||||||
return DeobUtils.lookup(module, def, errorMessage);
|
return DeobUtils.Lookup(module, def, errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void find(byte[] moduleBytes) {
|
public void Find(byte[] moduleBytes) {
|
||||||
if (cliSecureRtType != null)
|
if (cliSecureRtType != null)
|
||||||
return;
|
return;
|
||||||
if (find2())
|
if (Find2())
|
||||||
return;
|
return;
|
||||||
if (find3())
|
if (Find3())
|
||||||
return;
|
return;
|
||||||
findNativeCode(moduleBytes);
|
FindNativeCode(moduleBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
static readonly string[] requiredFields1 = new string[] {
|
static readonly string[] requiredFields1 = new string[] {
|
||||||
|
@ -101,23 +101,23 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
||||||
"System.Reflection.Assembly",
|
"System.Reflection.Assembly",
|
||||||
"System.Byte[]",
|
"System.Byte[]",
|
||||||
};
|
};
|
||||||
bool find2() {
|
bool Find2() {
|
||||||
foreach (var cctor in DeobUtils.getInitCctors(module, 3)) {
|
foreach (var cctor in DeobUtils.GetInitCctors(module, 3)) {
|
||||||
foreach (var calledMethod in DotNetUtils.getCalledMethods(module, cctor)) {
|
foreach (var calledMethod in DotNetUtils.GetCalledMethods(module, cctor)) {
|
||||||
var type = calledMethod.DeclaringType;
|
var type = calledMethod.DeclaringType;
|
||||||
if (type.IsPublic)
|
if (type.IsPublic)
|
||||||
continue;
|
continue;
|
||||||
var fieldTypes = new FieldTypes(type);
|
var fieldTypes = new FieldTypes(type);
|
||||||
if (!fieldTypes.exactly(requiredFields1) && !fieldTypes.exactly(requiredFields2) &&
|
if (!fieldTypes.Exactly(requiredFields1) && !fieldTypes.Exactly(requiredFields2) &&
|
||||||
!fieldTypes.exactly(requiredFields3) && !fieldTypes.exactly(requiredFields4))
|
!fieldTypes.Exactly(requiredFields3) && !fieldTypes.Exactly(requiredFields4))
|
||||||
continue;
|
continue;
|
||||||
if (!hasInitializeMethod(type, "_Initialize") && !hasInitializeMethod(type, "_Initialize64"))
|
if (!HasInitializeMethod(type, "_Initialize") && !HasInitializeMethod(type, "_Initialize64"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
stringDecrypterMethod = findStringDecrypterMethod(type);
|
stringDecrypterMethod = FindStringDecrypterMethod(type);
|
||||||
initializeMethod = calledMethod;
|
initializeMethod = calledMethod;
|
||||||
postInitializeMethod = findMethod(type, "System.Void", "PostInitialize", "()");
|
postInitializeMethod = FindMethod(type, "System.Void", "PostInitialize", "()");
|
||||||
loadMethod = findMethod(type, "System.IntPtr", "Load", "()");
|
loadMethod = FindMethod(type, "System.IntPtr", "Load", "()");
|
||||||
cliSecureRtType = type;
|
cliSecureRtType = type;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -126,7 +126,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool find3() {
|
bool Find3() {
|
||||||
foreach (var type in module.Types) {
|
foreach (var type in module.Types) {
|
||||||
if (type.Fields.Count != 1)
|
if (type.Fields.Count != 1)
|
||||||
continue;
|
continue;
|
||||||
|
@ -148,11 +148,11 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MethodDef findStringDecrypterMethod(TypeDef type) {
|
static MethodDef FindStringDecrypterMethod(TypeDef type) {
|
||||||
foreach (var method in type.Methods) {
|
foreach (var method in type.Methods) {
|
||||||
if (method.Body == null || !method.IsStatic)
|
if (method.Body == null || !method.IsStatic)
|
||||||
continue;
|
continue;
|
||||||
if (!DotNetUtils.isMethod(method, "System.String", "(System.String)"))
|
if (!DotNetUtils.IsMethod(method, "System.String", "(System.String)"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
return method;
|
return method;
|
||||||
|
@ -161,7 +161,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MethodDef findMethod(TypeDef type, string returnType, string name, string parameters) {
|
static MethodDef FindMethod(TypeDef type, string returnType, string name, string parameters) {
|
||||||
var methodName = returnType + " " + type.FullName + "::" + name + parameters;
|
var methodName = returnType + " " + type.FullName + "::" + name + parameters;
|
||||||
foreach (var method in type.Methods) {
|
foreach (var method in type.Methods) {
|
||||||
if (method.Body == null || !method.IsStatic)
|
if (method.Body == null || !method.IsStatic)
|
||||||
|
@ -175,8 +175,8 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool hasInitializeMethod(TypeDef type, string name) {
|
static bool HasInitializeMethod(TypeDef type, string name) {
|
||||||
var method = DotNetUtils.getPInvokeMethod(type, name);
|
var method = DotNetUtils.GetPInvokeMethod(type, name);
|
||||||
if (method == null)
|
if (method == null)
|
||||||
return false;
|
return false;
|
||||||
var sig = method.MethodSig;
|
var sig = method.MethodSig;
|
||||||
|
@ -190,17 +190,17 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool findNativeCode(byte[] moduleBytes) {
|
bool FindNativeCode(byte[] moduleBytes) {
|
||||||
var bytes = moduleBytes != null ? moduleBytes : DeobUtils.readModule(module);
|
var bytes = moduleBytes != null ? moduleBytes : DeobUtils.ReadModule(module);
|
||||||
using (var peImage = new MyPEImage(bytes))
|
using (var peImage = new MyPEImage(bytes))
|
||||||
return foundSig = MethodsDecrypter.detect(peImage);
|
return foundSig = MethodsDecrypter.Detect(peImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isAtLeastVersion50() {
|
public bool IsAtLeastVersion50() {
|
||||||
return DotNetUtils.hasPinvokeMethod(cliSecureRtType, "LoadLibraryA");
|
return DotNetUtils.HasPinvokeMethod(cliSecureRtType, "LoadLibraryA");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void findStringDecrypterMethod() {
|
public void FindStringDecrypterMethod() {
|
||||||
if (cliSecureRtType != null)
|
if (cliSecureRtType != null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -210,7 +210,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
||||||
if (type.Methods.Count != 1)
|
if (type.Methods.Count != 1)
|
||||||
continue;
|
continue;
|
||||||
var cs = type.Methods[0];
|
var cs = type.Methods[0];
|
||||||
if (!isOldStringDecrypterMethod(cs))
|
if (!IsOldStringDecrypterMethod(cs))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
cliSecureRtType = type;
|
cliSecureRtType = type;
|
||||||
|
@ -219,12 +219,12 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isOldStringDecrypterMethod(MethodDef method) {
|
static bool IsOldStringDecrypterMethod(MethodDef method) {
|
||||||
if (method == null || method.Body == null || !method.IsStatic)
|
if (method == null || method.Body == null || !method.IsStatic)
|
||||||
return false;
|
return false;
|
||||||
if (!DotNetUtils.isMethod(method, "System.String", "(System.String)"))
|
if (!DotNetUtils.IsMethod(method, "System.String", "(System.String)"))
|
||||||
return false;
|
return false;
|
||||||
if (!DeobUtils.hasInteger(method, 0xFF))
|
if (!DeobUtils.HasInteger(method, 0xFF))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -26,7 +26,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
||||||
: base(key) {
|
: base(key) {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void encrypt(ref uint rxl, ref uint rxr) {
|
protected override void Encrypt(ref uint rxl, ref uint rxr) {
|
||||||
uint xl = rxl, xr = rxr;
|
uint xl = rxl, xr = rxr;
|
||||||
for (int i = 0; i < 16; i++) {
|
for (int i = 0; i < 16; i++) {
|
||||||
xl ^= P[i];
|
xl ^= P[i];
|
||||||
|
@ -38,7 +38,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
||||||
rxl = xr ^ P[17];
|
rxl = xr ^ P[17];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void decrypt(ref uint rxl, ref uint rxr) {
|
protected override void Decrypt(ref uint rxl, ref uint rxr) {
|
||||||
uint xl = rxl, xr = rxr;
|
uint xl = rxl, xr = rxr;
|
||||||
for (int i = 17; i >= 2; i--) {
|
for (int i = 17; i >= 2; i--) {
|
||||||
xl ^= P[i];
|
xl ^= P[i];
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user