描述
对C#的类库可以动态编辑,并在保证不更改类库签名的情况下输出dll文件
操作类如下
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Cecil.Rocks;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace ModifyAssemblyDemo
{
internal class ILA
{
AssemblyDefinition currentASM;
TypeDefinition currentType;
MethodDefinition currentMethod;
ILProcessor ilPro;
Instruction currentIns;
public AssemblyDefinition CurrentASM { get => currentASM; set => currentASM = value; }
public TypeDefinition CurrentType { get => currentType; set => currentType = value; }
public MethodDefinition CurrentMethod { get => currentMethod; set => currentMethod = value; }
public ILProcessor IlPro { get => ilPro; set => ilPro = value; }
public Instruction CurrentIns { get => currentIns; set => currentIns = value; }
static List<AssemblyDefinition> assemblies = new List<AssemblyDefinition>();
private class CustomResolver : BaseAssemblyResolver
{
private DefaultAssemblyResolver _defaultResolver;
public CustomResolver()
{
_defaultResolver = new DefaultAssemblyResolver();
}
public override AssemblyDefinition Resolve(AssemblyNameReference name)
{
AssemblyDefinition assembly;
try
{
assembly = _defaultResolver.Resolve(name);
}
catch (AssemblyResolutionException ex)
{
assembly = assemblies.FirstOrDefault(u=>u.FullName.Equals(name.FullName));
}
return assembly;
}
}
public ILA(string path)
{
if (File.Exists(path))
{
currentASM = AssemblyDefinition.ReadAssembly(path,new ReaderParameters() { AssemblyResolver=new CustomResolver() });
string[] files = Directory.GetFiles(Path.GetDirectoryName(path));
//Task.Run(() =>
//{
//});
for (int i = 0; i < files.Length; i++)
{
try
{
var f = files[i];
var ex = Path.GetExtension(f);
if (!string.IsNullOrWhiteSpace(ex) && (ex.ToLower().Equals(".exe") || ex.ToLower().Equals(".dll")))
assemblies.Add(AssemblyDefinition.ReadAssembly(files[i]));
}
catch (Exception exception)
{
}
}
}
}
public ILA FM(Func<TypeDefinition, bool> typeWhere, Func<MethodDefinition, bool> methodType)
{
if (currentASM != null)
{
currentType = currentASM.MainModule.Types.First(typeWhere);
if (currentType != null)
{
currentMethod = currentType.GetMethods().First(methodType);
if (currentMethod != null)
ilPro = currentMethod.Body.GetILProcessor();
}
}
return this;
}
public ILA FI(Func<Instruction, bool> where)
{
if (currentMethod != null)
currentIns = currentMethod.Body.Instructions.First(where);
return this;
}
public ILA InsertAfter(OpCode codes)
{
if (ilPro != null)
{
var ins = ilPro.Create(codes);
ilPro.InsertAfter(currentIns, ins);
currentIns = ins;
}
return this;
}
public ILA InsertBefore(OpCode codes)
{
if (ilPro != null)
{
var ins = ilPro.Create(codes);
ilPro.InsertBefore(currentIns, ins);
currentIns = ins;
}
return this;
}
public ILA InsertAfter(OpCode codes, Func<ILA, object> func)
{
if (ilPro != null)
{
var obj = func(this);
if (obj != null)
{
var method = ilPro.GetType().GetMethod("Create", new Type[] { typeof(OpCode), obj.GetType() });
var ins = (Instruction)method.Invoke(ilPro, new object[] { codes, obj });
ilPro.InsertAfter(currentIns, ins);
currentIns = ins;
}
}
return this;
}
public ILA InsertBefore(OpCode codes, Func<ILA, object> func)
{
if (ilPro != null)
{
var obj = func(this);
if (obj != null)
{
var method = ilPro.GetType().GetMethod("Create", new Type[] { typeof(OpCode), obj.GetType() });
var ins = (Instruction)method.Invoke(ilPro, new object[] { codes, obj });
ilPro.InsertBefore(currentIns, ins);
currentIns = ins;
}
}
return this;
}
public TypeDefinition FT(Func<AssemblyDefinition, bool> assWhere, Func<TypeDefinition, bool> typeWhere)
{
var ass = assemblies.FirstOrDefault(assWhere);
if (ass != null)
{
return ass.MainModule.Types.FirstOrDefault(typeWhere);
}
return null;
}
//public ILA InsertAfter(params object[] paramList)
//{
// if (ilPro != null)
// {
// var types = Array.ConvertAll<object, Type>(paramList, new Converter<object, Type>(u => u.GetType()));
// var method = ilPro.GetType().GetMethod("Create", types);
// var ins = (Instruction)method.Invoke(ilPro, paramList);
// ilPro.InsertAfter(currentIns, ins);
// currentIns = ins;
// }
// return this;
//}
//public ILA InsertBefore(params object[] paramList)
//{
// if (ilPro != null)
// {
// var types = Array.ConvertAll<object, Type>(paramList, new Converter<object, Type>(u => u.GetType()));
// var method = ilPro.GetType().GetMethod("Create", types);
// var ins = (Instruction)method.Invoke(ilPro, paramList);
// ilPro.InsertBefore(currentIns, ins);
// currentIns = ins;
// }
// return this;
//}
public ILA Save(string path)
{
if (currentASM != null)
currentASM.Write(path);
return this;
}
}
}
调用代码
string path = AppDomain.CurrentDomain.BaseDirectory+ "Runtime\\";
string importDllPath = path+"test.dll";
string saveDllPath ="test_new.dll";
string className = "TConnection";
string methodName = "TExecute";
new ILA(importDllPath).
FM(u => u.Name.Equals(className), m => m.Name.Equals(methodName)).
FI(u => u.Offset == 0xC5).
InsertAfter(OpCodes.Ldsfld, asm => asm.CurrentType.Fields.Where(u => u.Name.Equals("Log")).First()).
InsertAfter(OpCodes.Ldstr, asm => "sqliteconnect:").
InsertAfter(OpCodes.Ldarg_0).
InsertAfter(OpCodes.Ldfld, asm=> asm.CurrentType.Fields.Where(u => u.Name.Equals("_connection")).First()).
InsertAfter(OpCodes.Callvirt, asm => asm.CurrentASM.MainModule.ImportReference(asm.FT(u=>u.FullName.Contains("System.Data.SQLite"),t=>t.Name.Equals("SQLiteConnection")).Properties.FirstOrDefault(p=>p.Name.Equals("ConnectionString")).GetMethod)).
//InsertAfter(OpCodes.Ldarg_0).
InsertAfter(OpCodes.Call, asm => asm.CurrentASM.MainModule.ImportReference(typeof(String).GetMethod("Concat", new Type[] { typeof(string), typeof(string) }))).
InsertAfter(OpCodes.Callvirt, asm => asm.CurrentASM.MainModule.ImportReference(asm.FT(u => u.FullName.Contains("OFX.Core.Contracts"), t => t.Name.Equals("ILog")).Methods.FirstOrDefault(m => m.Name.Equals("Debug") && m.Parameters != null && m.Parameters.Count == 1&&m.Parameters[0].ParameterType.FullName.Equals(typeof(object).FullName)))).
//InsertAfter(OpCodes.Ldarg_2).
InsertAfter(OpCodes.Nop).
Save(saveDllPath);