Немного подправил изначальный код Confuser'a.
И упростил вызов инжекта для каждого метода ( можно ещё упростить но лень )
P.S: Комментарии и.т.п вы можете найти в оригинальном проекте Confuser'a =) Убрал чтобы не мешались.
Создаём класс InjectContext.cs
Интерфейс IInjectContext:
Создадим класс InjectHelper.cs
Ну и на по следок сам класс который производит инжект Inject.cs
Используется очень просто:
На это всё)
Инжектор работает прекрасно, проверено лично =)
P.P.S: Оберните var module = ModuleDefMD.Load(File.ReadAllBytes(FileName)); в using ( )
примечание если вы используете выходные данные через ref или out то using нужно убрать и просто в конце записи добавить module.Dispose();
И упростил вызов инжекта для каждого метода ( можно ещё упростить но лень )
P.S: Комментарии и.т.п вы можете найти в оригинальном проекте Confuser'a =) Убрал чтобы не мешались.
Создаём класс InjectContext.cs
Код:
namespace ConfuserEx.PackEx.Injectors
{
using dnlib.DotNet;
using System.Collections.Generic;
internal class InjectContext : ImportResolver, IInjectContext
{
public readonly Dictionary<IDnlibDef, IDnlibDef> Map = new Dictionary<IDnlibDef, IDnlibDef>();
public readonly ModuleDef OriginModule, TargetModule;
public readonly Importer importer;
public InjectContext() { }
public InjectContext(ModuleDef module, ModuleDef target)
{
this.OriginModule = module;
this.TargetModule = target;
this.importer = new Importer(target, ImporterOptions.TryToUseTypeDefs)
{
Resolver = this
};
}
public InjectContext(Dictionary<IDnlibDef, IDnlibDef> map, ModuleDef originModule, ModuleDef targetModule, Importer importer)
{
this.Map = map;
this.OriginModule = originModule;
this.TargetModule = targetModule;
this.importer = importer;
}
public Importer Importer => this.importer;
public override TypeDef Resolve(TypeDef typeDef) => this.Map.ContainsKey(typeDef) ? (TypeDef)this.Map[typeDef] : null;
public override MethodDef Resolve(MethodDef methodDef) => this.Map.ContainsKey(methodDef) ? (MethodDef)this.Map[methodDef] : null;
public override FieldDef Resolve(FieldDef fieldDef) => this.Map.ContainsKey(fieldDef) ? (FieldDef)this.Map[fieldDef] : null;
}
}
Интерфейс IInjectContext:
Код:
namespace ConfuserEx.PackEx.Injectors
{
using dnlib.DotNet;
internal interface IInjectContext
{
Importer Importer { get; }
FieldDef Resolve(FieldDef fieldDef);
MethodDef Resolve(MethodDef methodDef);
TypeDef Resolve(TypeDef typeDef);
}
}
Создадим класс InjectHelper.cs
Код:
namespace ConfuserEx.PackEx.Injectors
{
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using System.Collections.Generic;
using System.Linq;
internal static partial class InjectHelper
{
private static TypeDefUser Clone(TypeDef origin)
{
var ret = new TypeDefUser(origin.Namespace, origin.Name)
{
Attributes = origin.Attributes
};
if (origin.ClassLayout != null)
{
ret.ClassLayout = new ClassLayoutUser(origin.ClassLayout.PackingSize, origin.ClassSize);
}
foreach (GenericParam genericParam in origin.GenericParameters)
{
ret.GenericParameters.Add(new GenericParamUser(genericParam.Number, genericParam.Flags, "-"));
}
return ret;
}
private static MethodDefUser Clone(MethodDef origin)
{
var ret = new MethodDefUser(origin.Name, null, origin.ImplAttributes, origin.Attributes);
foreach (GenericParam genericParam in origin.GenericParameters)
{
ret.GenericParameters.Add(new GenericParamUser(genericParam.Number, genericParam.Flags, "-"));
}
return ret;
}
private static FieldDefUser Clone(FieldDef origin)
{
var fieldDefUser = new FieldDefUser(origin.Name, null, origin.Attributes);
return fieldDefUser;
}
private static TypeDef PopulateContext(TypeDef typeDef, InjectContext ctx)
{
TypeDef ret;
if (!ctx.Map.TryGetValue(typeDef, out IDnlibDef existing))
{
ret = Clone(typeDef);
ctx.Map[typeDef] = ret;
}
else
{
ret = (TypeDef)existing;
}
foreach (TypeDef nestedType in typeDef.NestedTypes)
{
ret.NestedTypes.Add(PopulateContext(nestedType, ctx));
}
foreach (MethodDef method in typeDef.Methods)
{
ret.Methods.Add((MethodDef)(ctx.Map[method] = Clone(method)));
}
foreach (FieldDef field in typeDef.Fields)
{
ret.Fields.Add((FieldDef)(ctx.Map[field] = Clone(field)));
}
return ret;
}
private static void CopyTypeDef(TypeDef typeDef, InjectContext ctx)
{
var newTypeDef = (TypeDef)ctx.Map[typeDef];
newTypeDef.BaseType = (ITypeDefOrRef)ctx.Importer.Import(typeDef.BaseType);
foreach (InterfaceImpl iface in typeDef.Interfaces)
{
newTypeDef.Interfaces.Add(new InterfaceImplUser((ITypeDefOrRef)ctx.Importer.Import(iface.Interface)));
}
}
private static void CopyMethodDef(MethodDef methodDef, InjectContext ctx)
{
var newMethodDef = (MethodDef)ctx.Map[methodDef];
newMethodDef.Signature = ctx.Importer.Import(methodDef.Signature);
newMethodDef.Parameters.UpdateParameterTypes();
if (methodDef.ImplMap != null)
{
newMethodDef.ImplMap = new ImplMapUser(new ModuleRefUser(ctx.TargetModule, methodDef.ImplMap.Module.Name), methodDef.ImplMap.Name, methodDef.ImplMap.Attributes);
}
foreach (CustomAttribute ca in methodDef.CustomAttributes)
{
newMethodDef.CustomAttributes.Add(new CustomAttribute((ICustomAttributeType)ctx.Importer.Import(ca.Constructor)));
}
if (methodDef.HasBody)
{
newMethodDef.Body = new CilBody(methodDef.Body.InitLocals, new List<Instruction>(), new List<ExceptionHandler>(), new List<Local>());
newMethodDef.Body.MaxStack = methodDef.Body.MaxStack;
var bodyMap = new Dictionary<object, object>();
foreach (Local local in methodDef.Body.Variables)
{
var newLocal = new Local(ctx.Importer.Import(local.Type));
newMethodDef.Body.Variables.Add(newLocal);
newLocal.Name = local.Name;
newLocal.PdbAttributes = local.PdbAttributes;
bodyMap[local] = newLocal;
}
foreach (Instruction instr in methodDef.Body.Instructions)
{
var newInstr = new Instruction(instr.OpCode, instr.Operand)
{
SequencePoint = instr.SequencePoint
};
switch (newInstr.Operand)
{
case IType _:
newInstr.Operand = ctx.Importer.Import((IType)newInstr.Operand);
break;
case IMethod _:
newInstr.Operand = ctx.Importer.Import((IMethod)newInstr.Operand);
break;
case IField _:
newInstr.Operand = ctx.Importer.Import((IField)newInstr.Operand);
break;
default:
break;
}
newMethodDef.Body.Instructions.Add(newInstr);
bodyMap[instr] = newInstr;
}
foreach (Instruction instr in newMethodDef.Body.Instructions)
{
if (instr.Operand != null && bodyMap.ContainsKey(instr.Operand))
{
instr.Operand = bodyMap[instr.Operand];
}
else
{
if (instr.Operand is Instruction[])
{
instr.Operand = ((Instruction[])instr.Operand).Select(target => (Instruction)bodyMap[target]).ToArray();
}
}
}
foreach (ExceptionHandler eh in methodDef.Body.ExceptionHandlers)
{
newMethodDef.Body.ExceptionHandlers.Add(new ExceptionHandler(eh.HandlerType)
{
CatchType = eh.CatchType == null ? null : (ITypeDefOrRef)ctx.Importer.Import(eh.CatchType),
TryStart = (Instruction)bodyMap[eh.TryStart],
TryEnd = (Instruction)bodyMap[eh.TryEnd],
HandlerStart = (Instruction)bodyMap[eh.HandlerStart],
HandlerEnd = (Instruction)bodyMap[eh.HandlerEnd],
FilterStart = eh.FilterStart == null ? null : (Instruction)bodyMap[eh.FilterStart]
});
}
newMethodDef.Body.SimplifyMacros(newMethodDef.Parameters);
}
}
private static void CopyFieldDef(FieldDef fieldDef, InjectContext ctx) => ((FieldDef)ctx.Map[fieldDef]).Signature = ctx.Importer.Import(fieldDef.Signature);
private static void Copy(TypeDef typeDef, InjectContext ctx, bool copySelf)
{
if (copySelf)
{
CopyTypeDef(typeDef, ctx);
}
foreach (TypeDef nestedType in typeDef.NestedTypes)
{
Copy(nestedType, ctx, true);
}
foreach (MethodDef method in typeDef.Methods)
{
CopyMethodDef(method, ctx);
}
foreach (FieldDef field in typeDef.Fields)
{
CopyFieldDef(field, ctx);
}
}
public static TypeDef Inject(TypeDef typeDef, ModuleDef target)
{
var ctx = new InjectContext(typeDef.Module, target);
PopulateContext(typeDef, ctx);
Copy(typeDef, ctx, true);
return (TypeDef)ctx.Map[typeDef];
}
public static MethodDef Inject(MethodDef methodDef, ModuleDef target)
{
var ctx = new InjectContext(methodDef.Module, target);
ctx.Map[methodDef] = Clone(methodDef);
CopyMethodDef(methodDef, ctx);
return (MethodDef)ctx.Map[methodDef];
}
public static IEnumerable<IDnlibDef> Inject(TypeDef typeDef, TypeDef newType, ModuleDef target)
{
var ctx = new InjectContext(typeDef.Module, target);
ctx.Map[typeDef] = newType;
PopulateContext(typeDef, ctx);
Copy(typeDef, ctx, false);
return ctx.Map.Values.Except(new[] { newType });
}
}
}
Ну и на по следок сам класс который производит инжект Inject.cs
Код:
namespace ConfuserEx.PackEx.Injectors
{
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using System;
using System.Collections.Generic;
using System.Linq;
internal class Inject
{
public Inject(ModuleDef module, Type modclass, int metadatatoken, string method_inizialize)
{
using (var typeModule = ModuleDefMD.Load(modclass.Module)) // typeof(Ваш класс.cs)
{
MethodDef cctor = module.GlobalType.FindOrCreateStaticConstructor();
TypeDef typeDef = typeModule.ResolveTypeDef(MDToken.ToRID(metadatatoken)); // typeof(Ваш класс.cs).MetadataToken)
IEnumerable<IDnlibDef> members = InjectHelper.Inject(typeDef, module.GlobalType, module);
var init = (MethodDef)members.Single(method => method.Name.Equals(method_inizialize)); // "Метод который будет вызываться"
cctor.Body.Instructions.Insert(0, Instruction.Create(OpCodes.Call, init));
foreach (TypeDef type in module.Types)
{
if (type.IsGlobalModuleType)
{
continue;
}
foreach (MethodDef method in type.Methods)
{
if (!method.HasBody)
{
continue;
}
if (method.IsConstructor)
{
method.Body.Instructions.Insert(0, Instruction.Create(OpCodes.Nop));
method.Body.Instructions.Insert(0, Instruction.Create(OpCodes.Call, init));
}
}
}
foreach (MethodDef md in module.GlobalType.Methods)
{
if (md.Name != ".ctor")
{
continue;
}
module.GlobalType.Remove(md);
break;
}
}
}
}
}
Используется очень просто:
Код:
public void Run(string FileName)
{
var module = ModuleDefMD.Load(File.ReadAllBytes(FileName)); // Загружаем файл
new Inject(module, typeof(EOFAntitamp), typeof(EOFAntitamp).MetadataToken, "Initialize"); // Инжектим класс EOFAntitamp, добавляем метод "Inizialize" || EOFAntitamp - За место этого указывайте свой класс для инжекта.
// Настройки MWO ставьте под себя.
var MWO = new ModuleWriterOptions(module)
{
Logger = DummyLogger.NoThrowInstance
};
MWO.MetaDataOptions.Flags |= MetaDataFlags.AlwaysCreateGuidHeap | MetaDataFlags.PreserveTypeDefRids | MetaDataFlags.PreserveMemberRefRids;
MWO.PEHeadersOptions.Characteristics |= Characteristics.NetRunFromSwap | Characteristics.DebugStripped | Characteristics.BytesReversedLo;
MWO.AddCheckSum = true;
MWO.ShareMethodBodies = true;
module.Write(Путь куда сохранять.., MWO);
module.Dispose();
}
На это всё)
Инжектор работает прекрасно, проверено лично =)
P.P.S: Оберните var module = ModuleDefMD.Load(File.ReadAllBytes(FileName)); в using ( )
примечание если вы используете выходные данные через ref или out то using нужно убрать и просто в конце записи добавить module.Dispose();