You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# Harmony补丁中如何比较CodeInstruction.Labels与已知Label值?

问题解答

明确一点:.NET原生的System.Reflection.Emit.Label没有直接从IL偏移量字符串(比如"IL_0067")创建实例的方法。因为Label是和特定ILGenerator绑定的不透明标识,内部关联的是IL生成过程中的位置信息,而非最终编译后的字符串偏移量。

要实现你替换IL指令的需求,得根据场景选择不同的解决方案:


场景1:动态生成IL(未完成编译)

如果正在用ILGenerator构建方法,直接通过标签定义和标记的方式绑定目标位置即可:

// 假设已有对应的ILGenerator实例
ILGenerator ilGen = ...;

// 先定义目标标签
Label targetLabel = ilGen.DefineLabel();

// 在IL_0067对应的指令位置(ldc.i4.8之前)标记标签
ilGen.MarkLabel(targetLabel);
ilGen.Emit(OpCodes.Ldc_I4_8);

// 回到IL_004e的位置,替换原ldstr指令为跳转指令
ilGen.Emit(OpCodes.Br_S, targetLabel); // 用短跳转匹配原代码的ble.s格式,偏移量较长时可改用Br

场景2:修改已编译的程序集

如果是修改已存在的编译后程序集,推荐使用dnlib、Mono.Cecil这类专门的IL编辑库,它们直接处理IL偏移量,不需要依赖System.Reflection.Emit.Label。以Mono.Cecil为例:

var module = ModuleDefinition.ReadModule("yourAssembly.dll");
var targetType = module.Types.First(t => t.Name == "classname");
var targetMethod = targetType.Methods.First(m => ...); // 定位到目标方法

// 找到IL_004e对应的指令(偏移量0x4e)
var instToReplace = targetMethod.Body.Instructions.First(inst => inst.Offset == 0x4e);
// 找到IL_0067对应的指令(偏移量0x67)作为跳转目标
var targetInst = targetMethod.Body.Instructions.First(inst => inst.Offset == 0x67);

// 替换指令为短跳转
instToReplace.OpCode = OpCodes.Br_S;
instToReplace.Operand = targetInst;

// 保存修改后的程序集
module.Write("modifiedAssembly.dll");

为什么不存在Label.FromString?

Label是ILGenerator在IL生成阶段维护的内部标记,它的有效性仅局限于当前正在构建的方法上下文。而IL偏移量(比如IL_0067)是IL生成完成后才确定的最终地址,两者没有直接的预映射关系,因此.NET原生框架不会提供从偏移量字符串创建Label的方法。

内容的提问来源于stack exchange,提问作者jmucchiello

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 20:03:24