public override void ProcessCall(RPContext ctx, int instrIndex) { Instruction invoke = ctx.Body.Instructions[instrIndex]; var target = (IMethod)invoke.Operand; // Value type proxy is not supported in mild mode. if (target.DeclaringType.ResolveTypeDefThrow().IsValueType) return; // Skipping visibility is not supported in mild mode. if (!target.ResolveThrow().IsPublic && !target.ResolveThrow().IsAssembly) return; Tuple<Code, TypeDef, IMethod> key = Tuple.Create(invoke.OpCode.Code, ctx.Method.DeclaringType, target); MethodDef proxy; if (!proxies.TryGetValue(key, out proxy)) { MethodSig sig = CreateProxySignature(ctx, target, invoke.OpCode.Code == Code.Newobj); proxy = new MethodDefUser(ctx.Name.RandomName(), sig); proxy.Attributes = MethodAttributes.PrivateScope | MethodAttributes.Static; proxy.ImplAttributes = MethodImplAttributes.Managed | MethodImplAttributes.IL; ctx.Method.DeclaringType.Methods.Add(proxy); // Fix peverify --- Non-virtual call to virtual methods must be done on this pointer if (invoke.OpCode.Code == Code.Call && target.ResolveThrow().IsVirtual) { proxy.IsStatic = false; sig.HasThis = true; sig.Params.RemoveAt(0); } ctx.Marker.Mark(proxy, ctx.Protection); ctx.Name.Analyze(proxy); ctx.Name.SetCanRename(proxy, false); proxy.Body = new CilBody(); for (int i = 0; i < proxy.Parameters.Count; i++) proxy.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg, proxy.Parameters[i])); proxy.Body.Instructions.Add(Instruction.Create(invoke.OpCode, target)); proxy.Body.Instructions.Add(Instruction.Create(OpCodes.Ret)); proxies[key] = proxy; } invoke.OpCode = OpCodes.Call; if (ctx.Method.DeclaringType.HasGenericParameters) { var genArgs = new GenericVar[ctx.Method.DeclaringType.GenericParameters.Count]; for (int i = 0; i < genArgs.Length; i++) genArgs[i] = new GenericVar(i); invoke.Operand = new MemberRefUser( ctx.Module, proxy.Name, proxy.MethodSig, new GenericInstSig((ClassOrValueTypeSig)ctx.Method.DeclaringType.ToTypeSig(), genArgs).ToTypeDefOrRef()); } else invoke.Operand = proxy; var targetDef = target.ResolveMethodDef(); if (targetDef != null) ctx.Context.Annotations.Set(targetDef, ReferenceProxyProtection.Targeted, ReferenceProxyProtection.Targeted); }
protected static TypeDef GetDelegateType(RPContext ctx, MethodSig sig) { TypeDef ret; if (ctx.Delegates.TryGetValue(sig, out ret)) return ret; ret = new TypeDefUser(ctx.Name.ObfuscateName(ctx.Method.DeclaringType.Namespace, RenameMode.Unicode), ctx.Name.RandomName(), ctx.Module.CorLibTypes.GetTypeRef("System", "MulticastDelegate")); ret.Attributes = TypeAttributes.NotPublic | TypeAttributes.Sealed; var ctor = new MethodDefUser(".ctor", MethodSig.CreateInstance(ctx.Module.CorLibTypes.Void, ctx.Module.CorLibTypes.Object, ctx.Module.CorLibTypes.IntPtr)); ctor.Attributes = MethodAttributes.Assembly | MethodAttributes.HideBySig | MethodAttributes.RTSpecialName | MethodAttributes.SpecialName; ctor.ImplAttributes = MethodImplAttributes.Runtime; ret.Methods.Add(ctor); var invoke = new MethodDefUser("Invoke", sig.Clone()); invoke.MethodSig.HasThis = true; invoke.Attributes = MethodAttributes.Assembly | MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.NewSlot; invoke.ImplAttributes = MethodImplAttributes.Runtime; ret.Methods.Add(invoke); ctx.Module.Types.Add(ret); foreach (IDnlibDef def in ret.FindDefinitions()) { ctx.Marker.Mark(def); ctx.Name.SetCanRename(def, false); } ctx.Delegates[sig] = ret; return ret; }
public Instruction[] EmitDecode(MethodDef init, RPContext ctx, Instruction[] arg) { Tuple<MethodDef, Func<int, int>> key = GetKey(ctx, init); var repl = new List<Instruction>(); repl.AddRange(arg); repl.Add(Instruction.Create(OpCodes.Call, key.Item1)); return repl.ToArray(); }
public Instruction[] EmitDecode(MethodDef init, RPContext ctx, Instruction[] arg) { Tuple<Expression, Func<int, int>> key = GetKey(ctx, init); var invCompiled = new List<Instruction>(); new CodeGen(arg, ctx.Method, invCompiled).GenerateCIL(key.Item1); init.Body.MaxStack += (ushort)ctx.Depth; return invCompiled.ToArray(); }
private TypeDef GetKeyAttr(RPContext ctx) { if (keyAttrs == null) { keyAttrs = new Tuple <TypeDef, Func <int, int> > [0x10]; } int index = ctx.Random.NextInt32(keyAttrs.Length); if (keyAttrs[index] == null) { TypeDef rtType = ctx.Context.Registry.GetService <IRuntimeService>().GetRuntimeType("Confuser.Runtime.RefProxyKey"); TypeDef injectedAttr = InjectHelper.Inject(rtType, ctx.Module); injectedAttr.Name = ctx.Name.RandomName(); injectedAttr.Namespace = string.Empty; Expression expression, inverse; var var = new Variable("{VAR}"); var result = new Variable("{RESULT}"); ctx.DynCipher.GenerateExpressionPair( ctx.Random, new VariableExpression { Variable = var }, new VariableExpression { Variable = result }, ctx.Depth, out expression, out inverse); var expCompiled = new DMCodeGen(typeof(int), new[] { Tuple.Create("{VAR}", typeof(int)) }) .GenerateCIL(expression) .Compile <Func <int, int> >(); MethodDef ctor = injectedAttr.FindMethod(".ctor"); MutationHelper.ReplacePlaceholder(ctor, arg => { var invCompiled = new List <Instruction>(); new CodeGen(arg, ctor, invCompiled).GenerateCIL(inverse); return(invCompiled.ToArray()); }); keyAttrs[index] = Tuple.Create(injectedAttr, expCompiled); ctx.Module.AddAsNonNestedType(injectedAttr); foreach (IDnlibDef def in injectedAttr.FindDefinitions()) { if (def.Name == "GetHashCode") { ctx.Name.MarkHelper(def, ctx.Marker); ((MethodDef)def).Access = MethodAttributes.Public; } else { ctx.Name.MarkHelper(def, ctx.Marker); } } } return(keyAttrs[index].Item1); }
void ProcessBridge(RPContext ctx, int instrIndex) { Instruction instr = ctx.Body.Instructions[instrIndex]; var target = (IMethod)instr.Operand; TypeDef declType = target.DeclaringType.ResolveTypeDefThrow(); if (!declType.Module.IsILOnly) // Reflection doesn't like mixed mode modules. { return; } if (declType.IsGlobalModuleType) // Reflection doesn't like global methods too. { return; } Tuple <Code, IMethod, IRPEncoding> key = Tuple.Create(instr.OpCode.Code, target, ctx.EncodingHandler); Tuple <FieldDef, MethodDef> proxy; if (fields.TryGetValue(key, out proxy)) { if (proxy.Item2 != null) { instr.OpCode = OpCodes.Call; instr.Operand = proxy.Item2; return; } } else { proxy = new Tuple <FieldDef, MethodDef>(null, null); } MethodSig sig = CreateProxySignature(ctx, target, instr.OpCode.Code == Code.Newobj); TypeDef delegateType = GetDelegateType(ctx, sig); // Create proxy field if (proxy.Item1 == null) { proxy = new Tuple <FieldDef, MethodDef>( CreateField(ctx, delegateType), proxy.Item2); } // Create proxy bridge Debug.Assert(proxy.Item2 == null); proxy = new Tuple <FieldDef, MethodDef>( proxy.Item1, CreateBridge(ctx, delegateType, proxy.Item1, sig)); fields[key] = proxy; // Replace instruction instr.OpCode = OpCodes.Call; instr.Operand = proxy.Item2; }
Tuple <Expression, Func <int, int> > GetKey(RPContext ctx, MethodDef init) { if (!keys.TryGetValue(init, out var ret)) { Compile(ctx, init.Body, out var keyFunc, out var inverse); keys[init] = ret = Tuple.Create(inverse, keyFunc); } return(ret); }
Tuple <MethodDef, Func <int, int> > GetKey(RPContext ctx, MethodDef init) { if (!keys.TryGetValue(init, out var ret)) { Compile(ctx, out var keyFunc, out var native); keys[init] = ret = Tuple.Create(native, keyFunc); } return(ret); }
public Instruction[] EmitDecode(MethodDef init, RPContext ctx, Instruction[] arg) { Tuple <MethodDef, Func <int, int> > key = GetKey(ctx, init); var repl = new List <Instruction>(); repl.AddRange(arg); repl.Add(Instruction.Create(OpCodes.Call, key.Item1)); return(repl.ToArray()); }
public Instruction[] EmitDecode(MethodDef init, RPContext ctx, Instruction[] arg) { Tuple <Expression, Func <int, int> > key = GetKey(ctx, init); var invCompiled = new List <Instruction>(); new CodeGen(arg, ctx.Method, invCompiled).GenerateCIL(key.Item1); init.Body.MaxStack += (ushort)ctx.Depth; return(invCompiled.ToArray()); }
Tuple<Expression, Func<int, int>> GetKey(RPContext ctx, MethodDef init) { Tuple<Expression, Func<int, int>> ret; if (!keys.TryGetValue(init, out ret)) { Func<int, int> keyFunc; Expression inverse; Compile(ctx, init.Body, out keyFunc, out inverse); keys[init] = ret = Tuple.Create(inverse, keyFunc); } return ret; }
Tuple<MethodDef, Func<int, int>> GetKey(RPContext ctx, MethodDef init) { Tuple<MethodDef, Func<int, int>> ret; if (!keys.TryGetValue(init, out ret)) { Func<int, int> keyFunc; MethodDef native; Compile(ctx, out keyFunc, out native); keys[init] = ret = Tuple.Create(native, keyFunc); } return ret; }
static ITypeDefOrRef Import(RPContext ctx, TypeDef typeDef) { ITypeDefOrRef retTypeRef = new Importer(ctx.Module, ImporterOptions.TryToUseTypeDefs).Import(typeDef); if (typeDef.Module != ctx.Module && ctx.Context.Modules.Contains((ModuleDefMD)typeDef.Module)) { ctx.Name.AddReference(typeDef, new TypeRefReference((TypeRef)retTypeRef, typeDef)); } return(retTypeRef); }
void ProcessMethod(RPContext ctx) { for (int i = 0; i < ctx.Body.Instructions.Count; i++) { Instruction instr = ctx.Body.Instructions[i]; if (instr.OpCode.Code == Code.Call || instr.OpCode.Code == Code.Callvirt || instr.OpCode.Code == Code.Newobj) { var operand = (IMethod)instr.Operand; // Call constructor if (instr.OpCode.Code != Code.Newobj && operand.Name == ".ctor") { continue; } // Internal reference option if (operand is MethodDef && !ctx.InternalAlso) { continue; } // No generic methods if (operand is MethodSpec) { continue; } // No generic types / array types if (operand.DeclaringType is TypeSpec) { continue; } // No varargs if (operand.MethodSig.ParamsAfterSentinel != null && operand.MethodSig.ParamsAfterSentinel.Count > 0) { continue; } TypeDef declType = operand.DeclaringType.ResolveTypeDefThrow(); // No delegates if (declType.IsDelegate()) { continue; } // No instance value type methods if (declType.IsValueType && operand.MethodSig.HasThis) { return; } // No prefixed call if (i - 1 >= 0 && ctx.Body.Instructions[i - 1].OpCode.OpCodeType == OpCodeType.Prefix) { continue; } ctx.ModeHandler.ProcessCall(ctx, i); } } }
private Tuple<MethodDef, Func<int, int>> GetKey(RPContext ctx, MethodDef init) { Tuple<MethodDef, Func<int, int>> ret; if (!keys.TryGetValue(init, out ret)) { Func<int, int> keyFunc; MethodDef native; Compile(ctx, out keyFunc, out native); keys[init] = ret = Tuple.Create(native, keyFunc); } return ret; }
private Tuple <Expression, Func <int, int> > GetKey(RPContext ctx, MethodDef init) { Tuple <Expression, Func <int, int> > ret; if (!keys.TryGetValue(init, out ret)) { Func <int, int> keyFunc; Expression inverse; Compile(ctx, init.Body, out keyFunc, out inverse); keys[init] = ret = Tuple.Create(inverse, keyFunc); } return(ret); }
static int?TraceBeginning(RPContext ctx, int index, int argCount) { if (ctx.BranchTargets.Contains(ctx.Body.Instructions[index])) { return(null); } var currentStack = argCount; var currentIndex = index; while (currentStack > 0) { currentIndex--; var currentInstr = ctx.Body.Instructions[currentIndex]; // Disrupt stack analysis :/ Used by array initializer if (currentInstr.OpCode == OpCodes.Pop || currentInstr.OpCode == OpCodes.Dup) { return(null); } // No branch instr. switch (currentInstr.OpCode.FlowControl) { case FlowControl.Call: case FlowControl.Break: case FlowControl.Meta: case FlowControl.Next: break; default: return(null); } currentInstr.CalculateStackUsage(out var push, out var pop); currentStack += pop; currentStack -= push; // No branch target if (ctx.BranchTargets.Contains(currentInstr) && currentStack != 0) { return(null); } } if (currentStack < 0) { return(null); } return(currentIndex); }
public Instruction[] EmitDecode(MethodDef init, RPContext ctx, Instruction[] arg) { Tuple<int, int> key = GetKey(ctx.Random, init); var ret = new List<Instruction>(); if (ctx.Random.NextBoolean()) { ret.Add(Instruction.Create(OpCodes.Ldc_I4, key.Item1)); ret.AddRange(arg); } else { ret.AddRange(arg); ret.Add(Instruction.Create(OpCodes.Ldc_I4, key.Item1)); } ret.Add(Instruction.Create(OpCodes.Mul)); return ret.ToArray(); }
void Compile(RPContext ctx, CilBody body, out Func<int, int> expCompiled, out Expression inverse) { var var = new Variable("{VAR}"); var result = new Variable("{RESULT}"); Expression expression; ctx.DynCipher.GenerateExpressionPair( ctx.Random, new VariableExpression { Variable = var }, new VariableExpression { Variable = result }, ctx.Depth, out expression, out inverse); expCompiled = new DMCodeGen(typeof(int), new[] { Tuple.Create("{VAR}", typeof(int)) }) .GenerateCIL(expression) .Compile<Func<int, int>>(); }
InitMethodDesc GetInitMethod(RPContext ctx, IRPEncoding encoding) { InitMethodDesc[] initDescs; if (!inits.TryGetValue(encoding, out initDescs)) { inits[encoding] = initDescs = new InitMethodDesc[ctx.InitCount]; } int index = ctx.Random.NextInt32(initDescs.Length); if (initDescs[index] == null) { TypeDef rtType = ctx.Context.Registry.GetService <IRuntimeService>().GetRuntimeType("Confuser.Runtime.RefProxyStrong"); MethodDef injectedMethod = InjectHelper.Inject(rtType.FindMethod("Initialize"), ctx.Module); ctx.Module.GlobalType.Methods.Add(injectedMethod); injectedMethod.Access = MethodAttributes.PrivateScope; injectedMethod.Name = ctx.Name.RandomName(); ctx.Name.SetCanRename(injectedMethod, false); ctx.Marker.Mark(injectedMethod, ctx.Protection); var desc = new InitMethodDesc { Method = injectedMethod }; // Field name has five bytes, each bytes has different order & meaning int[] order = Enumerable.Range(0, 5).ToArray(); ctx.Random.Shuffle(order); desc.OpCodeIndex = order[4]; desc.TokenNameOrder = new int[4]; Array.Copy(order, 0, desc.TokenNameOrder, 0, 4); desc.TokenByteOrder = Enumerable.Range(0, 4).Select(x => x * 8).ToArray(); ctx.Random.Shuffle(desc.TokenByteOrder); var keyInjection = new int[9]; Array.Copy(desc.TokenNameOrder, 0, keyInjection, 0, 4); Array.Copy(desc.TokenByteOrder, 0, keyInjection, 4, 4); keyInjection[8] = desc.OpCodeIndex; MutationHelper.InjectKeys(injectedMethod, Enumerable.Range(0, 9).ToArray(), keyInjection); // Encoding MutationHelper.ReplacePlaceholder(injectedMethod, arg => { return(encoding.EmitDecode(injectedMethod, ctx, arg)); }); desc.Encoding = encoding; initDescs[index] = desc; } return(initDescs[index]); }
void Compile(RPContext ctx, out Func <int, int> expCompiled, out MethodDef native) { var var = new Variable("{VAR}"); var result = new Variable("{RESULT}"); var int32 = ctx.Module.CorLibTypes.Int32; native = new MethodDefUser(ctx.Context.Registry.GetService <INameService>().RandomName(), MethodSig.CreateStatic(int32, int32), MethodAttributes.PinvokeImpl | MethodAttributes.PrivateScope | MethodAttributes.Static) { ImplAttributes = MethodImplAttributes.Native | MethodImplAttributes.Unmanaged | MethodImplAttributes.PreserveSig }; ctx.Module.GlobalType.Methods.Add(native); ctx.Context.Registry.GetService <IMarkerService>().Mark(native, ctx.Protection); ctx.Context.Registry.GetService <INameService>().SetCanRename(native, false); x86Register?reg; var codeGen = new x86CodeGen(); Expression expression; do { ctx.DynCipher.GenerateExpressionPair( ctx.Random, new VariableExpression { Variable = var }, new VariableExpression { Variable = result }, ctx.Depth, out expression, out var inverse); reg = codeGen.GenerateX86(inverse, (v, r) => { return(new[] { x86Instruction.Create(x86OpCode.POP, new x86RegisterOperand(r)) }); }); } while (reg == null); var code = CodeGenUtils.AssembleCode(codeGen, reg.Value); expCompiled = new DMCodeGen(typeof(int), new[] { Tuple.Create("{VAR}", typeof(int)) }) .GenerateCIL(expression) .Compile <Func <int, int> >(); nativeCodes.Add(Tuple.Create(native, code, (MethodBody)null)); if (!addedHandler) { ctx.Context.CurrentModuleWriterListener.OnWriterEvent += InjectNativeCode; addedHandler = true; } }
protected static MethodSig CreateProxySignature(RPContext ctx, IMethod method, bool newObj) { ModuleDef module = ctx.Module; if (newObj) { Debug.Assert(method.MethodSig.HasThis); Debug.Assert(method.Name == ".ctor"); TypeSig[] paramTypes = method.MethodSig.Params.Select(type => { if (ctx.TypeErasure && type.IsClassSig && method.MethodSig.HasThis) { return(module.CorLibTypes.Object); } return(type); }).ToArray(); TypeSig retType; if (ctx.TypeErasure) // newobj will not be used with value types { retType = module.CorLibTypes.Object; } else { TypeDef declType = method.DeclaringType.ResolveTypeDefThrow(); retType = Import(ctx, declType).ToTypeSig(); } return(MethodSig.CreateStatic(retType, paramTypes)); } else { IEnumerable <TypeSig> paramTypes = method.MethodSig.Params.Select(type => { if (ctx.TypeErasure && type.IsClassSig && method.MethodSig.HasThis) { return(module.CorLibTypes.Object); } return(type); }); if (method.MethodSig.HasThis && !method.MethodSig.ExplicitThis) { TypeDef declType = method.DeclaringType.ResolveTypeDefThrow(); if (ctx.TypeErasure && !declType.IsValueType) { paramTypes = new[] { module.CorLibTypes.Object } }
void ProcessInvoke(RPContext ctx, int instrIndex, int argBeginIndex) { Instruction instr = ctx.Body.Instructions[instrIndex]; var target = (IMethod)instr.Operand; MethodSig sig = CreateProxySignature(ctx, target, instr.OpCode.Code == Code.Newobj); TypeDef delegateType = GetDelegateType(ctx, sig); Tuple <Code, IMethod, IRPEncoding> key = Tuple.Create(instr.OpCode.Code, target, ctx.EncodingHandler); Tuple <FieldDef, MethodDef> proxy; if (!fields.TryGetValue(key, out proxy)) { // Create proxy field proxy = new Tuple <FieldDef, MethodDef>(CreateField(ctx, delegateType), null); fields[key] = proxy; } // Insert field load & replace instruction if (argBeginIndex == instrIndex) { ctx.Body.Instructions.Insert(instrIndex + 1, new Instruction(OpCodes.Call, delegateType.FindMethod("Invoke"))); instr.OpCode = OpCodes.Ldsfld; instr.Operand = proxy.Item1; } else { Instruction argBegin = ctx.Body.Instructions[argBeginIndex]; ctx.Body.Instructions.Insert(argBeginIndex + 1, new Instruction(argBegin.OpCode, argBegin.Operand)); argBegin.OpCode = OpCodes.Ldsfld; argBegin.Operand = proxy.Item1; instr.OpCode = OpCodes.Call; instr.Operand = delegateType.FindMethod("Invoke"); } var targetDef = target.ResolveMethodDef(); if (targetDef != null) { ctx.Context.Annotations.Set(targetDef, ReferenceProxyProtection.Targeted, ReferenceProxyProtection.Targeted); } }
static RPContext ParseParameters(ModuleDef module, ConfuserContext context, ProtectionParameters parameters, RPStore store) { var ret = new RPContext(); ret.Depth = parameters.GetParameter(context, module, "depth", 3); ret.InitCount = parameters.GetParameter(context, module, "initCount", 0x10); ret.Random = store.random; ret.Module = module; ret.Context = context; ret.Marker = context.Registry.GetService <IMarkerService>(); ret.DynCipher = context.Registry.GetService <IDynCipherService>(); ret.Name = context.Registry.GetService <INameService>(); ret.Delegates = store.delegates; return(ret); }
public Instruction[] EmitDecode(MethodDef init, RPContext ctx, Instruction[] arg) { var key = GetKey(ctx.Random, init); var ret = new List <Instruction>(); if (ctx.Random.NextBoolean()) { ret.Add(Instruction.Create(OpCodes.Ldc_I4, key.Item1)); ret.AddRange(arg); } else { ret.AddRange(arg); ret.Add(Instruction.Create(OpCodes.Ldc_I4, key.Item1)); } ret.Add(Instruction.Create(OpCodes.Mul)); return(ret.ToArray()); }
void Compile(RPContext ctx, CilBody body, out Func <int, int> expCompiled, out Expression inverse) { var var = new Variable("{VAR}"); var result = new Variable("{RESULT}"); ctx.DynCipher.GenerateExpressionPair( ctx.Random, new VariableExpression { Variable = var }, new VariableExpression { Variable = result }, ctx.Depth, out var expression, out inverse); expCompiled = new DMCodeGen(typeof(int), new[] { Tuple.Create("{VAR}", typeof(int)) }) .GenerateCIL(expression) .Compile <Func <int, int> >(); }
protected static MethodSig CreateProxySignature(RPContext ctx, IMethod method, bool newObj) { ModuleDef module = ctx.Module; if (newObj) { Debug.Assert(method.MethodSig.HasThis); Debug.Assert(method.Name == ".ctor"); TypeSig[] paramTypes = method.MethodSig.Params.Select(type => { if (ctx.TypeErasure && type.IsClassSig && method.MethodSig.HasThis) return module.CorLibTypes.Object; return type; }).ToArray(); TypeSig retType; if (ctx.TypeErasure) // newobj will not be used with value types retType = module.CorLibTypes.Object; else { TypeDef declType = method.DeclaringType.ResolveTypeDefThrow(); retType = Import(ctx, declType).ToTypeSig(); } return MethodSig.CreateStatic(retType, paramTypes); } else { IEnumerable<TypeSig> paramTypes = method.MethodSig.Params.Select(type => { if (ctx.TypeErasure && type.IsClassSig && method.MethodSig.HasThis) return module.CorLibTypes.Object; return type; }); if (method.MethodSig.HasThis && !method.MethodSig.ExplicitThis) { TypeDef declType = method.DeclaringType.ResolveTypeDefThrow(); if (ctx.TypeErasure && !declType.IsValueType) paramTypes = new[] { module.CorLibTypes.Object }.Concat(paramTypes); else paramTypes = new[] { Import(ctx, declType).ToTypeSig() }.Concat(paramTypes); } TypeSig retType = method.MethodSig.RetType; if (ctx.TypeErasure && retType.IsClassSig) retType = module.CorLibTypes.Object; return MethodSig.CreateStatic(retType, paramTypes.ToArray()); } }
public override void Finalize(RPContext ctx) { foreach (var field in fields) { InitMethodDesc init = GetInitMethod(ctx, field.Key.Item3); byte opKey; do { // No zero bytes opKey = ctx.Random.NextByte(); } while (opKey == (byte)field.Key.Item1); TypeDef delegateType = field.Value.Item1.DeclaringType; MethodDef cctor = delegateType.FindOrCreateStaticConstructor(); cctor.Body.Instructions.Insert(0, Instruction.Create(OpCodes.Call, init.Method)); cctor.Body.Instructions.Insert(0, Instruction.CreateLdcI4(opKey)); cctor.Body.Instructions.Insert(0, Instruction.Create(OpCodes.Ldtoken, field.Value.Item1)); fieldDescs.Add(new FieldDesc { Field = field.Value.Item1, OpCode = field.Key.Item1, Method = field.Key.Item2, OpKey = opKey, InitDesc = init }); } foreach (TypeDef delegateType in ctx.Delegates.Values) { MethodDef cctor = delegateType.FindOrCreateStaticConstructor(); ctx.Marker.Mark(cctor, ctx.Protection); ctx.Name.SetCanRename(cctor, false); } ctx.Context.CurrentModuleWriterOptions.MetaDataOptions.Flags |= MetaDataFlags.PreserveExtraSignatureData; ctx.Context.CurrentModuleWriterListener.OnWriterEvent += EncodeField; encodeCtx = ctx; }
protected override void Execute(ConfuserContext context, ProtectionParameters parameters) { RandomGenerator random = context.Registry.GetService <IRandomService>().GetRandomGenerator(ReferenceProxyProtection._FullId); var store = new RPStore { random = random }; foreach (MethodDef method in parameters.Targets.OfType <MethodDef>().WithProgress(context.Logger)) { if (method.HasBody && method.Body.Instructions.Count > 0) { ProcessMethod(ParseParameters(method, context, parameters, store)); context.CheckCancellation(); } } RPContext ctx = ParseParameters(context.CurrentModule, context, parameters, store); store.mild?.Finalize(ctx); store.strong?.Finalize(ctx); }
FieldDef CreateField(RPContext ctx, TypeDef delegateType) { // Details will be filled in during metadata writing TypeDef randomType; do { randomType = ctx.Module.Types[ctx.Random.NextInt32(ctx.Module.Types.Count)]; } while (randomType.HasGenericParameters || randomType.IsGlobalModuleType || randomType.IsDelegate()); TypeSig fieldType = new CModOptSig(randomType, delegateType.ToTypeSig()); var field = new FieldDefUser("", new FieldSig(fieldType), FieldAttributes.Static | FieldAttributes.Assembly); field.CustomAttributes.Add(new CustomAttribute(GetKeyAttr(ctx).FindInstanceConstructors().First())); delegateType.Fields.Add(field); ctx.Marker.Mark(field, ctx.Protection); ctx.Name.SetCanRename(field, false); return(field); }
public override void ProcessCall(RPContext ctx, int instrIndex) { Instruction invoke = ctx.Body.Instructions[instrIndex]; TypeDef declType = ((IMethod)invoke.Operand).DeclaringType.ResolveTypeDefThrow(); if (!declType.Module.IsILOnly) // Reflection doesn't like mixed mode modules. return; if (declType.IsGlobalModuleType) // Reflection doesn't like global methods too. return; int push, pop; invoke.CalculateStackUsage(out push, out pop); int? begin = TraceBeginning(ctx, instrIndex, pop); // Fail to trace the arguments => fall back to bridge method bool fallBack = begin == null; if (fallBack) { ProcessBridge(ctx, instrIndex); } else { ProcessInvoke(ctx, instrIndex, begin.Value); } }
protected static TypeDef GetDelegateType(RPContext ctx, MethodSig sig) { if (ctx.Delegates.TryGetValue(sig, out var ret)) { return(ret); } ret = new TypeDefUser(ctx.Name.ObfuscateName(ctx.Method.DeclaringType.Namespace, RenameMode.Unicode), ctx.Name.RandomName(), ctx.Module.CorLibTypes.GetTypeRef("System", "MulticastDelegate")) { Attributes = TypeAttributes.NotPublic | TypeAttributes.Sealed }; var ctor = new MethodDefUser(".ctor", MethodSig.CreateInstance(ctx.Module.CorLibTypes.Void, ctx.Module.CorLibTypes.Object, ctx.Module.CorLibTypes.IntPtr)) { Attributes = MethodAttributes.Assembly | MethodAttributes.HideBySig | MethodAttributes.RTSpecialName | MethodAttributes.SpecialName, ImplAttributes = MethodImplAttributes.Runtime }; ret.Methods.Add(ctor); var invoke = new MethodDefUser("Invoke", sig.Clone()); invoke.MethodSig.HasThis = true; invoke.Attributes = MethodAttributes.Assembly | MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.NewSlot; invoke.ImplAttributes = MethodImplAttributes.Runtime; ret.Methods.Add(invoke); ctx.Module.Types.Add(ret); foreach (var def in ret.FindDefinitions()) { ctx.Marker.Mark(def, ctx.Protection); ctx.Name.SetCanRename(def, false); } ctx.Delegates[sig] = ret; return(ret); }
static int? TraceBeginning(RPContext ctx, int index, int argCount) { if (ctx.BranchTargets.Contains(ctx.Body.Instructions[index])) return null; int currentStack = argCount; int currentIndex = index; while (currentStack > 0) { currentIndex--; Instruction currentInstr = ctx.Body.Instructions[currentIndex]; // Disrupt stack analysis :/ Used by array initializer if (currentInstr.OpCode == OpCodes.Pop || currentInstr.OpCode == OpCodes.Dup) return null; // No branch instr. switch (currentInstr.OpCode.FlowControl) { case FlowControl.Call: case FlowControl.Break: case FlowControl.Meta: case FlowControl.Next: break; default: return null; } int push, pop; currentInstr.CalculateStackUsage(out push, out pop); currentStack += pop; currentStack -= push; // No branch target if (ctx.BranchTargets.Contains(currentInstr) && currentStack != 0) return null; } if (currentStack < 0) return null; return currentIndex; }
MethodDef CreateBridge(RPContext ctx, TypeDef delegateType, FieldDef field, MethodSig sig) { var method = new MethodDefUser(ctx.Name.RandomName(), sig); method.Attributes = MethodAttributes.PrivateScope | MethodAttributes.Static; method.ImplAttributes = MethodImplAttributes.Managed | MethodImplAttributes.IL; method.Body = new CilBody(); method.Body.Instructions.Add(Instruction.Create(OpCodes.Ldsfld, field)); for (int i = 0; i < method.Parameters.Count; i++) { method.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg, method.Parameters[i])); } method.Body.Instructions.Add(Instruction.Create(OpCodes.Call, delegateType.FindMethod("Invoke"))); method.Body.Instructions.Add(Instruction.Create(OpCodes.Ret)); delegateType.Methods.Add(method); ctx.Context.Registry.GetService <IMarkerService>().Mark(method, ctx.Protection); ctx.Name.SetCanRename(method, false); return(method); }
private void Compile(RPContext ctx, out Func<int, int> expCompiled, out MethodDef native) { var var = new Variable("{VAR}"); var result = new Variable("{RESULT}"); CorLibTypeSig int32 = ctx.Module.CorLibTypes.Int32; native = new MethodDefUser(ctx.Context.Registry.GetService<INameService>().RandomName(), MethodSig.CreateStatic(int32, int32), MethodAttributes.PinvokeImpl | MethodAttributes.PrivateScope | MethodAttributes.Static); native.ImplAttributes = MethodImplAttributes.Native | MethodImplAttributes.Unmanaged | MethodImplAttributes.PreserveSig; ctx.Module.GlobalType.Methods.Add(native); ctx.Context.Registry.GetService<IMarkerService>().Mark(native); ctx.Context.Registry.GetService<INameService>().SetCanRename(native, false); x86Register? reg; var codeGen = new x86CodeGen(); Expression expression, inverse; do { ctx.DynCipher.GenerateExpressionPair( ctx.Random, new VariableExpression { Variable = var }, new VariableExpression { Variable = result }, ctx.Depth, out expression, out inverse); reg = codeGen.GenerateX86(inverse, (v, r) => { return new[] { x86Instruction.Create(x86OpCode.POP, new x86RegisterOperand(r)) }; }); } while (reg == null); byte[] code = CodeGenUtils.AssembleCode(codeGen, reg.Value); expCompiled = new DMCodeGen(typeof(int), new[] { Tuple.Create("{VAR}", typeof(int)) }) .GenerateCIL(expression) .Compile<Func<int, int>>(); nativeCodes.Add(Tuple.Create(native, code, (MethodBody)null)); if (!addedHandler) { ctx.Context.CurrentModuleWriterListener.OnWriterEvent += InjectNativeCode; addedHandler = true; } }
public override void Finalize(RPContext ctx) { foreach (var field in fields) { InitMethodDesc init = GetInitMethod(ctx, field.Key.Item3); byte opKey; do { // No zero bytes opKey = ctx.Random.NextByte(); } while (opKey == (byte)field.Key.Item1); TypeDef delegateType = field.Value.Item1.DeclaringType; MethodDef cctor = delegateType.FindOrCreateStaticConstructor(); cctor.Body.Instructions.Insert(0, Instruction.Create(OpCodes.Call, init.Method)); cctor.Body.Instructions.Insert(0, Instruction.CreateLdcI4(opKey)); cctor.Body.Instructions.Insert(0, Instruction.Create(OpCodes.Ldtoken, field.Value.Item1)); fieldDescs.Add(new FieldDesc { Field = field.Value.Item1, OpCode = field.Key.Item1, Method = field.Key.Item2, OpKey = opKey, InitDesc = init }); } foreach (TypeDef delegateType in ctx.Delegates.Values) { MethodDef cctor = delegateType.FindOrCreateStaticConstructor(); ctx.Marker.Mark(cctor); ctx.Name.SetCanRename(cctor, false); } ctx.Context.CurrentModuleWriterOptions.MetaDataOptions.Flags |= MetaDataFlags.PreserveExtraSignatureData; ctx.Context.CurrentModuleWriterListener.OnWriterEvent += EncodeField; encodeCtx = ctx; }
public override void ProcessCall(RPContext ctx, int instrIndex) { var invoke = ctx.Body.Instructions[instrIndex]; var target = (IMethod)invoke.Operand; // Value type proxy is not supported in mild mode. if (target.DeclaringType.ResolveTypeDefThrow().IsValueType) { return; } // Skipping visibility is not supported in mild mode. if (!target.ResolveThrow().IsPublic&& !target.ResolveThrow().IsAssembly) { return; } var key = Tuple.Create(invoke.OpCode.Code, ctx.Method.DeclaringType, target); if (!proxies.TryGetValue(key, out var proxy)) { var sig = CreateProxySignature(ctx, target, invoke.OpCode.Code == Code.Newobj); proxy = new MethodDefUser(ctx.Name.RandomName(), sig) { Attributes = MethodAttributes.PrivateScope | MethodAttributes.Static, ImplAttributes = MethodImplAttributes.Managed | MethodImplAttributes.IL }; ctx.Method.DeclaringType.Methods.Add(proxy); // Fix peverify --- Non-virtual call to virtual methods must be done on this pointer if (invoke.OpCode.Code == Code.Call && target.ResolveThrow().IsVirtual) { proxy.IsStatic = false; sig.HasThis = true; sig.Params.RemoveAt(0); } ctx.Marker.Mark(proxy, ctx.Protection); ctx.Name.Analyze(proxy); ctx.Name.SetCanRename(proxy, false); proxy.Body = new CilBody(); for (var i = 0; i < proxy.Parameters.Count; i++) { proxy.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg, proxy.Parameters[i])); } proxy.Body.Instructions.Add(Instruction.Create(invoke.OpCode, target)); proxy.Body.Instructions.Add(Instruction.Create(OpCodes.Ret)); proxies[key] = proxy; } invoke.OpCode = OpCodes.Call; if (ctx.Method.DeclaringType.HasGenericParameters) { var genArgs = new GenericVar[ctx.Method.DeclaringType.GenericParameters.Count]; for (var i = 0; i < genArgs.Length; i++) { genArgs[i] = new GenericVar(i); } invoke.Operand = new MemberRefUser( ctx.Module, proxy.Name, proxy.MethodSig, new GenericInstSig((ClassOrValueTypeSig)ctx.Method.DeclaringType.ToTypeSig(), genArgs).ToTypeDefOrRef()); } else { invoke.Operand = proxy; } var targetDef = target.ResolveMethodDef(); if (targetDef != null) { ctx.Context.Annotations.Set(targetDef, ReferenceProxyProtection.Targeted, ReferenceProxyProtection.Targeted); } }
public override void Finalize(RPContext ctx) { }
RPContext ParseParameters(MethodDef method, ConfuserContext context, ProtectionParameters parameters, RPStore store) { var ret = new RPContext(); ret.Mode = parameters.GetParameter(context, method, "mode", Mode.Mild); ret.Encoding = parameters.GetParameter(context, method, "encoding", EncodingType.Normal); ret.InternalAlso = parameters.GetParameter(context, method, "internal", false); ret.TypeErasure = parameters.GetParameter(context, method, "typeErasure", false); ret.Depth = parameters.GetParameter(context, method, "depth", 3); ret.Module = method.Module; ret.Method = method; ret.Body = method.Body; ret.BranchTargets = new HashSet <Instruction>( method.Body.Instructions .Select(instr => instr.Operand as Instruction) .Concat(method.Body.Instructions .Where(instr => instr.Operand is Instruction[]) .SelectMany(instr => (Instruction[])instr.Operand)) .Where(target => target != null)); ret.Protection = (ReferenceProxyProtection)Parent; ret.Random = store.random; ret.Context = context; ret.Marker = context.Registry.GetService <IMarkerService>(); ret.DynCipher = context.Registry.GetService <IDynCipherService>(); ret.Name = context.Registry.GetService <INameService>(); ret.Delegates = store.delegates; switch (ret.Mode) { case Mode.Mild: ret.ModeHandler = store.mild ?? (store.mild = new MildMode()); break; case Mode.Strong: ret.ModeHandler = store.strong ?? (store.strong = new StrongMode()); break; default: throw new UnreachableException(); } switch (ret.Encoding) { case EncodingType.Normal: ret.EncodingHandler = store.normal ?? (store.normal = new NormalEncoding()); break; case EncodingType.Expression: ret.EncodingHandler = store.expression ?? (store.expression = new ExpressionEncoding()); break; case EncodingType.x86: ret.EncodingHandler = store.x86 ?? (store.x86 = new x86Encoding()); if ((context.CurrentModule.Cor20HeaderFlags & ComImageFlags.ILOnly) != 0) { context.CurrentModuleWriterOptions.Cor20HeaderOptions.Flags &= ~ComImageFlags.ILOnly; } break; default: throw new UnreachableException(); } return(ret); }
public int Encode(MethodDef init, RPContext ctx, int value) { Tuple<int, int> key = GetKey(ctx.Random, init); return value * key.Item2; }
public int Encode(MethodDef init, RPContext ctx, int value) { Tuple<Expression, Func<int, int>> key = GetKey(ctx, init); return key.Item2(value); }
public abstract void Finalize(RPContext ctx);
private InitMethodDesc GetInitMethod(RPContext ctx, IRPEncoding encoding) { InitMethodDesc[] initDescs; if (!inits.TryGetValue(encoding, out initDescs)) inits[encoding] = initDescs = new InitMethodDesc[ctx.InitCount]; int index = ctx.Random.NextInt32(initDescs.Length); if (initDescs[index] == null) { TypeDef rtType = ctx.Context.Registry.GetService<IRuntimeService>().GetRuntimeType("Confuser.Runtime.RefProxyStrong"); MethodDef injectedMethod = InjectHelper.Inject(rtType.FindMethod("Initialize"), ctx.Module); ctx.Module.GlobalType.Methods.Add(injectedMethod); injectedMethod.Access = MethodAttributes.PrivateScope; injectedMethod.Name = ctx.Name.RandomName(); ctx.Name.SetCanRename(injectedMethod, false); ctx.Marker.Mark(injectedMethod); var desc = new InitMethodDesc { Method = injectedMethod }; // Field name has five bytes, each bytes has different order & meaning int[] order = Enumerable.Range(0, 5).ToArray(); ctx.Random.Shuffle(order); desc.OpCodeIndex = order[4]; desc.TokenNameOrder = new int[4]; Array.Copy(order, 0, desc.TokenNameOrder, 0, 4); desc.TokenByteOrder = Enumerable.Range(0, 4).Select(x => x * 8).ToArray(); ctx.Random.Shuffle(desc.TokenByteOrder); var keyInjection = new int[9]; Array.Copy(desc.TokenNameOrder, 0, keyInjection, 0, 4); Array.Copy(desc.TokenByteOrder, 0, keyInjection, 4, 4); keyInjection[8] = desc.OpCodeIndex; MutationHelper.InjectKeys(injectedMethod, Enumerable.Range(0, 9).ToArray(), keyInjection); // Encoding MutationHelper.ReplacePlaceholder(injectedMethod, arg => { return encoding.EmitDecode(injectedMethod, ctx, arg); }); desc.Encoding = encoding; initDescs[index] = desc; } return initDescs[index]; }
private FieldDef CreateField(RPContext ctx, TypeDef delegateType) { // Details will be filled in during metadata writing TypeDef randomType; do { randomType = ctx.Module.Types[ctx.Random.NextInt32(ctx.Module.Types.Count)]; } while (randomType.HasGenericParameters || randomType.IsGlobalModuleType || randomType.IsDelegate()); TypeSig fieldType = new CModOptSig(randomType, delegateType.ToTypeSig()); var field = new FieldDefUser("", new FieldSig(fieldType), FieldAttributes.Static | FieldAttributes.Assembly); field.CustomAttributes.Add(new CustomAttribute(GetKeyAttr(ctx).FindInstanceConstructors().First())); delegateType.Fields.Add(field); ctx.Marker.Mark(field); ctx.Name.SetCanRename(field, false); return field; }
public int Encode(MethodDef init, RPContext ctx, int value) { Tuple <Expression, Func <int, int> > key = GetKey(ctx, init); return(key.Item2(value)); }
public abstract void ProcessCall(RPContext ctx, int instrIndex);
private TypeDef GetKeyAttr(RPContext ctx) { if (keyAttrs == null) keyAttrs = new Tuple<TypeDef, Func<int, int>>[0x10]; int index = ctx.Random.NextInt32(keyAttrs.Length); if (keyAttrs[index] == null) { TypeDef rtType = ctx.Context.Registry.GetService<IRuntimeService>().GetRuntimeType("Confuser.Runtime.RefProxyKey"); TypeDef injectedAttr = InjectHelper.Inject(rtType, ctx.Module); injectedAttr.Name = ctx.Name.RandomName(); injectedAttr.Namespace = string.Empty; Expression expression, inverse; var var = new Variable("{VAR}"); var result = new Variable("{RESULT}"); ctx.DynCipher.GenerateExpressionPair( ctx.Random, new VariableExpression { Variable = var }, new VariableExpression { Variable = result }, ctx.Depth, out expression, out inverse); var expCompiled = new DMCodeGen(typeof(int), new[] { Tuple.Create("{VAR}", typeof(int)) }) .GenerateCIL(expression) .Compile<Func<int, int>>(); MethodDef ctor = injectedAttr.FindMethod(".ctor"); MutationHelper.ReplacePlaceholder(ctor, arg => { var invCompiled = new List<Instruction>(); new CodeGen(arg, ctor, invCompiled).GenerateCIL(inverse); return invCompiled.ToArray(); }); keyAttrs[index] = Tuple.Create(injectedAttr, expCompiled); ctx.Module.AddAsNonNestedType(injectedAttr); foreach (IDnlibDef def in injectedAttr.FindDefinitions()) { if (def.Name == "GetHashCode") { ctx.Name.MarkHelper(def, ctx.Marker); ((MethodDef)def).Access = MethodAttributes.Public; } else ctx.Name.MarkHelper(def, ctx.Marker); } } return keyAttrs[index].Item1; }
public int Encode(MethodDef init, RPContext ctx, int value) { var key = GetKey(ctx.Random, init); return(value * key.Item2); }
private MethodDef CreateBridge(RPContext ctx, TypeDef delegateType, FieldDef field, MethodSig sig) { var method = new MethodDefUser(ctx.Name.RandomName(), sig); method.Attributes = MethodAttributes.PrivateScope | MethodAttributes.Static; method.ImplAttributes = MethodImplAttributes.Managed | MethodImplAttributes.IL; method.Body = new CilBody(); method.Body.Instructions.Add(Instruction.Create(OpCodes.Ldsfld, field)); for (int i = 0; i < method.Parameters.Count; i++) method.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg, method.Parameters[i])); method.Body.Instructions.Add(Instruction.Create(OpCodes.Call, delegateType.FindMethod("Invoke"))); method.Body.Instructions.Add(Instruction.Create(OpCodes.Ret)); delegateType.Methods.Add(method); ctx.Context.Registry.GetService<IMarkerService>().Mark(method); ctx.Name.SetCanRename(method, false); return method; }
private static ITypeDefOrRef Import(RPContext ctx, TypeDef typeDef) { ITypeDefOrRef retTypeRef = new Importer(ctx.Module, ImporterOptions.TryToUseTypeDefs).Import(typeDef); if (typeDef.Module != ctx.Module && ctx.Context.Modules.Contains((ModuleDefMD)typeDef.Module)) ctx.Name.AddReference(typeDef, new TypeRefReference((TypeRef)retTypeRef, typeDef)); return retTypeRef; }
private void ProcessInvoke(RPContext ctx, int instrIndex, int argBeginIndex) { Instruction instr = ctx.Body.Instructions[instrIndex]; var target = (IMethod)instr.Operand; MethodSig sig = CreateProxySignature(ctx, target, instr.OpCode.Code == Code.Newobj); TypeDef delegateType = GetDelegateType(ctx, sig); Tuple<Code, IMethod, IRPEncoding> key = Tuple.Create(instr.OpCode.Code, target, ctx.EncodingHandler); Tuple<FieldDef, MethodDef> proxy; if (!fields.TryGetValue(key, out proxy)) { // Create proxy field proxy = new Tuple<FieldDef, MethodDef>(CreateField(ctx, delegateType), null); fields[key] = proxy; } // Insert field load & replace instruction if (argBeginIndex == instrIndex) { ctx.Body.Instructions.Insert(instrIndex + 1, new Instruction(OpCodes.Call, delegateType.FindMethod("Invoke"))); instr.OpCode = OpCodes.Ldsfld; instr.Operand = proxy.Item1; } else { Instruction argBegin = ctx.Body.Instructions[argBeginIndex]; ctx.Body.Instructions.Insert(argBeginIndex + 1, new Instruction(argBegin.OpCode, argBegin.Operand)); argBegin.OpCode = OpCodes.Ldsfld; argBegin.Operand = proxy.Item1; instr.OpCode = OpCodes.Call; instr.Operand = delegateType.FindMethod("Invoke"); } }
private void ProcessBridge(RPContext ctx, int instrIndex) { Instruction instr = ctx.Body.Instructions[instrIndex]; var target = (IMethod)instr.Operand; TypeDef declType = target.DeclaringType.ResolveTypeDefThrow(); if (!declType.Module.IsILOnly) // Reflection doesn't like mixed mode modules. return; if (declType.IsGlobalModuleType) // Reflection doesn't like global methods too. return; Tuple<Code, IMethod, IRPEncoding> key = Tuple.Create(instr.OpCode.Code, target, ctx.EncodingHandler); Tuple<FieldDef, MethodDef> proxy; if (fields.TryGetValue(key, out proxy)) { if (proxy.Item2 != null) { instr.OpCode = OpCodes.Call; instr.Operand = proxy.Item2; return; } } else proxy = new Tuple<FieldDef, MethodDef>(null, null); MethodSig sig = CreateProxySignature(ctx, target, instr.OpCode.Code == Code.Newobj); TypeDef delegateType = GetDelegateType(ctx, sig); // Create proxy field if (proxy.Item1 == null) proxy = new Tuple<FieldDef, MethodDef>( CreateField(ctx, delegateType), proxy.Item2); // Create proxy bridge Debug.Assert(proxy.Item2 == null); proxy = new Tuple<FieldDef, MethodDef>( proxy.Item1, CreateBridge(ctx, delegateType, proxy.Item1, sig)); fields[key] = proxy; // Replace instruction instr.OpCode = OpCodes.Call; instr.Operand = proxy.Item2; }