假设我在第三方dll中有一个私有的,“实例”,非静态的bool方法。所有这个方法都返回一个值。没有其他的。我将如何拦截对此方法的调用,更改它的IL OpCodes /方法体,或将其重定向到额外的,重写或派生的方法。
我不想反编译第三方dll,手动更改源代码并重新编译它。 我也不想将程序集保存到磁盘,因为这也涉及使用“重新编译”的程序集而不是原始程序集。
我基本上希望能够使用原始dll - 没有替换或文件更改。我只是想做我上面提到的。
有什么方法可以解决这个问题吗?如果是这样,你可以详细说明或发布参考/教程/等。
另外,我知道虚拟,覆盖和新修饰符,但请记住我:没有所说的第三方dll的源代码,无法访问源代码,不想用dotPeek等反编译并重新编译。
谢谢!
编辑: 我忘了提到剩下的基础设施: MainProgram加载ThirdPartyDLL。 MainProgram还加载MyPluginDLL。 我正在尝试从MyPluginDLL更改ThirdPartyDLL中的方法,以便当MainProgram调用所述方法时,它将调用更改的方法。我希望能够在不保存新装配并使用新装配重新启动MainProgram的情况下执行此操作。基本上,我想在启动时或MainProgram运行时执行此操作。
答案 0 :(得分:4)
这是使用Mono Cecil更改内存中的程序集并在其上执行方法的代码示例。请注意,修改和保存程序集非常慢。这应该在您的应用程序启动时完成。
class Program
{
static void Main(string[] args)
{
Assembly assembly;
using (MemoryStream assemblyStream = new MemoryStream(File.ReadAllBytes("TargetDLL.dll")))
{
// 1. Get the reference to third-party method.
AssemblyDefinition assemblyDef = AssemblyDefinition.ReadAssembly(assemblyStream);
TypeDefinition targetDLLType = assemblyDef.Modules[0].GetType("TargetDLL.Foo");
MethodDefinition barMethod = targetDLLType.Methods[0];
// 2. Let's see what Foo.Bar returns...
assembly = Assembly.Load(assemblyStream.ToArray());
Console.WriteLine(CallMethod<int>(assembly.GetType("TargetDLL.Foo"), "Bar"));
// 3. Boot up the IL processor.
var processor = barMethod.Body.GetILProcessor();
// 4 View the unmodified IL.
Console.WriteLine("Original code");
PrintIL(processor);
// 5. Modify the code.
// 5.a Clear the method of all IL.
processor.Body.Instructions.Clear();
// 5.b Inject our custom return value.
processor.Emit(OpCodes.Ldc_I4, 1337);
processor.Emit(OpCodes.Ret);
// 6. And how does it look now?
Console.WriteLine();
Console.WriteLine("New code");
PrintIL(processor);
// 7. Save it.
assemblyDef.Write(assemblyStream);
assembly = Assembly.Load(assemblyStream.ToArray());
// 8. Result value.
Console.WriteLine(CallMethod<int>(assembly.GetType("TargetDLL.Foo"), "Bar"));
}
Console.WriteLine("END");
Console.ReadKey(true);
}
static void PrintIL(ILProcessor processor)
{
foreach (var instruction in processor.Body.Instructions)
{
Console.WriteLine(instruction);
}
}
static T CallMethod<T>(Type type, string method)
{
return (T)type.InvokeMember("Bar", BindingFlags.Static | BindingFlags.InvokeMethod | BindingFlags.Public, null, null,
null);
}
}
在同一目录中添加名为TargetDLL.dll的以下DLL。包含此代码:
namespace TargetDLL
{
public static class Foo
{
public static int Bar()
{
return 0;
}
}
}
修改强>
我认为你的错误与Mono.Cecil的版本有关。我正在使用master branch on GitHub中的 9.5.0 。下载ZIP文件并根据需要构建项目。