Skip to content

Commit b2a44ff

Browse files
mcpolo99RandomCrocodile
andauthored
feature: randomize anti-tamper feedback + CFG multiplier constants (#69 level 2) (#98)
* feature: randomize anti-tamper feedback constant per run (#69) Phase 2 of #69 (Level 2 identity). The anti-tamper method-body cipher used a hardcoded feedback constant 0x3dbb2819 in both the obfuscator (encrypt) and the injected runtime (decrypt) — a value de4dot signature-matches to identify ConfuserEx. Normal and Anti modes now generate a random per-run feedback value, use it in the encryption loop, and inject it into the runtime via a new Mutation key (KeyI5), exactly like the existing z/x/c/v hash constants (KeyI1-4). Obfuscator and runtime stay in sync automatically because the same generated value is both used and injected. JIT mode is intentionally left unchanged — its runtime component is already broken and its test is skipped, so a crypto change there cannot be validated. Validated by AntiTamper.Test: the obfuscated app decrypts its own method bodies at runtime and produces correct output (exit 42) for both Normal and Anti modes. * 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). --------- Co-authored-by: RandomCrocodile <mawi@polosab.com>
1 parent ee3a56c commit b2a44ff

7 files changed

Lines changed: 33 additions & 16 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Visual Studio Cache files (starting with VS 2015)
22
.vs/
3+
.temp
34

45
# Launch Settings
56
launchSettings.json

Confuser.Protections/AntiTamper/AntiMode.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
namespace Confuser.Protections.AntiTamper {
1717
internal class AntiMode : IModeHandler {
1818
uint c;
19+
uint feedback;
1920
IKeyDeriver deriver;
2021

2122
List<MethodDef> methods;
@@ -31,6 +32,7 @@ public void HandleInject(AntiTamperProtection parent, ConfuserContext context, P
3132
x = random.NextUInt32();
3233
c = random.NextUInt32();
3334
v = random.NextUInt32();
35+
feedback = random.NextUInt32();
3436
name1 = random.NextUInt32() & 0x7f7f7f7f;
3537
name2 = random.NextUInt32() & 0x7f7f7f7f;
3638

@@ -77,8 +79,8 @@ public void HandleInject(AntiTamperProtection parent, ConfuserContext context, P
7779
initMethod.Body.Instructions.Add(instr);
7880

7981
MutationHelper.InjectKeys(initMethod,
80-
new[] { 0, 1, 2, 3, 4 },
81-
new[] { (int)(name1 * name2), (int)z, (int)x, (int)c, (int)v });
82+
new[] { 0, 1, 2, 3, 4, 5 },
83+
new[] { (int)(name1 * name2), (int)z, (int)x, (int)c, (int)v, (int)feedback });
8284

8385
var name = context.Registry.GetService<INameService>();
8486
var marker = context.Registry.GetService<IMarkerService>();
@@ -219,7 +221,7 @@ void EncryptSection(ModuleWriterBase writer) {
219221
for (uint i = 0; i < encSize; i++) {
220222
uint data = reader.ReadUInt32();
221223
result[i] = data ^ key[i & 0xf];
222-
key[i & 0xf] = (key[i & 0xf] ^ data) + 0x3dbb2819;
224+
key[i & 0xf] = (key[i & 0xf] ^ data) + feedback;
223225
}
224226
var byteResult = new byte[encSize << 2];
225227
Buffer.BlockCopy(result, 0, byteResult, 0, byteResult.Length);

Confuser.Protections/AntiTamper/NormalMode.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
namespace Confuser.Protections.AntiTamper {
1717
internal class NormalMode : IModeHandler {
1818
uint c;
19+
uint feedback;
1920
IKeyDeriver deriver;
2021

2122
List<MethodDef> methods;
@@ -31,6 +32,7 @@ public void HandleInject(AntiTamperProtection parent, ConfuserContext context, P
3132
x = random.NextUInt32();
3233
c = random.NextUInt32();
3334
v = random.NextUInt32();
35+
feedback = random.NextUInt32();
3436
name1 = random.NextUInt32() & 0x7f7f7f7f;
3537
name2 = random.NextUInt32() & 0x7f7f7f7f;
3638

@@ -77,8 +79,8 @@ public void HandleInject(AntiTamperProtection parent, ConfuserContext context, P
7779
initMethod.Body.Instructions.Add(instr);
7880

7981
MutationHelper.InjectKeys(initMethod,
80-
new[] { 0, 1, 2, 3, 4 },
81-
new[] { (int)(name1 * name2), (int)z, (int)x, (int)c, (int)v });
82+
new[] { 0, 1, 2, 3, 4, 5 },
83+
new[] { (int)(name1 * name2), (int)z, (int)x, (int)c, (int)v, (int)feedback });
8284

8385
var name = context.Registry.GetService<INameService>();
8486
var marker = context.Registry.GetService<IMarkerService>();
@@ -220,7 +222,7 @@ void EncryptSection(ModuleWriterBase writer) {
220222
for (uint i = 0; i < encSize; i++) {
221223
uint data = reader.ReadUInt32();
222224
result[i] = data ^ key[i & 0xf];
223-
key[i & 0xf] = (key[i & 0xf] ^ data) + 0x3dbb2819;
225+
key[i & 0xf] = (key[i & 0xf] ^ data) + feedback;
224226
}
225227
var byteResult = new byte[encSize << 2];
226228
Buffer.BlockCopy(result, 0, byteResult, 0, byteResult.Length);

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);

Confuser.Runtime/AntiTamper.Anti.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ static unsafe void Initialize() {
2727
uint l = 0;
2828
var r = (uint*)(p + 0x18 + o);
2929
uint z = (uint)Mutation.KeyI1, x = (uint)Mutation.KeyI2, c = (uint)Mutation.KeyI3, v = (uint)Mutation.KeyI4;
30+
uint fb = (uint)Mutation.KeyI5;
3031

3132
CheckRemoteDebuggerPresent(Process.GetCurrentProcess().Handle, ref isDebuggerPresent);
3233
if (isDebuggerPresent) Environment.FailFast(null);
@@ -80,7 +81,7 @@ static unsafe void Initialize() {
8081
uint h = 0;
8182
for (uint i = 0; i < l; i++) {
8283
*e ^= y[h & 0xf];
83-
y[h & 0xf] = (y[h & 0xf] ^ (*e++)) + 0x3dbb2819;
84+
y[h & 0xf] = (y[h & 0xf] ^ (*e++)) + fb;
8485

8586
CheckRemoteDebuggerPresent(Process.GetCurrentProcess().Handle, ref isDebuggerPresent);
8687
if (isDebuggerPresent) Environment.FailFast(null);

Confuser.Runtime/AntiTamper.Normal.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ static unsafe void Initialize() {
2020
uint l = 0;
2121
var r = (uint*)(p + 0x18 + o);
2222
uint z = (uint)Mutation.KeyI1, x = (uint)Mutation.KeyI2, c = (uint)Mutation.KeyI3, v = (uint)Mutation.KeyI4;
23+
uint fb = (uint)Mutation.KeyI5;
2324
for (int i = 0; i < s; i++) {
2425
uint g = (*r++) * (*r++);
2526
if (g == (uint)Mutation.KeyI0) {
@@ -60,7 +61,7 @@ static unsafe void Initialize() {
6061
uint h = 0;
6162
for (uint i = 0; i < l; i++) {
6263
*e ^= y[h & 0xf];
63-
y[h & 0xf] = (y[h & 0xf] ^ (*e++)) + 0x3dbb2819;
64+
y[h & 0xf] = (y[h & 0xf] ^ (*e++)) + fb;
6465
h++;
6566
}
6667
}

0 commit comments

Comments
 (0)