Reputation: 265
I have two assemblies. "patchsrc.exe" and "Assembly-CSharp.dll"
I get all IL-instructions from patchsrc.exe::TXDLLLoader.Program::Main()
And all IL-instructions from Assembly-CSharp.dll::Class::Method()
I remove 'ret' opcode from first code and then merge them into one function.
When I try to save it, I get this:
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
I'm using this code:
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");
How can I resolve everything?
Upvotes: 1
Views: 665
Reputation: 244998
As explained in Cecil documentation on importing member references like the one to LoadFile()
that you're using are scoped to modules. If you want to use the reference in another module, you need to import it first. Since you don't know what instructions you'll encounter in patchsrc, you need to be able import any operands of any instruction. To do that, you can write a helper method:
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;
}
And then use it when adding patchsrc instructions:
foreach (var instruction in instrForPatch)
{
Console.WriteLine($"Adding instruction: [{instruction}]");
instr.Add(ImportInstruction(instruction, assembly.MainModule));
}
Upvotes: 2