保存程序集时 Mono.Cecil 中的 ArgumentException
ArgumentException in Mono.Cecil while saving assembly
我有两个程序集。 "patchsrc.exe" 和 "Assembly-CSharp.dll"
我从 patchsrc.exe::TXDLLLoader.Program::Main()
获得所有 IL 指令
以及来自 Assembly-CSharp.dll::Class::Method()
的所有 IL 指令
我从第一个代码中删除 'ret' 操作码,然后将它们合并到一个函数中。
当我尝试保存它时,我得到了这个:
An unhandled exception of type 'System.ArgumentException' occurred in Mono.Cecil.dll
Additional information: Member 'System.Reflection.Assembly
System.Reflection.Assembly::LoadFile(System.String)' is declared in another module and needs to be imported
我正在使用此代码:
var assembly = AssemblyDefinition.ReadAssembly("./game_Data/Managed/Assembly-CSharp.dll");
var assembly_patchsrc = AssemblyDefinition.ReadAssembly("./patchsrc.exe");
Console.WriteLine("searching..");
Collection<Instruction> instrForPatch = new Collection<Instruction>();
foreach (var methodDefinition in from type in assembly_patchsrc.MainModule.Types from methodDefinition in type.GetMethods() where methodDefinition.FullName.Contains("TXDLLLoader.Program::Main()") select methodDefinition)
{
Console.WriteLine("Found some patch instructions!");
var instr_patchsrc = methodDefinition.Body.Instructions;
instr_patchsrc.Remove(instr_patchsrc.Last());
for (var i = 0; i <= instr_patchsrc.Count - 1; i++)
{
instrForPatch.Add(instr_patchsrc[i]);
}
}
Console.ReadLine();
foreach (var instr in from typeDef in assembly.MainModule.Types
from method in typeDef.Methods
where typeDef.Name.Equals("Class") && method.Name.Equals("Method")
select method.Body.Instructions)
{
Collection<Instruction> oldList = new Collection<Instruction>();
for (var i = 0; i<=instr.Count-1; i++)
{
oldList.Add(instr[i]);
}
instr.Clear();
Console.WriteLine($"Begin injecting patch instructions.. [{instrForPatch.Count}]");
foreach (var instruction in instrForPatch)
{
Console.WriteLine($"Adding instruction: [{instruction}]");
instr.Add(instruction);
}
Console.WriteLine($"Begin injecting old instructions.. [{oldList.Count}]");
foreach (var instruction in oldList)
{
Console.WriteLine($"Adding instruction: [{instruction}]");
instr.Add(instruction);
}
Console.WriteLine("patched!");
}
Console.WriteLine("saving asssembly..");
assembly.Write("./game_Data/Managed/Assembly-CSharp_patched.dll");
我该如何解决所有问题?
如 Cecil documentation on importing 中所述,您正在使用的 LoadFile()
成员引用的范围仅限于模块。如果你想在另一个模块中使用引用,你需要先导入它。由于您不知道在 patchsrc 中会遇到什么指令,因此您需要能够导入任何指令的任何操作数。为此,您可以编写一个辅助方法:
static Instruction ImportInstruction(Instruction instruction, ModuleDefinition module)
{
object operand = instruction.Operand;
var fieldOperand = operand as FieldReference;
if (fieldOperand != null)
return Instruction.Create(instruction.OpCode, module.Import(fieldOperand));
var methodOperand = operand as MethodReference;
if (methodOperand != null)
return Instruction.Create(instruction.OpCode, module.Import(methodOperand));
var typeOperand = operand as TypeReference;
if (typeOperand != null)
return Instruction.Create(instruction.OpCode, module.Import(typeOperand));
return instruction;
}
然后在添加patchsrc指令时使用:
foreach (var instruction in instrForPatch)
{
Console.WriteLine($"Adding instruction: [{instruction}]");
instr.Add(ImportInstruction(instruction, assembly.MainModule));
}
我有两个程序集。 "patchsrc.exe" 和 "Assembly-CSharp.dll"
我从 patchsrc.exe::TXDLLLoader.Program::Main()
获得所有 IL 指令
以及来自 Assembly-CSharp.dll::Class::Method()
我从第一个代码中删除 'ret' 操作码,然后将它们合并到一个函数中。
当我尝试保存它时,我得到了这个:
An unhandled exception of type 'System.ArgumentException' occurred in Mono.Cecil.dll
Additional information: Member 'System.Reflection.Assembly System.Reflection.Assembly::LoadFile(System.String)' is declared in another module and needs to be imported
我正在使用此代码:
var assembly = AssemblyDefinition.ReadAssembly("./game_Data/Managed/Assembly-CSharp.dll");
var assembly_patchsrc = AssemblyDefinition.ReadAssembly("./patchsrc.exe");
Console.WriteLine("searching..");
Collection<Instruction> instrForPatch = new Collection<Instruction>();
foreach (var methodDefinition in from type in assembly_patchsrc.MainModule.Types from methodDefinition in type.GetMethods() where methodDefinition.FullName.Contains("TXDLLLoader.Program::Main()") select methodDefinition)
{
Console.WriteLine("Found some patch instructions!");
var instr_patchsrc = methodDefinition.Body.Instructions;
instr_patchsrc.Remove(instr_patchsrc.Last());
for (var i = 0; i <= instr_patchsrc.Count - 1; i++)
{
instrForPatch.Add(instr_patchsrc[i]);
}
}
Console.ReadLine();
foreach (var instr in from typeDef in assembly.MainModule.Types
from method in typeDef.Methods
where typeDef.Name.Equals("Class") && method.Name.Equals("Method")
select method.Body.Instructions)
{
Collection<Instruction> oldList = new Collection<Instruction>();
for (var i = 0; i<=instr.Count-1; i++)
{
oldList.Add(instr[i]);
}
instr.Clear();
Console.WriteLine($"Begin injecting patch instructions.. [{instrForPatch.Count}]");
foreach (var instruction in instrForPatch)
{
Console.WriteLine($"Adding instruction: [{instruction}]");
instr.Add(instruction);
}
Console.WriteLine($"Begin injecting old instructions.. [{oldList.Count}]");
foreach (var instruction in oldList)
{
Console.WriteLine($"Adding instruction: [{instruction}]");
instr.Add(instruction);
}
Console.WriteLine("patched!");
}
Console.WriteLine("saving asssembly..");
assembly.Write("./game_Data/Managed/Assembly-CSharp_patched.dll");
我该如何解决所有问题?
如 Cecil documentation on importing 中所述,您正在使用的 LoadFile()
成员引用的范围仅限于模块。如果你想在另一个模块中使用引用,你需要先导入它。由于您不知道在 patchsrc 中会遇到什么指令,因此您需要能够导入任何指令的任何操作数。为此,您可以编写一个辅助方法:
static Instruction ImportInstruction(Instruction instruction, ModuleDefinition module)
{
object operand = instruction.Operand;
var fieldOperand = operand as FieldReference;
if (fieldOperand != null)
return Instruction.Create(instruction.OpCode, module.Import(fieldOperand));
var methodOperand = operand as MethodReference;
if (methodOperand != null)
return Instruction.Create(instruction.OpCode, module.Import(methodOperand));
var typeOperand = operand as TypeReference;
if (typeOperand != null)
return Instruction.Create(instruction.OpCode, module.Import(typeOperand));
return instruction;
}
然后在添加patchsrc指令时使用:
foreach (var instruction in instrForPatch)
{
Console.WriteLine($"Adding instruction: [{instruction}]");
instr.Add(ImportInstruction(instruction, assembly.MainModule));
}