From e1a81d0b315f753ccc1bb7afa41d2dca68f9fee0 Mon Sep 17 00:00:00 2001 From: de4dot Date: Thu, 5 Jan 2012 16:21:02 +0100 Subject: [PATCH] Update stack emulation - Allow System.Object string decrypter return type - Fix for StackFrame.GetMethod() - Caller method is updated in stack frame --- AssemblyData/AssemblyService.cs | 9 +-- AssemblyData/DelegateStringDecrypter.cs | 2 +- AssemblyData/EmuStringDecrypter.cs | 3 +- AssemblyData/IAssemblyService.cs | 2 +- AssemblyData/IStringDecrypter.cs | 2 +- .../methodsrewriter/MethodsRewriter.cs | 63 +++++++++++++------ 6 files changed, 55 insertions(+), 26 deletions(-) diff --git a/AssemblyData/AssemblyService.cs b/AssemblyData/AssemblyService.cs index cda5cf6a..7f2ed648 100644 --- a/AssemblyData/AssemblyService.cs +++ b/AssemblyData/AssemblyService.cs @@ -76,16 +76,17 @@ namespace AssemblyData { var methodInfo = findMethod(methodToken); if (methodInfo == null) throw new ApplicationException(string.Format("Could not find method {0:X8}", methodToken)); - if (methodInfo.ReturnType != typeof(string)) - throw new ApplicationException(string.Format("Method return type must be string: {0}", methodInfo)); + if (methodInfo.ReturnType != typeof(string) && methodInfo.ReturnType != typeof(object)) + throw new ApplicationException(string.Format("Method return type must be string or object: {0}", methodInfo)); return stringDecrypter.defineStringDecrypter(methodInfo); } - public object[] decryptStrings(int stringDecrypterMethod, object[] args) { + public object[] decryptStrings(int stringDecrypterMethod, object[] args, int callerToken) { checkStringDecrypter(); + var caller = assembly.GetModules()[0].ResolveMethod(callerToken); foreach (var arg in args) SimpleData.unpack((object[])arg); - return SimpleData.pack(stringDecrypter.decryptStrings(stringDecrypterMethod, args)); + return SimpleData.pack(stringDecrypter.decryptStrings(stringDecrypterMethod, args, caller)); } public void exit() { diff --git a/AssemblyData/DelegateStringDecrypter.cs b/AssemblyData/DelegateStringDecrypter.cs index 81e2fa49..c82e8f39 100644 --- a/AssemblyData/DelegateStringDecrypter.cs +++ b/AssemblyData/DelegateStringDecrypter.cs @@ -32,7 +32,7 @@ namespace AssemblyData { return stringDecryptMethods.Count - 1; } - public object[] decryptStrings(int stringDecrypterMethod, object[] args) { + public object[] decryptStrings(int stringDecrypterMethod, object[] args, MethodBase caller) { if (stringDecrypterMethod > stringDecryptMethods.Count) throw new ApplicationException("Invalid string decrypter method"); diff --git a/AssemblyData/EmuStringDecrypter.cs b/AssemblyData/EmuStringDecrypter.cs index b949b0e2..8959f467 100644 --- a/AssemblyData/EmuStringDecrypter.cs +++ b/AssemblyData/EmuStringDecrypter.cs @@ -41,11 +41,12 @@ namespace AssemblyData { return decryptInfos.Count - 1; } - public object[] decryptStrings(int stringDecrypterMethod, object[] args) { + public object[] decryptStrings(int stringDecrypterMethod, object[] args, MethodBase caller) { var decryptInfo = decryptInfos[stringDecrypterMethod]; if (decryptInfo.decryptString == null) decryptInfo.decryptString = createDecryptString(decryptInfo.method); + methodsRewriter.setCaller(decryptInfo.decryptString, caller); var result = new object[args.Length]; for (int i = 0; i < args.Length; i++) result[i] = decryptInfo.decryptString((object[])args[i]); diff --git a/AssemblyData/IAssemblyService.cs b/AssemblyData/IAssemblyService.cs index bd3a1a31..605c8295 100644 --- a/AssemblyData/IAssemblyService.cs +++ b/AssemblyData/IAssemblyService.cs @@ -28,7 +28,7 @@ namespace AssemblyData { void loadAssembly(string filename); void setStringDecrypterType(StringDecrypterType type); int defineStringDecrypter(int methodToken); - object[] decryptStrings(int stringDecrypterMethod, object[] args); + object[] decryptStrings(int stringDecrypterMethod, object[] args, int callerToken); void exit(); } } diff --git a/AssemblyData/IStringDecrypter.cs b/AssemblyData/IStringDecrypter.cs index b909b297..2ef8fe3c 100644 --- a/AssemblyData/IStringDecrypter.cs +++ b/AssemblyData/IStringDecrypter.cs @@ -22,6 +22,6 @@ using System.Reflection; namespace AssemblyData { interface IStringDecrypter { int defineStringDecrypter(MethodInfo method); - object[] decryptStrings(int stringDecrypterMethod, object[] args); + object[] decryptStrings(int stringDecrypterMethod, object[] args, MethodBase caller); } } diff --git a/AssemblyData/methodsrewriter/MethodsRewriter.cs b/AssemblyData/methodsrewriter/MethodsRewriter.cs index c57246fe..fba99705 100644 --- a/AssemblyData/methodsrewriter/MethodsRewriter.cs +++ b/AssemblyData/methodsrewriter/MethodsRewriter.cs @@ -78,6 +78,7 @@ namespace AssemblyData.methodsrewriter { class MethodsRewriter : IMethodsRewriter { MethodsFinder methodsFinder = new MethodsFinder(); Dictionary realMethodToNewMethod = new Dictionary(); + Dictionary newStackMethodDict = new Dictionary(); List newMethodInfos = new List(); // There's no documented way to get a dynamic method's MethodInfo. If we name the @@ -163,6 +164,11 @@ namespace AssemblyData.methodsrewriter { return newMethodInfo.rewrittenMethod; } + public void setCaller(RewrittenMethod rewrittenMethod, MethodBase caller) { + var newMethodInfo = getNewMethodInfo(rewrittenMethod.Method.Name); + newStackMethodDict[newMethodInfo] = caller; + } + string getDelegateMethodName(MethodBase method) { string name = null; do { @@ -229,6 +235,12 @@ namespace AssemblyData.methodsrewriter { i += 2; continue; } + else if (MemberReferenceHelper.verifyType(ctor.DeclaringType, "mscorlib", "System.Diagnostics.StackFrame")) { + insertLoadThis(block, i + 1); + insertCallOurMethod(block, i + 2, "static_rtFixStackFrame"); + i += 2; + continue; + } } if (instr.OpCode == OpCodes.Call || instr.OpCode == OpCodes.Callvirt) { @@ -359,30 +371,45 @@ namespace AssemblyData.methodsrewriter { var newFrames = new List(frames.Length); foreach (var frame in frames) { - var method = frame.GetMethod(); - var info = getNewMethodInfo(method.Name); - if (info == null) { - newFrames.Add(frame); - } - else if (info.isRewrittenMethod(method.Name)) { - // Write random method from the same module - writeMethodBase(frame, methodsFinder.getMethod(info.oldMethod.Module)); - newFrames.Add(frame); - } - else if (info.isDelegateMethod(method.Name)) { - // Write original method - writeMethodBase(frame, info.oldMethod); - newFrames.Add(frame); - } - else { - throw new ApplicationException("BUG: Shouldn't be here"); - } + fixStackFrame(frame); + newFrames.Add(frame); } framesField.SetValue(stackTrace, newFrames.ToArray()); return stackTrace; } + static StackFrame static_rtFixStackFrame(StackFrame stackFrame, MethodsRewriter self) { + return self.rtFixStackFrame(stackFrame); + } + + StackFrame rtFixStackFrame(StackFrame frame) { + fixStackFrame(frame); + return frame; + } + + void fixStackFrame(StackFrame frame) { + var method = frame.GetMethod(); + var info = getNewMethodInfo(method.Name); + if (info == null) + return; + + MethodBase stackMethod; + if (newStackMethodDict.TryGetValue(info, out stackMethod)) { + writeMethodBase(frame, stackMethod); + } + else if (info.isRewrittenMethod(method.Name)) { + // Write random method from the same module + writeMethodBase(frame, methodsFinder.getMethod(info.oldMethod.Module)); + } + else if (info.isDelegateMethod(method.Name)) { + // Write original method + writeMethodBase(frame, info.oldMethod); + } + else + throw new ApplicationException("BUG: Shouldn't be here"); + } + // Called when the code calls GetCallingAssembly(), GetEntryAssembly(), or GetExecutingAssembly() Assembly rtGetAssembly(int delegateIndex) { return newMethodInfos[delegateIndex].oldMethod.Module.Assembly;