Skip to content

Commit 99977b6

Browse files
author
RandomCrocodile
committed
feature: randomize CFG state multiplier constant per run (#69)
The Constants protection's control-flow encoding baked the fixed multiplier 0x21412321 into both the obfuscator-side CFGState and the injected runtime CFGCtx constructor, giving de4dot a stable signature. Generate a random odd (invertible mod 2^32) multiplier per module when the CFG state type is injected, rewrite the literal in the runtime ctor IL, and thread the same value through the obfuscator CFGState so both sides stay in sync. Validated end-to-end by the constants protection tests (obfuscate -> run -> assert output).
1 parent 110b096 commit 99977b6

2 files changed

Lines changed: 18 additions & 8 deletions

File tree

Confuser.Protections/Constants/CEContext.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ internal class CEContext {
3535
public TypeDef CfgCtxType;
3636
public MethodDef CfgCtxCtor;
3737
public MethodDef CfgCtxNext;
38+
public uint CfgCtxMultiplier;
3839
public Dictionary<MethodDef, List<Tuple<Instruction, uint, IMethod>>> ReferenceRepl;
3940
}
4041

Confuser.Protections/Constants/ReferenceReplacer.cs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,11 @@ struct CFGState {
5151
public uint C;
5252
public uint D;
5353

54-
public CFGState(uint seed) {
55-
A = seed *= 0x21412321;
56-
B = seed *= 0x21412321;
57-
C = seed *= 0x21412321;
58-
D = seed *= 0x21412321;
54+
public CFGState(uint seed, uint mult) {
55+
A = seed *= mult;
56+
B = seed *= mult;
57+
C = seed *= mult;
58+
D = seed *= mult;
5959
}
6060

6161
public void UpdateExplicit(int id, uint value) {
@@ -136,6 +136,15 @@ static void InjectStateType(CEContext ctx) {
136136
ctx.CfgCtxCtor = ctx.CfgCtxType.FindMethod(".ctor");
137137
ctx.CfgCtxNext = ctx.CfgCtxType.FindMethod("Next");
138138

139+
// Randomize the CFG state multiplier so the baked-in 0x21412321 literal
140+
// no longer fingerprints the output. Must stay odd (invertible mod 2^32) and
141+
// match the obfuscator-side CFGState computation (see CFGState.ctor).
142+
ctx.CfgCtxMultiplier = ctx.Random.NextUInt32() | 1;
143+
foreach (var instr in ctx.CfgCtxCtor.Body.Instructions) {
144+
if (instr.OpCode == OpCodes.Ldc_I4 && (int)instr.Operand == 0x21412321)
145+
instr.Operand = (int)ctx.CfgCtxMultiplier;
146+
}
147+
139148
ctx.Name.MarkHelper(ctx.CfgCtxType, ctx.Marker, ctx.Protection);
140149
foreach (var def in ctx.CfgCtxType.Fields)
141150
ctx.Name.MarkHelper(def, ctx.Marker, ctx.Protection);
@@ -212,7 +221,7 @@ static void InsertEmptyStateUpdate(CFGContext ctx, ControlFlowBlock block) {
212221
if (!ctx.StatesMap.TryGetValue(key.ExitState, out exit)) {
213222
// Create new exit state from random seed
214223
var seed = ctx.Random.NextUInt32();
215-
exit = new CFGState(seed);
224+
exit = new CFGState(seed, ctx.Ctx.CfgCtxMultiplier);
216225
body.Instructions.Insert(targetIndex++, first = Instruction.Create(OpCodes.Ldloca, ctx.StateVariable));
217226
body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldc_I4, (int)seed));
218227
body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxCtor));
@@ -301,7 +310,7 @@ static uint InsertStateGetAndUpdate(CFGContext ctx, ref int index, BlockKeyType
301310
if (targetState == null) {
302311
// Create new exit state from random seed
303312
var seed = ctx.Random.NextUInt32();
304-
currentState = new CFGState(seed);
313+
currentState = new CFGState(seed, ctx.Ctx.CfgCtxMultiplier);
305314
body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldloca, ctx.StateVariable));
306315
body.Instructions.Insert(index++, Instruction.Create(OpCodes.Dup));
307316
body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4, (int)seed));
@@ -398,7 +407,7 @@ static void ReplaceCFG(MethodDef method, List<Tuple<Instruction, uint, IMethod>>
398407

399408
// Create new entry state
400409
uint blockSeed = ctx.Random.NextUInt32();
401-
currentState = new CFGState(blockSeed);
410+
currentState = new CFGState(blockSeed, ctx.CfgCtxMultiplier);
402411
cfgCtx.StatesMap[key.EntryState] = currentState;
403412

404413
var index = graph.Body.Instructions.IndexOf(graph[blockRef.Key].Header);

0 commit comments

Comments
 (0)