diff --git a/blocks/blocks.csproj b/blocks/blocks.csproj index eff0ba86..2a55027e 100644 --- a/blocks/blocks.csproj +++ b/blocks/blocks.csproj @@ -38,29 +38,29 @@ - - - - - - - - - - - + + + + + + + + + + + + - - + + - - + + - @@ -68,8 +68,8 @@ - + @@ -99,6 +99,10 @@ {D68133BD-1E63-496E-9EDE-4FBDBF77B486} Mono.Cecil + + {FDFC1237-143F-4919-8318-4926901F4639} + dot10 + diff --git a/blocks/cflow/InstructionEmulator.cs b/blocks/cflow/InstructionEmulator.cs index 6ca70268..129ef60e 100644 --- a/blocks/cflow/InstructionEmulator.cs +++ b/blocks/cflow/InstructionEmulator.cs @@ -19,39 +19,38 @@ using System; using System.Collections.Generic; -using Mono.Cecil; -using Mono.Cecil.Cil; -using Mono.Cecil.Metadata; +using dot10.DotNet; +using dot10.DotNet.Emit; namespace de4dot.blocks.cflow { public class InstructionEmulator { ValueStack valueStack = new ValueStack(); Dictionary protectedStackValues = new Dictionary(); - IList parameterDefinitions; - IList variableDefinitions; + IList parameterDefs; + IList localDefs; List args = new List(); List locals = new List(); - int argBase; - MethodDefinition prev_method; + MethodDef prev_method; List cached_args = new List(); List cached_locals = new List(); - int cached_argBase; public InstructionEmulator() { } - public InstructionEmulator(MethodDefinition method) { + public InstructionEmulator(MethodDef method) { init(method); } +#if PORT public void init(Blocks blocks) { init(blocks.Method); } +#endif - public void init(MethodDefinition method) { - this.parameterDefinitions = method.Parameters; - this.variableDefinitions = method.Body.Variables; + public void init(MethodDef method) { + this.parameterDefs = method.Parameters; + this.localDefs = method.CilBody.LocalList; valueStack.init(); protectedStackValues.Clear(); @@ -59,20 +58,14 @@ namespace de4dot.blocks.cflow { prev_method = method; cached_args.Clear(); - cached_argBase = 0; - if (method.HasImplicitThis) { - cached_argBase = 1; - cached_args.Add(new UnknownValue()); - } - for (int i = 0; i < parameterDefinitions.Count; i++) - cached_args.Add(getUnknownValue(parameterDefinitions[i].ParameterType)); + for (int i = 0; i < parameterDefs.Count; i++) + cached_args.Add(getUnknownValue(parameterDefs[i].Type)); cached_locals.Clear(); - for (int i = 0; i < variableDefinitions.Count; i++) - cached_locals.Add(getUnknownValue(variableDefinitions[i].VariableType)); + for (int i = 0; i < localDefs.Count; i++) + cached_locals.Add(getUnknownValue(localDefs[i].Type)); } - argBase = cached_argBase; args.Clear(); args.AddRange(cached_args); locals.Clear(); @@ -83,10 +76,14 @@ namespace de4dot.blocks.cflow { protectedStackValues[value] = true; } - static Value getUnknownValue(TypeReference typeReference) { - if (typeReference == null) + static Value getUnknownValue(ITypeDefOrRef type) { + return getUnknownValue(type.ToTypeSig(false)); + } + + static Value getUnknownValue(TypeSig type) { + if (type == null) return new UnknownValue(); - switch (typeReference.EType) { + switch (type.ElementType) { case ElementType.Boolean: return Int32Value.createUnknownBool(); case ElementType.I1: return Int32Value.createUnknown(); case ElementType.U1: return Int32Value.createUnknownUInt8(); @@ -100,13 +97,13 @@ namespace de4dot.blocks.cflow { return new UnknownValue(); } - Value truncateValue(Value value, TypeReference typeReference) { - if (typeReference == null) + Value truncateValue(Value value, TypeSig type) { + if (type == null) return value; if (protectedStackValues.ContainsKey(value)) return value; - switch (typeReference.EType) { + switch (type.ElementType) { case ElementType.Boolean: if (value.isInt32()) return ((Int32Value)value).toBoolean(); @@ -167,27 +164,22 @@ namespace de4dot.blocks.cflow { return getValue(args, i); } - int index(ParameterDefinition arg) { - return arg.Sequence; + public Value getArg(Parameter arg) { + return getArg(arg.Number); } - public Value getArg(ParameterDefinition arg) { - return getArg(index(arg)); - } - - TypeReference getArgType(int index) { - index -= argBase; - if (0 <= index && index < parameterDefinitions.Count) - return parameterDefinitions[index].ParameterType; + TypeSig getArgType(int index) { + if (0 <= index && index < parameterDefs.Count) + return parameterDefs[index].Type; return null; } - public void setArg(ParameterDefinition arg, Value value) { - setArg(index(arg), value); + public void setArg(Parameter arg, Value value) { + setArg(arg.Number, value); } - public void makeArgUnknown(ParameterDefinition arg) { - setArg(arg, getUnknownArg(index(arg))); + public void makeArgUnknown(Parameter arg) { + setArg(arg, getUnknownArg(arg.Number)); } void setArg(int index, Value value) { @@ -203,26 +195,26 @@ namespace de4dot.blocks.cflow { return getValue(locals, i); } - public Value getLocal(VariableDefinition local) { - return getLocal(local.Index); + public Value getLocal(Local local) { + return getLocal(local.Number); } - public void setLocal(VariableDefinition local, Value value) { - setLocal(local.Index, value); + public void setLocal(Local local, Value value) { + setLocal(local.Number, value); } - public void makeLocalUnknown(VariableDefinition local) { - setLocal(local.Index, getUnknownLocal(local.Index)); + public void makeLocalUnknown(Local local) { + setLocal(local.Number, getUnknownLocal(local.Number)); } void setLocal(int index, Value value) { if (0 <= index && index < locals.Count) - locals[index] = truncateValue(value, variableDefinitions[index].VariableType); + locals[index] = truncateValue(value, localDefs[index].Type); } Value getUnknownLocal(int index) { - if (0 <= index && index < variableDefinitions.Count) - return getUnknownValue(variableDefinitions[index].VariableType); + if (0 <= index && index < localDefs.Count) + return getUnknownValue(localDefs[index].Type); return new UnknownValue(); } @@ -242,6 +234,7 @@ namespace de4dot.blocks.cflow { return valueStack.peek(); } +#if PORT public void emulate(IEnumerable instructions) { foreach (var instr in instructions) emulate(instr.Instruction); @@ -251,35 +244,36 @@ namespace de4dot.blocks.cflow { for (int i = start; i < end; i++) emulate(instructions[i].Instruction); } +#endif public void emulate(Instruction instr) { switch (instr.OpCode.Code) { case Code.Starg: - case Code.Starg_S: emulate_Starg((ParameterDefinition)instr.Operand); break; + case Code.Starg_S: emulate_Starg((Parameter)instr.Operand); break; case Code.Stloc: - case Code.Stloc_S: emulate_Stloc(((VariableDefinition)instr.Operand).Index); break; + case Code.Stloc_S: emulate_Stloc(((Local)instr.Operand).Number); break; case Code.Stloc_0: emulate_Stloc(0); break; case Code.Stloc_1: emulate_Stloc(1); break; case Code.Stloc_2: emulate_Stloc(2); break; case Code.Stloc_3: emulate_Stloc(3); break; case Code.Ldarg: - case Code.Ldarg_S: valueStack.push(getArg((ParameterDefinition)instr.Operand)); break; + case Code.Ldarg_S: valueStack.push(getArg((Parameter)instr.Operand)); break; case Code.Ldarg_0: valueStack.push(getArg(0)); break; case Code.Ldarg_1: valueStack.push(getArg(1)); break; case Code.Ldarg_2: valueStack.push(getArg(2)); break; case Code.Ldarg_3: valueStack.push(getArg(3)); break; case Code.Ldloc: - case Code.Ldloc_S: valueStack.push(getLocal((VariableDefinition)instr.Operand)); break; + case Code.Ldloc_S: valueStack.push(getLocal((Local)instr.Operand)); break; case Code.Ldloc_0: valueStack.push(getLocal(0)); break; case Code.Ldloc_1: valueStack.push(getLocal(1)); break; case Code.Ldloc_2: valueStack.push(getLocal(2)); break; case Code.Ldloc_3: valueStack.push(getLocal(3)); break; case Code.Ldarga: - case Code.Ldarga_S: emulate_Ldarga((ParameterDefinition)instr.Operand); break; + case Code.Ldarga_S: emulate_Ldarga((Parameter)instr.Operand); break; case Code.Ldloca: - case Code.Ldloca_S: emulate_Ldloca(((VariableDefinition)instr.Operand).Index); break; + case Code.Ldloca_S: emulate_Ldloca(((Local)instr.Operand).Number); break; case Code.Dup: valueStack.copyTop(); break; @@ -369,7 +363,7 @@ namespace de4dot.blocks.cflow { case Code.Ldelem_U1: valueStack.pop(2); valueStack.push(Int32Value.createUnknownUInt8()); break; case Code.Ldelem_U2: valueStack.pop(2); valueStack.push(Int32Value.createUnknownUInt16()); break; case Code.Ldelem_U4: valueStack.pop(2); valueStack.push(Int32Value.createUnknown()); break; - case Code.Ldelem_Any:valueStack.pop(2); valueStack.push(getUnknownValue(instr.Operand as TypeReference)); break; + case Code.Ldelem: valueStack.pop(2); valueStack.push(getUnknownValue(instr.Operand as ITypeDefOrRef)); break; case Code.Ldind_I1: valueStack.pop(); valueStack.push(Int32Value.createUnknown()); break; case Code.Ldind_I2: valueStack.pop(); valueStack.push(Int32Value.createUnknown()); break; @@ -457,7 +451,6 @@ namespace de4dot.blocks.cflow { case Code.Mkrefany: case Code.Newarr: case Code.Newobj: - case Code.No: case Code.Nop: case Code.Pop: case Code.Readonly: @@ -465,7 +458,7 @@ namespace de4dot.blocks.cflow { case Code.Refanyval: case Code.Ret: case Code.Rethrow: - case Code.Stelem_Any: + case Code.Stelem: case Code.Stelem_I: case Code.Stelem_I1: case Code.Stelem_I2: @@ -486,7 +479,7 @@ namespace de4dot.blocks.cflow { case Code.Stobj: case Code.Stsfld: case Code.Switch: - case Code.Tail: + case Code.Tailcall: case Code.Throw: case Code.Unaligned: case Code.Volatile: @@ -498,7 +491,7 @@ namespace de4dot.blocks.cflow { void updateStack(Instruction instr) { int pushes, pops; - DotNetUtils.calculateStackUsage(instr, false, out pushes, out pops); + instr.CalculateStackUsage(out pushes, out pops); if (pops == -1) valueStack.clear(); else { @@ -847,15 +840,15 @@ namespace de4dot.blocks.cflow { valueStack.pushUnknown(); } - void emulate_Starg(ParameterDefinition arg) { - setArg(index(arg), valueStack.pop()); + void emulate_Starg(Parameter arg) { + setArg(arg.Number, valueStack.pop()); } void emulate_Stloc(int index) { setLocal(index, valueStack.pop()); } - void emulate_Ldarga(ParameterDefinition arg) { + void emulate_Ldarga(Parameter arg) { valueStack.pushUnknown(); makeArgUnknown(arg); } @@ -866,19 +859,19 @@ namespace de4dot.blocks.cflow { } void emulate_Call(Instruction instr) { - emulate_Call(instr, (MethodReference)instr.Operand); + emulate_Call(instr, (IMethod)instr.Operand); } void emulate_Callvirt(Instruction instr) { - emulate_Call(instr, (MethodReference)instr.Operand); + emulate_Call(instr, (IMethod)instr.Operand); } - void emulate_Call(Instruction instr, MethodReference method) { + void emulate_Call(Instruction instr, IMethod method) { int pushes, pops; - DotNetUtils.calculateStackUsage(instr, false, out pushes, out pops); + instr.CalculateStackUsage(out pushes, out pops); valueStack.pop(pops); if (pushes == 1) - valueStack.push(getUnknownValue(method.MethodReturnType.ReturnType)); + valueStack.push(getUnknownValue(method.MethodSig.RetType)); else valueStack.push(pushes); } @@ -903,16 +896,16 @@ namespace de4dot.blocks.cflow { void emulate_Ldfld(Instruction instr) { var val1 = valueStack.pop(); - emulateLoadField(instr.Operand as FieldReference); + emulateLoadField(instr.Operand as IField); } void emulate_Ldsfld(Instruction instr) { - emulateLoadField(instr.Operand as FieldReference); + emulateLoadField(instr.Operand as IField); } - void emulateLoadField(FieldReference fieldReference) { - if (fieldReference != null) - valueStack.push(getUnknownValue(fieldReference.FieldType)); + void emulateLoadField(IField field) { + if (field != null) + valueStack.push(getUnknownValue(field.FieldSig.Type)); else valueStack.pushUnknown(); } diff --git a/de4dot.code/ObfuscatedFile.cs b/de4dot.code/ObfuscatedFile.cs index 88b33c45..42892714 100644 --- a/de4dot.code/ObfuscatedFile.cs +++ b/de4dot.code/ObfuscatedFile.cs @@ -527,14 +527,18 @@ namespace de4dot.code { Log.v("Deobfuscating methods"); var methodPrinter = new MethodPrinter(); +#if PORT var cflowDeobfuscator = new BlocksCflowDeobfuscator(deob.BlocksDeobfuscators); +#endif foreach (var method in getAllMethods()) { Log.v("Deobfuscating {0} ({1:X8})", Utils.removeNewlines(method), method.MetadataToken.ToUInt32()); Log.indent(); int oldIndentLevel = Log.indentLevel; try { +#if PORT deobfuscate(method, cflowDeobfuscator, methodPrinter); +#endif } catch (ApplicationException) { throw; @@ -569,6 +573,7 @@ namespace de4dot.code { } } +#if PORT void deobfuscate(MethodDefinition method, BlocksCflowDeobfuscator cflowDeobfuscator, MethodPrinter methodPrinter) { if (!hasNonEmptyBody(method)) return; @@ -613,6 +618,7 @@ namespace de4dot.code { Log.deIndent(); } } +#endif bool hasNonEmptyBody(MethodDefinition method) { return method.HasBody && method.Body.Instructions.Count > 0; @@ -726,9 +732,11 @@ namespace de4dot.code { return; deobfuscate(method, "Deobfuscating control flow", (blocks) => { +#if PORT var cflowDeobfuscator = new BlocksCflowDeobfuscator(deob.BlocksDeobfuscators); cflowDeobfuscator.init(blocks); cflowDeobfuscator.deobfuscate(); +#endif }); } diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj index 074c942d..eb9089bf 100644 --- a/de4dot.code/de4dot.code.csproj +++ b/de4dot.code/de4dot.code.csproj @@ -57,166 +57,166 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + - - - - + + + + - - - - - - - - - - + + + + + + + + + + @@ -224,46 +224,46 @@ - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + @@ -341,6 +341,10 @@ {5C93C5E2-196F-4877-BF65-96FEBFCEFCA1} de4dot.mdecrypt + + {FDFC1237-143F-4919-8318-4926901F4639} + dot10 + diff --git a/de4dot.code/deobfuscators/ArrayFinder.cs b/de4dot.code/deobfuscators/ArrayFinder.cs index e15ddbc0..458afe8f 100644 --- a/de4dot.code/deobfuscators/ArrayFinder.cs +++ b/de4dot.code/deobfuscators/ArrayFinder.cs @@ -18,26 +18,26 @@ */ using System.Collections.Generic; -using Mono.Cecil; -using Mono.Cecil.Cil; +using dot10.DotNet; +using dot10.DotNet.Emit; using de4dot.blocks; using de4dot.blocks.cflow; namespace de4dot.code.deobfuscators { static class ArrayFinder { - public static List getArrays(MethodDefinition method) { + public static List getArrays(MethodDef method) { return getArrays(method, null); } - public static List getArrays(MethodDefinition method, TypeReference arrayElemntType) { + public static List getArrays(MethodDef method, IType arrayElementType) { var arrays = new List(); - var instrs = method.Body.Instructions; + var instrs = method.CilBody.Instructions; for (int i = 0; i < instrs.Count; i++) { - TypeReference type; + IType type; var ary = getArray(instrs, ref i, out type); if (ary == null) break; - if (arrayElemntType != null && !MemberReferenceHelper.compareTypes(type, arrayElemntType)) + if (arrayElementType != null && !new SigComparer().Equals(type, arrayElementType)) continue; arrays.Add(ary); @@ -45,7 +45,7 @@ namespace de4dot.code.deobfuscators { return arrays; } - public static byte[] getArray(IList instrs, ref int index, out TypeReference type) { + public static byte[] getArray(IList instrs, ref int index, out IType type) { for (int i = index; i < instrs.Count - 2; i++) { var newarr = instrs[i++]; if (newarr.OpCode.Code != Code.Newarr) @@ -57,12 +57,12 @@ namespace de4dot.code.deobfuscators { var ldtoken = instrs[i++]; if (ldtoken.OpCode.Code != Code.Ldtoken) continue; - var field = ldtoken.Operand as FieldDefinition; + var field = ldtoken.Operand as FieldDef; if (field == null || field.InitialValue == null) continue; index = i - 3; - type = newarr.Operand as TypeReference; + type = newarr.Operand as IType; return field.InitialValue; } @@ -71,14 +71,14 @@ namespace de4dot.code.deobfuscators { return null; } - public static byte[] getInitializedByteArray(MethodDefinition method, int arraySize) { + public static byte[] getInitializedByteArray(MethodDef method, int arraySize) { int newarrIndex = findNewarr(method, arraySize); if (newarrIndex < 0) return null; return getInitializedByteArray(arraySize, method, ref newarrIndex); } - public static byte[] getInitializedByteArray(int arraySize, MethodDefinition method, ref int newarrIndex) { + public static byte[] getInitializedByteArray(int arraySize, MethodDef method, ref int newarrIndex) { var resultValueArray = getInitializedArray(arraySize, method, ref newarrIndex, Code.Stelem_I1); var resultArray = new byte[resultValueArray.Length]; @@ -91,7 +91,7 @@ namespace de4dot.code.deobfuscators { return resultArray; } - public static short[] getInitializedInt16Array(int arraySize, MethodDefinition method, ref int newarrIndex) { + public static short[] getInitializedInt16Array(int arraySize, MethodDef method, ref int newarrIndex) { var resultValueArray = getInitializedArray(arraySize, method, ref newarrIndex, Code.Stelem_I2); var resultArray = new short[resultValueArray.Length]; @@ -104,7 +104,7 @@ namespace de4dot.code.deobfuscators { return resultArray; } - public static int[] getInitializedInt32Array(int arraySize, MethodDefinition method, ref int newarrIndex) { + public static int[] getInitializedInt32Array(int arraySize, MethodDef method, ref int newarrIndex) { var resultValueArray = getInitializedArray(arraySize, method, ref newarrIndex, Code.Stelem_I4); var resultArray = new int[resultValueArray.Length]; @@ -117,7 +117,7 @@ namespace de4dot.code.deobfuscators { return resultArray; } - public static uint[] getInitializedUInt32Array(int arraySize, MethodDefinition method, ref int newarrIndex) { + public static uint[] getInitializedUInt32Array(int arraySize, MethodDef method, ref int newarrIndex) { var resultArray = getInitializedInt32Array(arraySize, method, ref newarrIndex); if (resultArray == null) return null; @@ -128,14 +128,14 @@ namespace de4dot.code.deobfuscators { return ary; } - public static Value[] getInitializedArray(int arraySize, MethodDefinition method, ref int newarrIndex, Code stelemOpCode) { + public static Value[] getInitializedArray(int arraySize, MethodDef method, ref int newarrIndex, Code stelemOpCode) { var resultValueArray = new Value[arraySize]; var emulator = new InstructionEmulator(method); var theArray = new UnknownValue(); emulator.push(theArray); - var instructions = method.Body.Instructions; + var instructions = method.CilBody.Instructions; int i; for (i = newarrIndex + 1; i < instructions.Count; i++) { var instr = instructions[i]; @@ -183,7 +183,7 @@ done: return resultValueArray; } - static int findNewarr(MethodDefinition method, int arraySize) { + static int findNewarr(MethodDef method, int arraySize) { for (int i = 0; ; i++) { int size; if (!findNewarr(method, ref i, out size)) @@ -193,17 +193,17 @@ done: } } - public static bool findNewarr(MethodDefinition method, ref int i, out int size) { - var instructions = method.Body.Instructions; + public static bool findNewarr(MethodDef method, ref int i, out int size) { + var instructions = method.CilBody.Instructions; for (; i < instructions.Count; i++) { var instr = instructions[i]; if (instr.OpCode.Code != Code.Newarr || i < 1) continue; var ldci4 = instructions[i - 1]; - if (!DotNetUtils.isLdcI4(ldci4)) + if (!ldci4.IsLdcI4()) continue; - size = DotNetUtils.getLdcI4Value(ldci4); + size = ldci4.GetLdcI4Value(); return true; } diff --git a/de4dot.code/deobfuscators/DeobfuscatorBase.cs b/de4dot.code/deobfuscators/DeobfuscatorBase.cs index 90f15741..8da39331 100644 --- a/de4dot.code/deobfuscators/DeobfuscatorBase.cs +++ b/de4dot.code/deobfuscators/DeobfuscatorBase.cs @@ -95,6 +95,7 @@ namespace de4dot.code.deobfuscators { get { return Operations.DecryptStrings != OpDecryptString.None && staticStringInliner.InlinedAllCalls; } } +#if PORT public virtual IEnumerable BlocksDeobfuscators { get { var list = new List(); @@ -103,6 +104,7 @@ namespace de4dot.code.deobfuscators { return list; } } +#endif public DeobfuscatorBase(OptionsBase optionsBase) { this.optionsBase = optionsBase; @@ -821,7 +823,7 @@ namespace de4dot.code.deobfuscators { return false; } - public static int toInt32(bool b) { + protected static int toInt32(bool b) { return b ? 1 : 0; } } diff --git a/de4dot.code/deobfuscators/IDeobfuscator.cs b/de4dot.code/deobfuscators/IDeobfuscator.cs index e13fe2ec..47fde0aa 100644 --- a/de4dot.code/deobfuscators/IDeobfuscator.cs +++ b/de4dot.code/deobfuscators/IDeobfuscator.cs @@ -62,7 +62,9 @@ namespace de4dot.code.deobfuscators { StringFeatures StringFeatures { get; } RenamingOptions RenamingOptions { get; } DecrypterType DefaultDecrypterType { get; } +#if PORT IEnumerable BlocksDeobfuscators { get; } +#endif // This is non-null only in detect() and deobfuscateBegin(). IDeobfuscatedFile DeobfuscatedFile { get; set; } diff --git a/de4dot.cui/Program.cs b/de4dot.cui/Program.cs index 5a0a6c70..738a6fa8 100644 --- a/de4dot.cui/Program.cs +++ b/de4dot.cui/Program.cs @@ -37,6 +37,7 @@ namespace de4dot.cui { static IList createDeobfuscatorInfos() { return new List { new de4dot.code.deobfuscators.Unknown.DeobfuscatorInfo(), +#if PORT new de4dot.code.deobfuscators.Babel_NET.DeobfuscatorInfo(), new de4dot.code.deobfuscators.CliSecure.DeobfuscatorInfo(), new de4dot.code.deobfuscators.CodeFort.DeobfuscatorInfo(), @@ -57,6 +58,7 @@ namespace de4dot.cui { new de4dot.code.deobfuscators.SmartAssembly.DeobfuscatorInfo(), new de4dot.code.deobfuscators.Spices_Net.DeobfuscatorInfo(), new de4dot.code.deobfuscators.Xenocode.DeobfuscatorInfo(), +#endif }; } diff --git a/dot10 b/dot10 index 80ac6ba4..c7a83ee8 160000 --- a/dot10 +++ b/dot10 @@ -1 +1 @@ -Subproject commit 80ac6ba43c0ec9a044f850422415e3d2ad795d28 +Subproject commit c7a83ee87964d694a1e87ed9feb6cbc054226295