C#-使用Harmony库实现DLL文件反射调用

一. Harmony工作原理

利用C#运行时Runtime的反射机制,动态加载dll中的方法,字段,属性,实现对DLL方法的重写和代码注入。

二. Harmony下载及安装

1.下载Harmony_lib库lib.harmony.2.3.3.nupkg

霸王•吕布 / CSharpHarmonyLib · GitCodehttps://gitcode.net/qq_35829452/csharpharmonylib 2.csproj添加reference引用

<Reference Include="0Harmony">
    <HintPath>..\..\Tool\C#\lib.harmony.2.3.3\lib\net48\0Harmony.dll</HintPath>
</Reference>

3.通过创建Harmony实例,调用PatchAll()方法实现补丁类的加载

#加载已经实现的补丁类,重写原有DLL中方法
var harmonyPatch = new Harmony("patch");
harmonyPatch.PatchAll();

三. Harmony前置插桩,后置插桩

通过在类实例上添加Harmony注解,实现补丁类,添加Prefix,Postfix实现对调用方法前,调用方法后的重写,返回值true/false决定原DLL方法是否被执行。

[HarmonyPatch(typeof(OriginalClass), "OriginalMethod")]
public class MyHarmonyPatch
{
    __instance获取类实例,___a获取实例变量
    public static bool Prefix(int ___a, string ___c, OriginalClass __instance)
    {
        // 在这里编写补丁的逻辑
        Console.WriteLine("Patched method called!");
        Console.WriteLine(___c);
        return true; // 返回false将阻止原方法执行
    }

    public static bool Postfix(string ___c)
    {
        // 在这里编写补丁的逻辑
        Console.WriteLine("Patched method called!");
        Console.WriteLine(___c);
        return true; // 返回false将阻止原方法执行
    }
}

public class OriginalClass
{
    int a = 10;

    int b = 20;

    string c = "abc";
    public void OriginalMethod()
    {
       Console.WriteLine("Original method called!");
    }

    public void OtherMethod()
    {
       Console.WriteLine("Other Method called!");
    }
}

四. Traverse访问私有属性&私有方法

#访问私有属性
OriginalClass originalClass = new OriginalClass();
string value = Traverse.Create(originalClass).Field("a").GetValue<int>() + "a";
Console.WriteLine(value);

#访问私有方法Method("12")
OriginalClass originalClass = new OriginalClass();
bool methodExisits = Traverse.Create(originalClass).Method("12").MethodExists();
Console.WriteLine(methodExisits);

五. AccessTool

使用AccessTool对类进行反射,动态调用目标类的方法。

#AccessTool反射调用目标dll方法
MethodInfo method = AccessTools.Method(typeof(OriginalClass), "OtherMethod");
method.Invoke(__instance, new object[0]);


#AccessTool反射调用目标dll属性字段
FieldInfo info = AccessTools.Field(typeof(OriginalClass), "b");
Console.WriteLine(info.GetValue(__instance));