-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathInjectHelper.cs
More file actions
232 lines (194 loc) · 9.55 KB
/
InjectHelper.cs
File metadata and controls
232 lines (194 loc) · 9.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using System.Collections.Generic;
using System.Linq;
namespace kov.NET.Utils
{
/// <summary>
/// Provides methods to inject a <see cref="TypeDef" /> into another module.
/// </summary>
public static class InjectHelper
{
/// <summary>
/// Clones the specified origin TypeDef.
/// </summary>
/// <param name="origin">The origin TypeDef.</param>
/// <returns>The cloned TypeDef.</returns>
public static TypeDefUser Clone(TypeDef origin)
{
TypeDefUser 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;
}
/// <summary>
/// Clones the specified origin MethodDef.
/// </summary>
/// <param name="origin">The origin MethodDef.</param>
/// <returns>The cloned MethodDef.</returns>
public static MethodDefUser Clone(MethodDef origin)
{
MethodDefUser 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;
}
/// <summary>
/// Clones the specified origin FieldDef.
/// </summary>
/// <param name="origin">The origin FieldDef.</param>
/// <returns>The cloned FieldDef.</returns>
public static FieldDefUser Clone(FieldDef origin)
{
return new FieldDefUser(origin.Name, null, origin.Attributes);
}
/// <summary>
/// Populates the context mappings.
/// </summary>
/// <param name="typeDef">The origin TypeDef.</param>
/// <param name="ctx">The injection context.</param>
/// <returns>The new TypeDef.</returns>
public 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;
}
/// <summary>
/// Copies the information from the origin type to injected type.
/// </summary>
/// <param name="typeDef">The origin TypeDef.</param>
/// <param name="ctx">The injection context.</param>
public static void CopyTypeDef(TypeDef typeDef, InjectContext ctx)
{
TypeDef newTypeDef = (TypeDef)ctx.Map[typeDef];
newTypeDef.BaseType = ctx.Importer.Import(typeDef.BaseType);
foreach (InterfaceImpl iface in typeDef.Interfaces)
newTypeDef.Interfaces.Add(new InterfaceImplUser(ctx.Importer.Import(iface.Interface)));
}
/// <summary>
/// Copies the information from the origin method to injected method.
/// </summary>
/// <param name="methodDef">The origin MethodDef.</param>
/// <param name="ctx">The injection context.</param>
public static void CopyMethodDef(MethodDef methodDef, InjectContext ctx)
{
MethodDef 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;
Dictionary<object, object> bodyMap = new Dictionary<object, object>();
foreach (Local local in methodDef.Body.Variables)
{
Local newLocal = new Local(ctx.Importer.Import(local.Type));
newMethodDef.Body.Variables.Add(newLocal);
newLocal.Name = local.Name;
newLocal.Attributes = local.Attributes;
bodyMap[local] = newLocal;
}
foreach (Instruction instr in methodDef.Body.Instructions)
{
Instruction newInstr = new Instruction(instr.OpCode, instr.Operand)
{
SequencePoint = instr.SequencePoint
};
if (newInstr.Operand is IType)
newInstr.Operand = ctx.Importer.Import((IType)newInstr.Operand);
else if (newInstr.Operand is IMethod)
newInstr.Operand = ctx.Importer.Import((IMethod)newInstr.Operand);
else if (newInstr.Operand is IField)
newInstr.Operand = ctx.Importer.Import((IField)newInstr.Operand);
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 : 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);
}
}
/// <summary>
/// Copies the information from the origin field to injected field.
/// </summary>
/// <param name="fieldDef">The origin FieldDef.</param>
/// <param name="ctx">The injection context.</param>
public static void CopyFieldDef(FieldDef fieldDef, InjectContext ctx)
{
FieldDef newFieldDef = (FieldDef)ctx.Map[fieldDef];
newFieldDef.Signature = ctx.Importer.Import(fieldDef.Signature);
}
/// <summary>
/// Copies the information to the injected definitions.
/// </summary>
/// <param name="typeDef">The origin TypeDef.</param>
/// <param name="ctx">The injection context.</param>
/// <param name="copySelf">if set to <c>true</c>, copy information of <paramref name="typeDef" />.</param>
public 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);
}
/// <summary>
/// Injects the members of specified TypeDef to another module.
/// </summary>
/// <param name="typeDef">The source TypeDef.</param>
/// <param name="newType">The new type.</param>
/// <param name="target">The target module.</param>
/// <returns>Injected members.</returns>
public static IEnumerable<IDnlibDef> Inject(TypeDef typeDef, TypeDef newType, ModuleDef target)
{
InjectContext ctx = new InjectContext(typeDef.Module, target);
ctx.Map[typeDef] = newType;
PopulateContext(typeDef, ctx);
Copy(typeDef, ctx, false);
return ctx.Map.Values.Except(new[] { newType });
}
}
}