一.C#-Harmony反射及动态注入
利用C#运行时环境的反射原理,实现对已加载DLL,未加载DLL中代码替换和前置后置插桩.
C#依赖库下载地址:
霸王•吕布 / CSharpHarmonyLib · GitCodehttps://gitcode.net/qq_35829452/csharpharmonylib
根据实际运行.Net环境选择对应版本的0Harmony.dll
二.csproj文件添加0Harmony.dll依赖
<1.使用dnspy确定当前游戏版本使用.NET运行时环境
<2.确定启动项为TaleWorlds.MountAndBlade.Launcher.exe
<3.csproj选择编译环境,依赖dll路径
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Version>0.0.1</Version>
<!--指定VS编译依赖.net2框架-->
<TargetFramework>netstandard2.0</TargetFramework>
<Platforms>x64</Platforms>
<!--指定游戏安装目录-->
<GameFolder>D:\work\Steam\steamapps\common\Mount & Blade II Bannerlord</GameFolder>
<GameBinariesFolder Condition="Exists('$(GameFolder)\bin\Win64_Shipping_Client\Bannerlord.exe')">Win64_Shipping_Client</GameBinariesFolder>
<GameBinariesFolder Condition="Exists('$(GameFolder)\bin\Gaming.Desktop.x64_Shipping_Client\Bannerlord.exe')">Gaming.Desktop.x64_Shipping_Client</GameBinariesFolder>
<!--指定输出dll名称,输出dll路径-->
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<AssemblyName>NativeTest</AssemblyName>
<OutputPath>D:\work\Steam\steamapps\common\Mount & Blade II Bannerlord\Modules\NativeTest\bin\Win64_Shipping_Client</OutputPath>
</PropertyGroup>
<!--指定使用C#接口-->
<ItemGroup>
<Reference Include="$(GameFolder)\bin\$(GameBinariesFolder)\Newtonsoft.Json.dll">
<HintPath>%(Identity)</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="$(GameFolder)\Modules\Harmony\bin\Win64_Shipping_Client\0Harmony.dll">
<HintPath>%(Identity)</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="$(GameFolder)\bin\$(GameBinariesFolder)\TaleWorlds.*.dll" Exclude="$(GameFolder)\bin\$(GameBinariesFolder)\TaleWorlds.Native.dll">
<HintPath>%(Identity)</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="$(GameFolder)\Modules\Native\bin\$(GameBinariesFolder)\*.dll">
<HintPath>%(Identity)</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="$(GameFolder)\Modules\SandBox\bin\$(GameBinariesFolder)\*.dll">
<HintPath>%(Identity)</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="$(GameFolder)\Modules\SandBoxCore\bin\$(GameBinariesFolder)\*.dll">
<HintPath>%(Identity)</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="$(GameFolder)\Modules\StoryMode\bin\$(GameBinariesFolder)\*.dll">
<HintPath>%(Identity)</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="$(GameFolder)\Modules\CustomBattle\bin\$(GameBinariesFolder)\*.dll">
<HintPath>%(Identity)</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="$(GameFolder)\Modules\BirthAndDeath\bin\$(GameBinariesFolder)\*.dll">
<HintPath>%(Identity)</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>
</Project>
三.SubModule.xml添加0Harmony.dll依赖
<!-- 对应bin\Win64_Shipping_Client下的MOD自定义DLL-->
<SubModules>
<SubModule>
<Name value="NativeTestSubModule" />
<DLLName value="NativeTest.dll" />
<SubModuleClassType value="NativeTest.NativeTest" />
<Assemblies>
<Assembly value="0Harmony.dll" />
</Assemblies>
<Tags>
<Tag key="DedicatedServerType" value ="none" />
</Tags>
</SubModule>
</SubModules>
四.Harmony实现对任意类任意方法的前置后置插桩
<1.MBSubModuleBase.OnSubModuleLoad()中进行Harmony注入
<2.实现Prefix,Postfix前置后置插桩,实现对本体代码的修改,例如游戏菜单的加载调用前插入一个对话框MsgBox
public class NativeTest : MBSubModuleBase
{
protected override void OnSubModuleLoad()
{
base.OnSubModuleLoad();
Harmony patch = new Harmony("MyPatch");
patch.PatchAll();
PrefixbBox();
}
}
#实现对游戏菜单初始化的前置插桩
namespace CampaignMissionPatch
{
[HarmonyPatch(typeof(EncounterGameMenuBehavior), "AddGameMenus")]
public class CampaignMissionPatch {
[DllImport("user32.dll", EntryPoint = "MessageBoxA")]
public static extern int MsgBox(int hWnd, string msg, string caption, int type);
public static bool Prefix(CampaignGameStarter gameSystemInitializer)
{
MsgBox(0, "this is conversation mission", "msg box", 0x30);
return true;
}
}
}