protected override void Handle(NetfuserEvent ev) { switch (ev) { case NetfuserEvent.InjectResources injr: Parallel.ForEach(_entries, e => e.Initialize()); injr.Add(_index); foreach (var embedding in _entries) { injr.Add(embedding.Resource); } break; case NetfuserEvent.InjectTypes inj: if (Name != NetfuserFactory.EmbedderIndexName) { break; } var ep = Context.MainSourceModule.EntryPoint; if (ep == null) { throw Context.Error("assemblies can be embedded only in executable target"); } inj.Add(RuntimeUtils.TypesToInject); var decompTypes = _entries.Select(e => e.Compression?.RuntimeDecompressorType) .Where(t => t != null).ToList(); if (decompTypes.Count > 0) { inj.Add(decompTypes); } var decryptTypes = _entries.Select(e => e.Encryption?.RuntimeDecryptorType) .Where(t => t != null).ToList(); if (decryptTypes.Count > 0) { inj.Add(decryptTypes); } Context.OfType <NetfuserEvent.CilBodyBuilding>().Where(me => me.Source == ep).Take(1).Subscribe(me => { if (!Context.MappedTypes.TryGetValue(typeof(EmbeddedAssemblyResolver).CreateKey(), out var mapping)) { return; } var bootstrap = mapping.Target.Methods.FirstOrDefault(m => m.IsStatic && !m.IsConstructor && !m.IsRuntimeSpecialName); var il = me.GetEmitter(); il.MainFragment.Instructions.Insert(0, Instruction.Create(OpCodes.Call, bootstrap)); var name = Context.MappedResources[DnextFactory.NewTypeKey(null, _index)].Target.Name; il.MainFragment.Instructions.Insert(0, Instruction.Create(OpCodes.Ldstr, name)); }); break; } }
/// <summary> /// Get the instance of <see cref="IILEmitter"/> for the body of the target method. /// <see cref="IILEmitter"/> should have all you need to inject code into the target method's body /// </summary> /// <param name="create">the default is <see langword="true"/>, meaning that new emitter will be created if there's none yet, /// set to <see langword="false"/> if you don't want to create new one if none exists, in this case <see langword="null"/> may be returned</param> /// <returns>instance of <see cref="IILEmitter"/></returns> public IILEmitter GetEmitter(bool create = true) { if (_emitter == null && create) { lock (this) if (_emitter == null) { _emitter = DnextFactory.NewILEmitter(Context.TargetModule, Importer, Fragment); } } return(_emitter); }
void MapForwardedTypes(IEnumerable <ModuleDef> modules) { foreach (var mod in modules) { foreach (var exp in mod.ExportedTypes) { if (exp.IsForwarder) { _forwardedTypes.Add(DnextFactory.NewTypeKey(mod, exp.FullName), exp.ToTypeRef()); } } } }
public Stream OpenReader() { var root = new XElement("index"); var doc = new XDocument(root); foreach (var embedding in _entries) { var res = embedding.Resource; var name = Context.MappedResources[DnextFactory.NewTypeKey(null, res)].Target.Name; var entry = new XElement("entry"); if (embedding.Properties != null) { foreach (var kv in embedding.Properties) { entry.SetAttributeValue(kv.Key, kv.Value); } } entry.SetAttributeValue(ResourceEntry.KeyName, embedding.Name); entry.SetAttributeValue(ResourceEntry.KeyResourceName, name); if (embedding.Compression != null) { if (!Context.MappedTypes.TryGetValue(embedding.Compression.RuntimeDecompressorType.CreateKey(), out var mapping)) { throw Context.Error("could not find decompressor type in target assembly"); } entry.SetAttributeValue(ResourceEntry.KeyCompression, mapping.Target.MDToken.Raw); } if (embedding.Encryption != null) { if (!Context.MappedTypes.TryGetValue(embedding.Encryption.RuntimeDecryptorType.CreateKey(), out var mapping)) { throw Context.Error("could not find decryptor type in target assembly"); } entry.SetAttributeValue(ResourceEntry.KeyEncryption, mapping.Target.MDToken.Raw); } root.Add(entry); } var ms = new MemoryStream(); using (var writer = new XmlTextWriter(new StreamWriter(ms, Encoding.UTF8, 16384, true))) doc.WriteTo(writer); ms.Position = 0; return(ms); }
public Expr(ICFMangleContext ctx) : base(ctx) { _invCompiled = new CilFragment(); _stateVar = new Local(ctx.Method.Module.CorLibTypes.Int32); var body = ctx.Method.Body; body.Variables.Add(_stateVar); body.InitLocals = true; var nm = new IntGenerator(ctx.Mangler.Rng, ctx.Mangler.Options.MaxMangleIterations); var codec = nm.Generate(); codec.ParameterResolver = p => p == nm.Argument ? _stateVar : null; _codec = codec; var emitter = DnextFactory.NewILEmitter(ctx.Method.Module, ctx.Importer, _invCompiled); codec.EmitDemangler(emitter); }
bool Emit(IILEmitter emitter, ref Local local, bool upper, bool invert, Instruction falseTarget) { var ic = upper ? _upper : _lower; if (!ic.HasValue) { return(false); } var c = Base.Lang.Ints.Const(ic.Value.Value, Bytes, Signed); var compiler = new ExprCompiler(emitter); if (invert) { if (local == null) { local = emitter.RequestTempLocal(c.Type); emitter.Stloc(local); } compiler.Compile(c); emitter.Ldloc(local); var op = DnextFactory.CondBranch(upper, !ic.Value.Inclusive, Signed); emitter.Emit(op, falseTarget); } else { if (local != null) { emitter.Ldloc(local); } compiler.Compile(c); var op = DnextFactory.CondBranch(!upper, !ic.Value.Inclusive, Signed); emitter.Emit(op, falseTarget); } return(true); }
internal void Run() { var target = Context.TargetModule; if (_source.HasResources) { foreach (var r in _source.Resources) { if (r is LinkedResource lr && Context.MappedResources.TryGetValue(DnextFactory.NewTypeKey(_source, r), out var mapping) && mapping.Target is LinkedResource tlr && tlr.File == lr.File) { tlr.File = Clone(lr.File); } } } if (_source == Context.MainSourceModule) { if (_source.Win32Resources != null) { target.Win32Resources = _source.Win32Resources; } var sourceAssembly = _source.Assembly; var targetAssembly = target.Assembly; CopyCustomAttributes(_source, target); CopyCustomAttributes(sourceAssembly, targetAssembly); CopyCustomDebugInfo(_source, target); CopyCustomDebugInfo(sourceAssembly, targetAssembly); CopyDeclSecurities(sourceAssembly, targetAssembly); if (_source.IsEntryPointValid) { target.EntryPoint = Importer.Import(_source.EntryPoint).ResolveMethodDef(); } } }
protected override void Handle(NetfuserEvent ev) { switch (ev) { case NetfuserEvent.Initialize _: if (Options.Generator == null) { Options.Generator = Context.DebugMode ? (NameGenerator) new NameGenerator.Debug() : new NameGenerator.Hash(); } break; case NetfuserEvent.TypeSkeletonsImported e: if ((_options.Type & MetaType.Method) != 0) { _nameChains = DnextFactory.BuildVNameChains(Context.Plugin <IVTablePlugin>().VTables, Context.MappedTypes.Values.Select(m => m.Source), m => !Context.MappedTypes.TryGetValue(m.DeclaringType.CreateKey(), out var tm) || DontRename(tm, m)); } // build scopes for types with preserved names first foreach (var tm in Context.MappedTypes.Values.Where(m => _ns.IsPreserved(m, MetaType.NamespaceAndType))) { Prepopulate(tm); } if (_options.NamespaceMangling == NamespaceMangling.Distribute) { var count = (int)Math.Sqrt(Context.MappedTypes.Count); for (var i = 0; i < count; i++) { GetNode(_root, null, i.ToString()); } } // build scopes for the remaining types and their preserved member names foreach (var tm in Context.MappedTypes.Values.Where(m => !_ns.IsPreserved(m, MetaType.NamespaceAndType))) { Prepopulate(tm); } if ((_options.Type & MetaType.Method) != 0) { // add virtual renamable methods before regular methods // we use fake scope here var scope = new MetadataElement(null, string.Empty); foreach (var c in _nameChains.All()) { if (!c.DontRename) { c.NewName = NameGenerator(scope, null, c.Name, n => MatchesTypeOrMemberName(c.Types, n)); } } } break; case NetfuserEvent.CreateMethod cm when(_options.Type& MetaType.Method) != 0: cm.Target.Name = GetMangledName(cm.TypeMapping, cm.Source); break; case NetfuserEvent.CreateField cm when(_options.Type& MetaType.Field) != 0: cm.Target.Name = GetMangledName(cm.TypeMapping, cm.Source); break; case NetfuserEvent.CreateProperty cm when(_options.Type& MetaType.Property) != 0: cm.Target.Name = GetMangledName(cm.TypeMapping, cm.Source); break; case NetfuserEvent.CreateEvent cm when(_options.Type& MetaType.Event) != 0: cm.Target.Name = GetMangledName(cm.TypeMapping, cm.Source); break; case NetfuserEvent.CreateMethodParameter cm when(_options.Type& MetaType.Method) != 0: // fast and easy way to check if we should rename parameter names: // if renaming didn't happen for this method, there's little sense to rename its parameters. // someone may even rely on parameter names [theoretically], as they are available via reflection // However, we allow one exception - RTSpecialNames (.ctors), as they are never renamed var method = cm.Source.DeclaringMethod; if (!method.IsRuntimeSpecialName && GetMangledName(cm.TypeMapping, method) == method.Name) { break; } cm.Target.Name = _options.Generator.Generate(this, cm.Source); break; case NetfuserEvent.CreateGenericParameter cm: method = cm.Source.DeclaringMethod; if (method != null) { if (!method.IsRuntimeSpecialName && GetMangledName(cm.TypeMapping, method) == method.Name) { break; } } else if (cm.Source.DeclaringType != null) { if (GetNode(cm.TypeMapping).NewName == cm.Source.DeclaringType.Name) { break; } } else { throw new NotSupportedException(); } cm.Target.Name = _options.Generator.Generate(this, cm.Source); break; case NetfuserEvent.ResourcesDeclared rde: var rs = new MetadataElement(null, string.Empty); var newNames = new HashSet <string>(Context.MappedResources.Values.Select(m => (string)m.Target.Name)); foreach (var rm in Context.MappedResources.Values.Where(m => !_ns.IsPreserved(m))) { var oldName = rm.Target.Name; var newName = NameGenerator(rs, null, rm.Source.Name, n => newNames.Contains(n)); if (newName != oldName) { newNames.Remove(oldName); newNames.Add(newName); rm.Target.Name = newName; } } break; } }
void MapResources(IEnumerable <ModuleDef> modules) { var resourcesByName = new Dictionary <string, Resource>(); foreach (var module in modules) { if (module.HasResources) { foreach (var source in module.Resources) { Import(module, source); } } } var inject = Fire(new NetfuserEvent.InjectResources(this)).Resources; foreach (var resource in inject) { Import(null, resource); } Fire(new NetfuserEvent.ResourcesDeclared(this)); void Import(ModuleDef module, Resource source) { string name; if (resourcesByName.TryGetValue(source.Name, out var target)) { name = Duplicate(module, source, target); } else { name = source.Name; } target = Fire(new NetfuserEvent.CreateResource(this, module, source) { Target = Clone(source) }).Target; _targetModule.Resources.Add(target); resourcesByName.Add(name, target); var key = DnextFactory.NewTypeKey(module, source); var tm = new ResourceMapping(module, source, target); _resourceMappings.Add(key, tm); Fire(new NetfuserEvent.ResourceMapped(this, tm)); } string Duplicate(ModuleDef sourceModule, Resource source, Resource target) { var ev = new NetfuserEvent.DuplicateResource(this, sourceModule, source, target); var c = 0; do { ev.RenameInto = source.Name + "_" + ++c; } while (resourcesByName.ContainsKey(ev.RenameInto)); Fire(ev); var result = ev.RenameInto; if (string.IsNullOrEmpty(result) || resourcesByName.ContainsKey(result)) { throw Error("resource name must be unique, non-null and non-empty"); } return(result); } Resource Clone(Resource source) { switch (source) { case EmbeddedResource er: return(er.SharedClone()); case AssemblyLinkedResource alr: return(new AssemblyLinkedResource(alr.Name, alr.Assembly, alr.Attributes)); case LinkedResource lr: // we will later replace the File property with the clone FileDef, unless someone else changes it return(new LinkedResource(lr.Name, lr.File, lr.Attributes)); } throw new NotSupportedException(); } }
public void Mangle(Block.Regular block) { var rng = _switch.Mangler.Rng; var fi = _context.RootBlock.FlowInfo.Info; var fragments = _context.SplitFragments(block); if (fragments.Count < 3) { return; } int i; var keyId = Enumerable.Range(0, fragments.Count).ToArray(); keyId.Shuffle(rng); var key = new int[keyId.Length]; for (i = 0; i < key.Length; i++) { var q = rng.NextInt32() & 0x7fffffff; key[i] = q - q % fragments.Count + keyId[i]; } var statementKeys = new Dictionary <Instruction, int>(); var current = fragments.First; i = 0; while (current != null) { if (i != 0) { statementKeys[current.Value.First] = key[i]; } i++; current = current.Next; } var lastInstructions = new HashSet <Instruction>(fragments.Select(f => f.Last())); var blockInstructions = new HashSet <Instruction>(block.Fragment); var firstFragmentInstructions = new HashSet <Instruction>(fragments.First()); bool HasUnknownSource(IEnumerable <Instruction> instrs) => instrs.Any(instr => { //return true; fi.TryGetValue(instr, out var info); if (info.RefCount > 1) { return(true); } Debug.Assert(info.RefCount == 1); var srcs = info.ReferencedBy; if (srcs.Count == 0) { return(false); } Debug.Assert(srcs.Count == 1); var src = srcs[0]; return // Target of switch => assume unknown (src.OpCode.Code == Code.Switch // Operand is Instruction[] // Not targeted by the last of statements || lastInstructions.Contains(src) // Not within current instruction block / targeted in first statement // || src.Offset <= fragments.First.Value.Last().Offset || src.Offset >= block.Fragment.Last().Offset || !blockInstructions.Contains(src) || firstFragmentInstructions.Contains(src)); }); var switchInstr = new Instruction(OpCodes.Switch); var switchHdr = new CilFragment(); if (_predicate != null) { switchHdr.Add(Instruction.CreateLdcI4(_predicate.GetSwitchKey(key[1]))); _predicate.EmitSwitchLoad(switchHdr); } else { switchHdr.Add(Instruction.CreateLdcI4(key[1])); } switchHdr.Add(Instruction.Create(OpCodes.Dup)); switchHdr.Add(Instruction.Create(OpCodes.Stloc, _local)); switchHdr.Add(Instruction.Create(OpCodes.Ldc_I4, fragments.Count)); switchHdr.Add(Instruction.Create(OpCodes.Rem_Un)); switchHdr.Add(switchInstr); _context.AddJump(switchHdr, fragments.Last.Value.First, true); var switchHdrSecond = switchHdr.Instructions[1]; var operands = new Instruction[fragments.Count]; current = fragments.First; i = 0; while (current.Next != null) { var newFragment = new CilFragment(current.Value); if (i != 0) { var lastInstr = newFragment.Last(); // Convert to switch var converted = false; fi.TryGetValue(lastInstr, out var info); if (lastInstr.IsBr()) { // Unconditional var target = (Instruction)lastInstr.Operand; if (info.ReferencedBy.Count == 0 && statementKeys.TryGetValue(target, out var brKey)) { var targetKey = _predicate?.GetSwitchKey(brKey) ?? brKey; var unkSrc = HasUnknownSource(newFragment); newFragment.Instructions.RemoveAt(newFragment.Instructions.Count - 1); if (unkSrc) { newFragment.Add(Instruction.Create(OpCodes.Ldc_I4, targetKey)); } else { var thisKey = key[i]; var r = rng.NextInt32(); newFragment.Add(Instruction.Create(OpCodes.Ldloc, _local)); newFragment.Add(Instruction.CreateLdcI4(r)); newFragment.Add(Instruction.Create(OpCodes.Mul)); newFragment.Add(Instruction.Create(OpCodes.Ldc_I4, (thisKey * r) ^ targetKey)); newFragment.Add(Instruction.Create(OpCodes.Xor)); } _context.AddJump(newFragment, switchHdrSecond, false); operands[keyId[i]] = newFragment.First; converted = true; } } else if (lastInstr.IsConditionalBranch()) { // Conditional var target = (Instruction)lastInstr.Operand; if (info.ReferencedBy.Count == 0 && statementKeys.TryGetValue(target, out var brKey)) { var unkSrc = HasUnknownSource(newFragment); var nextKey = key[i + 1]; var condBr = newFragment.Last().OpCode; newFragment.Instructions.RemoveAt(newFragment.Instructions.Count - 1); if (rng.NextBoolean()) { condBr = DnextFactory.InverseBranch(condBr); var tmp = brKey; brKey = nextKey; nextKey = tmp; } var thisKey = key[i]; int r = 0, xorKey = 0; if (!unkSrc) { r = rng.NextInt32(); xorKey = thisKey * r; } var brKeyInstr = Instruction.CreateLdcI4(xorKey ^ (_predicate?.GetSwitchKey(brKey) ?? brKey)); var nextKeyInstr = Instruction.CreateLdcI4(xorKey ^ (_predicate?.GetSwitchKey(nextKey) ?? nextKey)); var pop = Instruction.Create(OpCodes.Pop); newFragment.Add(Instruction.Create(condBr, brKeyInstr)); newFragment.Add(nextKeyInstr); newFragment.Add(Instruction.Create(OpCodes.Dup)); newFragment.Add(Instruction.Create(OpCodes.Br, pop)); newFragment.Add(brKeyInstr); newFragment.Add(Instruction.Create(OpCodes.Dup)); newFragment.Add(pop); if (!unkSrc) { newFragment.Add(Instruction.Create(OpCodes.Ldloc, _local)); newFragment.Add(Instruction.CreateLdcI4(r)); newFragment.Add(Instruction.Create(OpCodes.Mul)); newFragment.Add(Instruction.Create(OpCodes.Xor)); } _context.AddJump(newFragment, switchHdrSecond, false); operands[keyId[i]] = newFragment.First; converted = true; } } if (!converted) { // Normal var targetKey = _predicate?.GetSwitchKey(key[i + 1]) ?? key[i + 1]; if (!HasUnknownSource(newFragment)) { var thisKey = key[i]; var r = rng.NextInt32(); newFragment.Add(Instruction.Create(OpCodes.Ldloc, _local)); newFragment.Add(Instruction.CreateLdcI4(r)); newFragment.Add(Instruction.Create(OpCodes.Mul)); newFragment.Add(Instruction.Create(OpCodes.Ldc_I4, (thisKey * r) ^ targetKey)); newFragment.Add(Instruction.Create(OpCodes.Xor)); } else { newFragment.Add(Instruction.Create(OpCodes.Ldc_I4, targetKey)); } _context.AddJump(newFragment, switchHdrSecond, false); operands[keyId[i]] = newFragment.First; } } else { operands[keyId[i]] = switchHdr.First; } current.Value = newFragment; current = current.Next; i++; } operands[keyId[i]] = current.Value.First; switchInstr.Operand = operands; var first = fragments.First.Value; fragments.RemoveFirst(); var last = fragments.Last.Value; fragments.RemoveLast(); var newStatements = fragments.ToList(); newStatements.Shuffle(rng); block.Fragment.Reset(first.Concat(switchHdr).Concat(newStatements.SelectMany(s => s)).Concat(last)); }
protected override void Handle(NetfuserEvent ev) { var ns = Context.Plugin <INaming>(); switch (ev) { case NetfuserEvent.ResourceMapped cre: var rm = cre.Mapping; if (rm.SourceModule != null && rm.Source.ResourceType == ResourceType.Embedded) { var typeName = ParseName(rm.Source.Name); if (typeName != null) { _bySourceType.Add(DnextFactory.NewTypeKey(rm.SourceModule, typeName), new Res { Resource = (EmbeddedResource)rm.Target }); } ns.Preserve(rm); } break; case NameManglerEvent.GenerateName stnre: if (stnre.Options is NameGenerator.Encoded enc && stnre.Source is TypeDef td) { if (_bySourceType.TryGetValue(td.CreateKey(), out _)) { enc.Dictionary = ManglerCharsets.Latin; // before we generate new name for this type (which is going to be used to name our resource, // we need to make sure that it won't clash with any other type that has attached resource stnre.Avoid(BuildTypeNamesToAvoid()); } } break; case NetfuserEvent.TypeSkeletonsImported ite: foreach (var kv in _bySourceType) { if (Context.MappedTypes.TryGetValue(kv.Key, out var mapping)) { kv.Value.TargetType = mapping.Target; kv.Value.Resource.Name = mapping.Target.FullName + Suffix; } } break; case StringManglerEvent.WillMangle wme: if (wme.Method.ReturnType.FullName == typeof(System.Resources.ResourceManager).FullName && wme.Method.Body != null && _bySourceType.TryGetValue(wme.Method.DeclaringType.CreateKey(), out var r) && wme.String == wme.Method.DeclaringType.FullName) { wme.String = r.TargetType?.FullName; _bySourceType.Remove(wme.Method.DeclaringType.CreateKey()); } break; case NetfuserEvent.CilBodyBuilding cme: if (cme.Source.ReturnType.FullName == typeof(System.Resources.ResourceManager).FullName && cme.Source.Body != null && _bySourceType.TryGetValue(cme.Source.DeclaringType.CreateKey(), out var rr) && rr.TargetType != null) { var instr = cme.Fragment.Instructions.FirstOrDefault(i => i.OpCode == OpCodes.Ldstr && (string)i.Operand == cme.Source.DeclaringType.FullName); if (instr != null) { instr.Operand = rr.TargetType.FullName; } } break; } }
/// <summary> /// This runs block parser on the target method body and returns parsed blocks. /// See <see cref="DnextFactory.ParseBlocks"/> for details /// </summary> /// <returns>parsed blocks</returns> public Block.Root ParseBlocks() => DnextFactory.ParseBlocks(Fragment.Instructions, ExceptionHandlers);
internal VTablePlugin(IContextImpl context) : base(context) { VTables = DnextFactory.NewVTables(); }
MethodDef CreateFlagCtor(FlagDef flag, Func <MethodSig, bool> validator) { MethodSig sig; var cats = new List <Tuple <FieldDef, TypeSig> >(); var it = flag.Type; var sm = it.TypeMapping.Source.Module; do { var qarg = Rng.NextInt32(1, 5); cats.Add(Tuple.Create(flag.Field, flag.Field.FieldType)); var fq = new Queue <FieldDef>( it.TypeMapping.Source.Fields.Where(f => !f.IsStatic & !f.IsLiteral & !f.HasFieldRVA)); while (cats.Count < qarg) { if (fq.Count > 0) { var f = fq.Dequeue(); cats.Add(Tuple.Create(f, f.FieldType)); } else { cats.Add(Tuple.Create <FieldDef, TypeSig>(null, sm.CorLibTypes.Int32)); } } cats.Shuffle(Rng); var args = cats.Select(c => c.Item2).ToArray(); sig = MethodSig.CreateInstance(sm.CorLibTypes.Void, args); } while (!validator(sig)); var ctor = new MethodDefUser(".ctor", sig, MethodImplAttributes.IL | MethodImplAttributes.Managed, MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.Public) { Body = new CilBody { MaxStack = 8 } }; var i = 0; foreach (var t in cats) { ctor.ParamDefs.Add(new ParamDefUser("a" + (i++), (ushort)i)); } var sc = new SigComparer(); IMethod baseCtor; var bc = it.Base?.Ctors.RandomElementOrDefault(Rng); var emitter = DnextFactory.NewILEmitter(sm); emitter.Emit(OpCodes.Ldarg_0); if (bc != null) { foreach (var pd in bc.Parameters) { if (pd.IsNormalMethodParameter) { var f = ctor.Parameters.FirstOrDefault(p => p.IsNormalMethodParameter && sc.Equals(p.Type, pd.Type)); if (f != null && Rng.NextBoolean()) { emitter.Ldarg(f); } else { Utils.RandomConst(emitter, pd.Type, Rng); } } } baseCtor = bc; } else { baseCtor = new MemberRefUser(sm, ".ctor", MethodSig.CreateInstance(sm.CorLibTypes.Void), sm.CorLibTypes.Object.TypeRef); } emitter.Call(baseCtor); Parameter flagpar = null; foreach (var p in ctor.Parameters) { if (p.IsNormalMethodParameter) { var t = cats[p.Index - 1]; if (t.Item1 != null) { emitter.Emit(OpCodes.Ldarg_0); emitter.Ldarg(p); emitter.Emit(Instruction.Create(OpCodes.Stfld, t.Item1)); if (t.Item1 == flag.Field) { flagpar = p; } } } } emitter.Emit(OpCodes.Ret); emitter.Replace(ctor.Body); flag.SetCtor(ctor, flagpar); return(ctor); }