From 9f8fd91c44a037423bfd7afe9d6fa52c3507bf30 Mon Sep 17 00:00:00 2001 From: RandomCrocodile Date: Mon, 21 Sep 2026 21:23:18 +0200 Subject: [PATCH] feature: randomize anti-tamper key-derivation rotation shifts (#69) The anti-tamper key-derivation mixer rotates its four state registers by the fixed amounts 5/3/7/11 on both the obfuscator (mode DeriveKey) and the injected runtime (Initialize), across all three modes (Normal, Anti, JIT). de4dot/AV pattern-match these fixed shifts. The four amounts are now chosen distinct per module and injected into the runtime via mutation keys (KeyI6..KeyI9); the runtime forms each rotation as (r >> amount) | (r << (32 - amount)). Both sides share the amounts, so the round-trip holds. Unlike the xorshift/prime constants, a bit rotation is a bijection for any amount in 1..31, so no curated set is required -- the shared RotationKey helper just picks four distinct non-trivial amounts. Validated by AntiTamper.Test (normal + anti pass; jit stays skipped as it is a pre-existing known-broken/untested mode -- its change mirrors the two validated modes and is compile-checked only). --- Confuser.Protections/AntiTamper/AntiMode.cs | 19 +++++++++----- Confuser.Protections/AntiTamper/JITMode.cs | 19 +++++++++----- Confuser.Protections/AntiTamper/NormalMode.cs | 19 +++++++++----- .../AntiTamper/RotationKey.cs | 26 +++++++++++++++++++ Confuser.Runtime/AntiTamper.Anti.cs | 8 +++--- Confuser.Runtime/AntiTamper.JIT.cs | 8 +++--- Confuser.Runtime/AntiTamper.Normal.cs | 8 +++--- 7 files changed, 77 insertions(+), 30 deletions(-) create mode 100644 Confuser.Protections/AntiTamper/RotationKey.cs diff --git a/Confuser.Protections/AntiTamper/AntiMode.cs b/Confuser.Protections/AntiTamper/AntiMode.cs index 4c28ea83b..e19d51175 100644 --- a/Confuser.Protections/AntiTamper/AntiMode.cs +++ b/Confuser.Protections/AntiTamper/AntiMode.cs @@ -22,6 +22,7 @@ internal class AntiMode : IModeHandler { List methods; uint name1, name2; RandomGenerator random; + int[] rotShifts; uint v; uint x; uint z; @@ -35,6 +36,9 @@ public void HandleInject(AntiTamperProtection parent, ConfuserContext context, P feedback = random.NextUInt32(); name1 = random.NextUInt32() & 0x7f7f7f7f; name2 = random.NextUInt32() & 0x7f7f7f7f; + // Randomize the key-derivation rotation amounts (were the fixed 5/3/7/11); the same + // amounts are injected into the runtime (Mutation.KeyI6..KeyI9) below. + rotShifts = RotationKey.PickShifts(random); switch (parameters.GetParameter(context, context.CurrentModule, "key", Mode.Normal)) { case Mode.Normal: @@ -79,8 +83,11 @@ public void HandleInject(AntiTamperProtection parent, ConfuserContext context, P initMethod.Body.Instructions.Add(instr); MutationHelper.InjectKeys(initMethod, - new[] { 0, 1, 2, 3, 4, 5 }, - new[] { (int)(name1 * name2), (int)z, (int)x, (int)c, (int)v, (int)feedback }); + new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, + new[] { + (int)(name1 * name2), (int)z, (int)x, (int)c, (int)v, (int)feedback, + rotShifts[0], rotShifts[1], rotShifts[2], rotShifts[3] + }); var name = context.Registry.GetService(); var marker = context.Registry.GetService(); @@ -249,10 +256,10 @@ uint[] DeriveKey() { for (int i = 0; i < 0x10; i++) { dst[i] = v; src[i] = x; - z = (x >> 5) | (x << 27); - x = (c >> 3) | (c << 29); - c = (v >> 7) | (v << 25); - v = (z >> 11) | (z << 21); + z = (x >> rotShifts[0]) | (x << (32 - rotShifts[0])); + x = (c >> rotShifts[1]) | (c << (32 - rotShifts[1])); + c = (v >> rotShifts[2]) | (v << (32 - rotShifts[2])); + v = (z >> rotShifts[3]) | (z << (32 - rotShifts[3])); } return deriver.DeriveKey(dst, src); } diff --git a/Confuser.Protections/AntiTamper/JITMode.cs b/Confuser.Protections/AntiTamper/JITMode.cs index 074c54b40..4ace926fa 100644 --- a/Confuser.Protections/AntiTamper/JITMode.cs +++ b/Confuser.Protections/AntiTamper/JITMode.cs @@ -35,6 +35,7 @@ internal class JITMode : IModeHandler { List methods; uint name1, name2; RandomGenerator random; + int[] rotShifts; uint v; uint x; uint z; @@ -49,6 +50,9 @@ public void HandleInject(AntiTamperProtection parent, ConfuserContext context, P name1 = random.NextUInt32() & 0x7f7f7f7f; name2 = random.NextUInt32() & 0x7f7f7f7f; key = random.NextUInt32(); + // Randomize the key-derivation rotation amounts (were the fixed 5/3/7/11); the same + // amounts are injected into the runtime (Mutation.KeyI6..KeyI9) below. + rotShifts = RotationKey.PickShifts(random); fieldLayout = new byte[6]; for (int i = 0; i < 6; i++) { @@ -101,8 +105,11 @@ public void HandleInject(AntiTamperProtection parent, ConfuserContext context, P initMethod.Body.Instructions.Add(instr); MutationHelper.InjectKeys(initMethod, - new[] { 0, 1, 2, 3, 4 }, - new[] { (int)(name1 * name2), (int)z, (int)x, (int)c, (int)v }); + new[] { 0, 1, 2, 3, 4, 6, 7, 8, 9 }, + new[] { + (int)(name1 * name2), (int)z, (int)x, (int)c, (int)v, + rotShifts[0], rotShifts[1], rotShifts[2], rotShifts[3] + }); var name = context.Registry.GetService(); var marker = context.Registry.GetService(); @@ -316,10 +323,10 @@ uint[] DeriveKey() { for (int i = 0; i < 0x10; i++) { dst[i] = v; src[i] = x; - z = (x >> 5) | (x << 27); - x = (c >> 3) | (c << 29); - c = (v >> 7) | (v << 25); - v = (z >> 11) | (z << 21); + z = (x >> rotShifts[0]) | (x << (32 - rotShifts[0])); + x = (c >> rotShifts[1]) | (c << (32 - rotShifts[1])); + c = (v >> rotShifts[2]) | (v << (32 - rotShifts[2])); + v = (z >> rotShifts[3]) | (z << (32 - rotShifts[3])); } return deriver.DeriveKey(dst, src); } diff --git a/Confuser.Protections/AntiTamper/NormalMode.cs b/Confuser.Protections/AntiTamper/NormalMode.cs index b73f57e2e..a337e9574 100644 --- a/Confuser.Protections/AntiTamper/NormalMode.cs +++ b/Confuser.Protections/AntiTamper/NormalMode.cs @@ -22,6 +22,7 @@ internal class NormalMode : IModeHandler { List methods; uint name1, name2; RandomGenerator random; + int[] rotShifts; uint v; uint x; uint z; @@ -35,6 +36,9 @@ public void HandleInject(AntiTamperProtection parent, ConfuserContext context, P feedback = random.NextUInt32(); name1 = random.NextUInt32() & 0x7f7f7f7f; name2 = random.NextUInt32() & 0x7f7f7f7f; + // Randomize the key-derivation rotation amounts (were the fixed 5/3/7/11); the same + // amounts are injected into the runtime (Mutation.KeyI6..KeyI9) below. + rotShifts = RotationKey.PickShifts(random); switch (parameters.GetParameter(context, context.CurrentModule, "key", Mode.Normal)) { case Mode.Normal: @@ -79,8 +83,11 @@ public void HandleInject(AntiTamperProtection parent, ConfuserContext context, P initMethod.Body.Instructions.Add(instr); MutationHelper.InjectKeys(initMethod, - new[] { 0, 1, 2, 3, 4, 5 }, - new[] { (int)(name1 * name2), (int)z, (int)x, (int)c, (int)v, (int)feedback }); + new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, + new[] { + (int)(name1 * name2), (int)z, (int)x, (int)c, (int)v, (int)feedback, + rotShifts[0], rotShifts[1], rotShifts[2], rotShifts[3] + }); var name = context.Registry.GetService(); var marker = context.Registry.GetService(); @@ -250,10 +257,10 @@ uint[] DeriveKey() { for (int i = 0; i < 0x10; i++) { dst[i] = v; src[i] = x; - z = (x >> 5) | (x << 27); - x = (c >> 3) | (c << 29); - c = (v >> 7) | (v << 25); - v = (z >> 11) | (z << 21); + z = (x >> rotShifts[0]) | (x << (32 - rotShifts[0])); + x = (c >> rotShifts[1]) | (c << (32 - rotShifts[1])); + c = (v >> rotShifts[2]) | (v << (32 - rotShifts[2])); + v = (z >> rotShifts[3]) | (z << (32 - rotShifts[3])); } return deriver.DeriveKey(dst, src); } diff --git a/Confuser.Protections/AntiTamper/RotationKey.cs b/Confuser.Protections/AntiTamper/RotationKey.cs new file mode 100644 index 000000000..5b30ff064 --- /dev/null +++ b/Confuser.Protections/AntiTamper/RotationKey.cs @@ -0,0 +1,26 @@ +using System; +using Confuser.Core.Services; + +namespace Confuser.Protections.AntiTamper { + /// + /// Picks the rotation amounts for the anti-tamper key-derivation mixer, replacing the fixed + /// 5 / 3 / 7 / 11 that de4dot/AV pattern-match. A bit rotation is a bijection for any amount + /// in 1..31, so -- unlike the xorshift/prime constants -- no curated set is required; the + /// four amounts are simply chosen distinct per module to keep the 16-word key expansion + /// spread. The same amounts are injected into the runtime (Mutation.KeyI6..KeyI9), which + /// forms each rotation as (r >> amount) | (r << (32 - amount)). + /// + internal static class RotationKey { + internal static int[] PickShifts(RandomGenerator random) { + var shifts = new int[4]; + for (int i = 0; i < shifts.Length; i++) { + int s; + do { + s = random.NextInt32(1, 32); + } while (Array.IndexOf(shifts, s, 0, i) != -1); + shifts[i] = s; + } + return shifts; + } + } +} diff --git a/Confuser.Runtime/AntiTamper.Anti.cs b/Confuser.Runtime/AntiTamper.Anti.cs index 7a0a88e7b..90fc94ce2 100644 --- a/Confuser.Runtime/AntiTamper.Anti.cs +++ b/Confuser.Runtime/AntiTamper.Anti.cs @@ -61,14 +61,14 @@ static unsafe void Initialize() { for (int i = 0; i < 0x10; i++) { y[i] = v; d[i] = x; - z = (x >> 5) | (x << 27); - x = (c >> 3) | (c << 29); + z = (x >> Mutation.KeyI6) | (x << (32 - Mutation.KeyI6)); + x = (c >> Mutation.KeyI7) | (c << (32 - Mutation.KeyI7)); CheckRemoteDebuggerPresent(Process.GetCurrentProcess().Handle, ref isDebuggerPresent); if (isDebuggerPresent) Environment.FailFast(null); - c = (v >> 7) | (v << 25); - v = (z >> 11) | (z << 21); + c = (v >> Mutation.KeyI8) | (v << (32 - Mutation.KeyI8)); + v = (z >> Mutation.KeyI9) | (z << (32 - Mutation.KeyI9)); } Mutation.Crypt(y, d); diff --git a/Confuser.Runtime/AntiTamper.JIT.cs b/Confuser.Runtime/AntiTamper.JIT.cs index 876f41f78..01f066dd6 100644 --- a/Confuser.Runtime/AntiTamper.JIT.cs +++ b/Confuser.Runtime/AntiTamper.JIT.cs @@ -52,10 +52,10 @@ public static void Initialize() { for (int i = 0; i < 0x10; i++) { y[i] = v; d[i] = x; - z = (x >> 5) | (x << 27); - x = (c >> 3) | (c << 29); - c = (v >> 7) | (v << 25); - v = (z >> 11) | (z << 21); + z = (x >> Mutation.KeyI6) | (x << (32 - Mutation.KeyI6)); + x = (c >> Mutation.KeyI7) | (c << (32 - Mutation.KeyI7)); + c = (v >> Mutation.KeyI8) | (v << (32 - Mutation.KeyI8)); + v = (z >> Mutation.KeyI9) | (z << (32 - Mutation.KeyI9)); } Mutation.Crypt(y, d); diff --git a/Confuser.Runtime/AntiTamper.Normal.cs b/Confuser.Runtime/AntiTamper.Normal.cs index 1e09da850..615a08dc7 100644 --- a/Confuser.Runtime/AntiTamper.Normal.cs +++ b/Confuser.Runtime/AntiTamper.Normal.cs @@ -45,10 +45,10 @@ static unsafe void Initialize() { for (int i = 0; i < 0x10; i++) { y[i] = v; d[i] = x; - z = (x >> 5) | (x << 27); - x = (c >> 3) | (c << 29); - c = (v >> 7) | (v << 25); - v = (z >> 11) | (z << 21); + z = (x >> Mutation.KeyI6) | (x << (32 - Mutation.KeyI6)); + x = (c >> Mutation.KeyI7) | (c << (32 - Mutation.KeyI7)); + c = (v >> Mutation.KeyI8) | (v << (32 - Mutation.KeyI8)); + v = (z >> Mutation.KeyI9) | (z << (32 - Mutation.KeyI9)); } Mutation.Crypt(y, d);