Add symbolObfusSettings.nameRandomSeed to randomise generated symbol names

Upstream assigns obfuscated names from a monotonic base-52 counter, so two
builds of the same source produce an identical mapping and a build with a
small source change keeps almost every previous name. An attacker who
reverses build N therefore carries that work forward to build N+1.

nameRandomSeed = 0 keeps the original counter, so this is opt-in and the
default behaviour is unchanged.
pull/36/head
Gabriel Olivato 2026-08-19 17:53:01 +01:00
parent 5932a6f9a6
commit dcf38b3f0f
5 changed files with 51 additions and 11 deletions

View File

@ -1,4 +1,4 @@
// Copyright 2025 Code Philosophy
// Copyright 2025 Code Philosophy
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -30,6 +30,11 @@ namespace Obfuz.ObfusPasses.SymbolObfus.NameMakers
}
public static INameMaker CreateNameMakerBaseASCIICharSet(string namePrefix)
{
return CreateNameMakerBaseASCIICharSet(namePrefix, 0);
}
public static INameMaker CreateNameMakerBaseASCIICharSet(string namePrefix, int seed)
{
var words = new List<string>();
for (int i = 0; i < 26; i++)
@ -37,7 +42,7 @@ namespace Obfuz.ObfusPasses.SymbolObfus.NameMakers
words.Add(((char)('a' + i)).ToString());
words.Add(((char)('A' + i)).ToString());
}
return new WordSetNameMaker(namePrefix, words);
return new WordSetNameMaker(namePrefix, words, seed);
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright 2025 Code Philosophy
// Copyright 2025 Code Philosophy
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -28,19 +28,35 @@ namespace Obfuz.ObfusPasses.SymbolObfus.NameMakers
{
private readonly string _namePrefix;
private readonly List<string> _wordSet;
private readonly System.Random _random;
private readonly int _nameSpace;
private int _nextIndex;
public NameScope(string namePrefix, List<string> wordSet)
public NameScope(string namePrefix, List<string> wordSet) : this(namePrefix, wordSet, 0)
{
}
// A zero seed keeps the original deterministic base-N counter. Any other seed draws
// names at random from a space wide enough that collisions are rare; NameScopeBase
// retries on collision, so correctness does not depend on the space being large.
public NameScope(string namePrefix, List<string> wordSet, int seed)
{
_namePrefix = namePrefix;
_wordSet = wordSet;
_nextIndex = 0;
_random = seed != 0 ? new System.Random(seed) : null;
int space = 1;
for (int i = 0; i < 4; i++)
{
space *= wordSet.Count;
}
_nameSpace = space;
}
protected override void BuildNewName(StringBuilder nameBuilder, string originalName, string lastName)
{
nameBuilder.Append(_namePrefix);
for (int i = _nextIndex++; ;)
for (int i = _random != null ? _random.Next(_nameSpace) : _nextIndex++; ;)
{
nameBuilder.Append(_wordSet[i % _wordSet.Count]);
i = i / _wordSet.Count;

View File

@ -1,4 +1,4 @@
// Copyright 2025 Code Philosophy
// Copyright 2025 Code Philosophy
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -27,16 +27,30 @@ namespace Obfuz.ObfusPasses.SymbolObfus.NameMakers
{
private readonly string _namePrefix;
private readonly List<string> _wordSet;
private readonly int _seed;
private int _scopeIndex;
public WordSetNameMaker(string namePrefix, List<string> wordSet)
public WordSetNameMaker(string namePrefix, List<string> wordSet) : this(namePrefix, wordSet, 0)
{
}
public WordSetNameMaker(string namePrefix, List<string> wordSet, int seed)
{
_namePrefix = namePrefix;
_wordSet = wordSet;
_seed = seed;
}
protected override INameScope CreateNameScope()
{
if (_seed == 0)
{
return new NameScope(_namePrefix, _wordSet);
}
// Distinct per scope, otherwise every scope would emit the same sequence.
int scopeSeed = unchecked(_seed + _scopeIndex++ * (int)0x9E3779B9);
return new NameScope(_namePrefix, _wordSet, scopeSeed != 0 ? scopeSeed : 1);
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright 2025 Code Philosophy
// Copyright 2025 Code Philosophy
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -66,7 +66,7 @@ namespace Obfuz.ObfusPasses.SymbolObfus
_obfuscationRuleFiles = settings.ruleFiles.ToList();
_renameRecordMap = new RenameRecordMap(settings.symbolMappingFile, settings.debug, settings.keepUnknownSymbolInSymbolMappingFile);
_virtualMethodGroupCalculator = new VirtualMethodGroupCalculator();
_nameMaker = settings.debug ? NameMakerFactory.CreateDebugNameMaker() : NameMakerFactory.CreateNameMakerBaseASCIICharSet(settings.obfuscatedNamePrefix);
_nameMaker = settings.debug ? NameMakerFactory.CreateDebugNameMaker() : NameMakerFactory.CreateNameMakerBaseASCIICharSet(settings.obfuscatedNamePrefix, settings.nameRandomSeed);
_customPolicyTypes = settings.customRenamePolicyTypes;
}

View File

@ -1,4 +1,4 @@
// Copyright 2025 Code Philosophy
// Copyright 2025 Code Philosophy
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -34,6 +34,7 @@ namespace Obfuz.Settings
public bool detectReflectionCompatibility;
public bool keepUnknownSymbolInSymbolMappingFile;
public string symbolMappingFile;
public int nameRandomSeed;
public List<string> ruleFiles;
public List<Type> customRenamePolicyTypes;
}
@ -58,6 +59,9 @@ namespace Obfuz.Settings
[Tooltip("symbol mapping file path")]
public string symbolMappingFile = "Assets/Obfuz/SymbolObfus/symbol-mapping.xml";
[Tooltip("random seed for generated names. 0 keeps the original deterministic sequence; any other value randomises which name each symbol gets, so the mapping differs between builds")]
public int nameRandomSeed = 0;
[Tooltip("debug symbol mapping file path, used for debugging purposes")]
public string debugSymbolMappingFile = "Assets/Obfuz/SymbolObfus/symbol-mapping-debug.xml";
@ -82,6 +86,7 @@ namespace Obfuz.Settings
detectReflectionCompatibility = detectReflectionCompatibility,
keepUnknownSymbolInSymbolMappingFile = keepUnknownSymbolInSymbolMappingFile,
symbolMappingFile = GetSymbolMappingFile(),
nameRandomSeed = nameRandomSeed,
ruleFiles = ruleFiles?.ToList() ?? new List<string>(),
customRenamePolicyTypes = customRenamePolicyTypes?.Select(typeName => ReflectionUtil.FindUniqueTypeInCurrentAppDomain(typeName)).ToList() ?? new List<Type>(),
};