Recently I found an architect-often-used .net program has implemented a function wrongly. So I successfully patched it using ILSpy and Reflexil in a static way of modifying binaries. However, it is annoying that you need to patch it and remove StrongNameCheck again when new minor version releases. (btw, the author believes it is a feature instead of a bug)
Hopefully, the program fully supports assemblies as a plugin. And my target is a public non-static member function in a public class which can be directly called by plugins. Is there a way to patch the function on the fly?
I usually use some APIHook tricks in unmanaged C++ but dotnet is really a different thing. In this case, I want the modification still valid after my assembly unloads (so more similar to a patch, not a hook).
Yes you can do it with code injection. But you need to know some MSIL. There is also a library for that which is called Mono.Cecil.
Here is a example code
Console.WriteLine("> INJECTING INTO 12345.EXE..." + Environment.NewLine);
AssemblyDefinition asm = AssemblyDefinition.ReadAssembly(#"C:\dummy.exe");
var writeLineMethod = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) });
var writeLineRef = asm.MainModule.Import(writeLineMethod);
var pStartMethod = typeof(Process).GetMethod("Start", new Type[] { typeof(string) });
var pStartRef = asm.MainModule.Import(pStartMethod);
foreach (var typeDef in asm.MainModule.Types)
{
foreach (var method in typeDef.Methods)
{
//Let's push a string using the Ldstr Opcode to the stack
method.Body.Instructions.Insert(0, Instruction.Create(OpCodes.Ldstr, "INJECTED!"));
//We add the call to the Console.WriteLine() method. It will read from the stack
method.Body.Instructions.Insert(1, Instruction.Create(OpCodes.Call, writeLineRef));
//We push the path of the executable you want to run to the stack
method.Body.Instructions.Insert(2, Instruction.Create(OpCodes.Ldstr, #"calc.exe"));
//Adding the call to the Process.Start() method, It will read from the stack
method.Body.Instructions.Insert(3, Instruction.Create(OpCodes.Call, pStartRef));
//Removing the value from stack with pop
method.Body.Instructions.Insert(4, Instruction.Create(OpCodes.Pop));
}
}
asm.Write("12345.exe"); //Now we just save the new assembly
Don't monkey patch code. Add the functionality to your code base and call that function. Or write an adapter class that wraps the underlying assembly, which is much neater.
If the author of the code thinks it's not a bug then it may be in there for reasons you don't understand and could be part of any number of bug fixes.
Related
I am enjoying using G1ANT's "macros" capability to call unmanaged code, but the unmanaged objects are of course not being automatically garbage collected absent code to do it.
My request is specifically for best practices in disposing of unmanaged code in these G1ANT C# macros, not for disposing of the same in C# generally, and it is not a request to fix the code below, which runs as is just fine.
If I were coding in C# using Visual Studio, I would likely use a System.Runtime.InteropServices.SafeHandle class, override the Finalize method, or use one of the other approaches in common use (see also this post on disposing of unmanaged objects in C#).
But none of these approaches appear to be a good fit for G1ANT macros per se, at least with my novice experience of them.
For illustration purposes I'm referring to this G1ANT code, but WITHOUT the last line in the macro (ahk.Reset()), because it runs fine with that line, more than once. (I'm painfully aware that there must be a much better example, but as I'm new to G1ANT, this is the only thing I have so far.) What I'm after is C# code that works in G1ANT when there is no explicit disposal of the unmanaged object:
addon core version 4.100.19170.929
addon language version 4.100.19170.929
-dialog ♥macrodlls
♥macrodlls = System.dll,System.Drawing.dll,System.Windows.Forms.dll,AutoHotkey.Interop.dll,System.Runtime.InteropServices.dll
-dialog ♥macrodlls
♥macronamespaces = System,AutoHotkey.Interop,System.Windows.Forms
⊂
var ahk = AutoHotkeyEngine.Instance;
//Load a library or exec scripts in a file
ahk.LoadFile("functions.ahk");
//execute a specific function (found in functions.ahk), with 2 parameters
ahk.ExecFunction("MyFunction", "Hello", "World");
string sayHelloFunction = "SayHello(name) \r\n { \r\n MsgBox, Hello %name% \r\n return \r\n }";
ahk.ExecRaw(sayHelloFunction);
//execute's newly made function\
ahk.ExecRaw(#"SayHello(""Mario"") ");
var add5Results = ahk.ExecFunction("Add5", "5");
MessageBox.Show("ExecFunction: Result of 5 with Add5 func is" + add5Results);
addon core version 4.100.19170.929
addon language version 4.100.19170.929
-dialog ♥macrodlls
♥macrodlls = System.dll,System.Drawing.dll,System.Windows.Forms.dll,AutoHotkey.Interop.dll,System.Runtime.InteropServices.dll,System.Reflection.dll,Microsoft.CSharp.dll
-dialog ♥macrodlls
♥macronamespaces = System,AutoHotkey.Interop,System.Windows.Forms,System.Reflection
⊂
var ahk = AutoHotkeyEngine.Instance;
//Load a library or exec scripts in a file
ahk.LoadFile("functions.ahk");
//execute a specific function (found in functions.ahk), with 2 parameters
ahk.ExecFunction("MyFunction", "Hello", "World");
string sayHelloFunction = "SayHello(name) \r\n { \r\n MsgBox, Hello %name% \r\n return \r\n }";
ahk.ExecRaw(sayHelloFunction);
//executes new function
ahk.ExecRaw(#"SayHello(""Mario"") ");
var add5Results = ahk.ExecFunction("Add5", "5");
MessageBox.Show("ExecFunction: Result of 5 with Add5 func is" + add5Results);
ahk.Reset();
⊃
⊃
It's taken nearly verbatim from the AutoHotkey.Interop github page.
Without the last line in the macro ('ahk.Reset()), the code runs perfectly the first time through, but on the second run G1ANT still sees the included AutoHotkey file, and warns of duplicate function definitions, but continues and still functions properly. The as-far-as-I-can-tell-undocumented AutoHotkey.Interop command Reset() takes care of the garbage collection problem by calling
public void Terminate()
{
AutoHotkeyDll.ahkTerminate(1000);
}
public void Reset() {
Terminate();
AutoHotkeyDll.ahkReload();
AutoHotkeyDll.ahktextdll("", "", "");
}
Thus, the AutoHotkeyEngine instance itself appears to be garbage collected, even without the ahk.Reset();, but the AutoHotkey script it loads into an object is not.
Stopping the G1ANT.Robot application and restarting, then reloading the script above (as mentioned, without the line ahk.Reset();), works just fine, but once again only for a single run.
Edit: The given answer's advice on treatment of singletons is what I will use henceforth when loading of AutoHotkey function scripts and the DLL itself. It seems prudent and good practice to check to see if the DLL or function file have been loaded, whether problems exist or not. "An ounce of prevention", etc. In addition, I have forked the AutoHotkey.Interop repo here, adding a boolean check to see if the AutoHotkeyEngine instance is ready.
Best regards,
burque505
You use AutoHotkeyEngine.Instance, so I guess it's a singleton. It will stay loaded in memory as long as the corresponding dll is kept there, and the latter is loaded and lives as long as the its domain lives. The macro app domain (the place where script stuff is placed) currently lives as long as Robot's app domain, so in fact your singleton instance lives as long as Robot.
Either:
don't use singleton,
or reset it right after obtaining the instance (kinda what you already did),
or treat it as a singleton that has life span longer than your app. In this case after obtaining singleton instance do a check if your functions file has been already loaded and only load it if it wasn't done already.
I'm actually integrating the amazing RoslynPad into a WinForms application and working damn well.
The point of the integration is allowing the user to type in some C# code so it can be used in a future.
Thing is I'm interested on "capping" the user so he could just use some System or even LinQ functions. I don't want to allow the user to think he is allowed to use System.IO and others. Of course I can't prevent him/her typing System.IO.File.Delete, but will surely help if the System.IO's Assembly is not loaded into the RoslynPad's IntelliSense.
The source code typed by the user is going to be compiled locally before being saved into the DB. I'm adding just a few and necessary Assemblies for the compilation, so if System.IO it won't compile, of course.
As I explained, I just want to cap the Intellisense, so they don't think they have access to almost the whole .NET Framework.
EDIT: Added the actual implementation actually done. I'm loading "RoslynPad.Roslyn.Windows" and "RoslynPad.Editor.Windows" assemblies to the editor.
private RoslynCodeEditor _editor;
private void InitializeEditor(string sourceCode)
{
if (string.IsNullOrWhiteSpace(sourceCode))
sourceCode = string.Empty;
_editor = new RoslynCodeEditor();
var workingDirectory = Directory.GetCurrentDirectory();
var roslynHost = new RoslynHost(additionalAssemblies: new[]
{
Assembly.Load("RoslynPad.Roslyn.Windows"),
Assembly.Load("RoslynPad.Editor.Windows")
});
_editor.Initialize(roslynHost, new ClassificationHighlightColors(), workingDirectory, sourceCode);
_editor.FontFamily = new System.Windows.Media.FontFamily("Consolas");
_editor.SyntaxHighlighting = HighlightingManager.Instance.GetDefinition("C#");
_editor.FontSize = 12.75f;
elementHost1.Child = _editor;
this.Controls.Add(elementHost1);
}
You can use pass a RoslynHostReferences instance to the RoslynHost constructor, and decide which assemblies and namespaces are imported by default.
You could use the same logic as Default, just remove System.IO.Path from the type list.
Note that System.IO is not an assembly, but rather a namespace, which is in the core library, so there's no simple way to completely remove it.
I have a C# dll that references a 3rd party dll. There are different versions of the 3rd party dll.
As you might expect if the latest 3rd Party dll is present I want to use the new functionality if not I want to execute the old functionality.
I wasn't sure how to achieve this but I thought the first thing to try would be a simple if statement that decides which function to call.
So I find the assembly, get its location and hence its version info. (I need the file version as the product versions are the same).
Then a simple
if (version >= 3) do x() else do y()
When I execute the code on a machine with version 2 installed I get a MissingMethodException regarding x(). I thought I had made a stupid mistake but the logic was correct. The version is 2 so x(); should not be executed. I decided to remove the offending method and replace it with a throw new Exception(). The exception is not thrown and the code completes successfully.
Here is the danger - I am thinking that this is due to branch prediction. This is dangerous because it is not an area I have any knowledge of and therefore making assumptions is a dangerous thing.
So my questions are:
Am I tacking this problem the wrong way - is there a more obvious solution that I am missing?
or
Is there a way to disable branch prediction (if that is the cause) or to somehow enforce/flag the if condition as a point that must be executed before continuing.
Here is the code being executed:
On a machine with version 3 installed then it is fine.
On a machine with version 2 installed I get a MissingMethodException regarding method x().
It I removed the call to x(); and uncomment the throwing of the exception - no exception is thrown.
Relevant code:
Assembly assembly = System.Reflection.Assembly.GetAssembly(typeof(3rdPartyClass));
FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(assembly.Location);
if (fileVersionInfo.FileMajorPart >= 3)
{
// throw new Exception("aagghh");
x();
}
else
{
y();
}
Using reflection, it's possible to get a list of Methods available for a particular DLL (more specifically: Type).
You could use this methodinfo to dynamically invoke the method as specified in Vlad's solution.
In fact, you could leave out the version check and just try to find the intended method directly.
var methodX = assembly.GetType("sometype").GetMethod("X");
if (methodX != null)
{
methodX.Invoke(params);
}
else
{
assembly.GetType("sometype").GetMethod("Y").Invoke(otherParams);
}
Edit: This is not exactly what you want, but with this kind of reflection you can find the correct methods, also for your own assembly.
There is no "branch prediction": the runtime binding seems to happen as the method is executed.
So the workaround would be like this:
if (fileVersionInfo.FileMajorPart >= 3)
{
CallX();
}
else
{
CallY();
}
void CallX()
{
DependentClass.X();
}
void CallY()
{
DependentClass.Y();
}
However, anyway this seems to be a hack: you need to execute with the version of DLL you were linking against.
This is actually a more accurate answer :
Assembly assembly = System.Reflection.Assembly.GetAssembly(typeof(String));
FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(assembly.Location);
ObjectHandle oh = Activator.CreateInstanceFrom("AssemblyName.dll", "namespace.class");
object o = oh.Unwrap();
Type to = o.GetType();
if (fileVersionInfo.FileMajorPart >= 3)
{
to.InvokeMember("Method X", BindingFlags.InvokeMethod, null, o, null);
}
else
{
to.InvokeMember("Method Y", BindingFlags.InvokeMethod, null, o, null);
}
There is an application that checks for activation using DLL Check function. Check returns 1 if application is activated and 0 otherwise. I create simple application and DLL containing function MyCheck (which always returns 1) with the same signature and detoured Check function with my version using MS detours lib for function hooking. Obviously it works and the application is successfully cracked, so I need to avoid it.
I tried to call Check function directly (by specifying exact address), without even using GetProcAddress, but looks like detours lib is modifying the function body itself, not export table.
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate bool CheckFunctionDelegate();
static void Main(string[] args)
{
ProcessModule module = Process.GetCurrentProcess().Modules
.Cast<ProcessModule>()
.First(m => m.ModuleName == "licensing_check.dll");
IntPtr procedurePtr = IntPtr.Add(module.BaseAddress, 0x00003FF0);
// Calling validation function by pointer
CheckFunctionDelegate checkFunction = (CheckFunctionDelegate)
Marshal.GetDelegateForFunctionPointer(procedurePtr, typeof(CheckFunctionDelegate));
if (checkFunction())
{
// do some stuff
}
}
}
Then I tried to read function body and I see that after detour MD5 checksum differs from the original one. So I'm trying to read entire contents of DLL in memory and check it to confirm that DLL contents are not changed, but it doesn't work either. It throws AccessViolationException.
Process.EnterDebugMode();
ProcessModule module = Process.GetCurrentProcess().MainModule;
byte[] data = new byte[module.ModuleMemorySize];
Marshal.Copy(module.BaseAddress, data, 0, module.ModuleMemorySize);
I used MainModule here, but it gives the same error for each module in Process.GetCurrentProcess().Modules collection.
I would appreciate any help on this, I'm not necessarily expecting to solve it in one of the ways I describe, any good solution is acceptable.
Thanks.
I'm exposing a C# class to COM using these attributes:
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
[GuidAttribute("2325EBEB-DB5F-4D29-B220-64845379D9C5")]
[ComSourceInterfaces(typeof(WrapperEvents))]
in this class I have a function:
public void shutdownService()
This function is meant to be called just once from a VB6 client via COM Interop. Everything works fine. But somehow, it's being called more than once. My C# codes doesn't call this function directly. So I'm guessing the problem is in VB6 code. Unfortunately, that's not what the VB6 team thinks.
Is there a way to determine the caller of this function, ie. from my C#code or the VB6 code?
Right now I'm using a simple function to get the stacktrace:
public void LogStack()
{
var trace = new System.Diagnostics.StackTrace();
foreach (var frame in trace.GetFrames())
{
var method = frame.GetMethod();
if (method.Name.Equals("LogStack")) continue;
logger.Debug(string.Format("LogStack: {0}::{1}",
method.ReflectedType != null ? method.ReflectedType.Name : string.Empty, method.Name));
}
}
Obviously, I got somthing like this on the log:
2011-12-23 08:28:40,067 1 DEBUG (null) LogStack: Service::shutdownService
Since the only line of LogStack is the COM exposed function, I assume it's being called from vb6. But that's not enough proof for the VB6 team. Any idea how to really prove where function ?
You can try several things:
set a breakpoint in your code to trigger the debugger, then look at the call stack.
You could do an application dump here from visual studio and send it to them or screenshot the stack.
ex. Debugger.Break
http://www.netsplore.com/PublicPortal/blog.aspx?EntryID=12
Dump with "Savre Dump As"
http://msdn.microsoft.com/en-us/library/d5zhxt22.aspx
Use the com tracing
from a system level see
http://support.microsoft.com/kb/926098
I also recall a tool being installed with visual studio 6 do to this as well