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
parent
5932a6f9a6
commit
dcf38b3f0f
|
|
@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
// 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)
|
public static INameMaker CreateNameMakerBaseASCIICharSet(string namePrefix)
|
||||||
|
{
|
||||||
|
return CreateNameMakerBaseASCIICharSet(namePrefix, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static INameMaker CreateNameMakerBaseASCIICharSet(string namePrefix, int seed)
|
||||||
{
|
{
|
||||||
var words = new List<string>();
|
var words = new List<string>();
|
||||||
for (int i = 0; i < 26; i++)
|
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());
|
||||||
words.Add(((char)('A' + i)).ToString());
|
words.Add(((char)('A' + i)).ToString());
|
||||||
}
|
}
|
||||||
return new WordSetNameMaker(namePrefix, words);
|
return new WordSetNameMaker(namePrefix, words, seed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
// 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 string _namePrefix;
|
||||||
private readonly List<string> _wordSet;
|
private readonly List<string> _wordSet;
|
||||||
|
private readonly System.Random _random;
|
||||||
|
private readonly int _nameSpace;
|
||||||
private int _nextIndex;
|
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;
|
_namePrefix = namePrefix;
|
||||||
_wordSet = wordSet;
|
_wordSet = wordSet;
|
||||||
_nextIndex = 0;
|
_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)
|
protected override void BuildNewName(StringBuilder nameBuilder, string originalName, string lastName)
|
||||||
{
|
{
|
||||||
nameBuilder.Append(_namePrefix);
|
nameBuilder.Append(_namePrefix);
|
||||||
for (int i = _nextIndex++; ;)
|
for (int i = _random != null ? _random.Next(_nameSpace) : _nextIndex++; ;)
|
||||||
{
|
{
|
||||||
nameBuilder.Append(_wordSet[i % _wordSet.Count]);
|
nameBuilder.Append(_wordSet[i % _wordSet.Count]);
|
||||||
i = i / _wordSet.Count;
|
i = i / _wordSet.Count;
|
||||||
|
|
|
||||||
|
|
@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
// 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 string _namePrefix;
|
||||||
private readonly List<string> _wordSet;
|
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;
|
_namePrefix = namePrefix;
|
||||||
_wordSet = wordSet;
|
_wordSet = wordSet;
|
||||||
|
_seed = seed;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override INameScope CreateNameScope()
|
protected override INameScope CreateNameScope()
|
||||||
|
{
|
||||||
|
if (_seed == 0)
|
||||||
{
|
{
|
||||||
return new NameScope(_namePrefix, _wordSet);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
@ -66,7 +66,7 @@ namespace Obfuz.ObfusPasses.SymbolObfus
|
||||||
_obfuscationRuleFiles = settings.ruleFiles.ToList();
|
_obfuscationRuleFiles = settings.ruleFiles.ToList();
|
||||||
_renameRecordMap = new RenameRecordMap(settings.symbolMappingFile, settings.debug, settings.keepUnknownSymbolInSymbolMappingFile);
|
_renameRecordMap = new RenameRecordMap(settings.symbolMappingFile, settings.debug, settings.keepUnknownSymbolInSymbolMappingFile);
|
||||||
_virtualMethodGroupCalculator = new VirtualMethodGroupCalculator();
|
_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;
|
_customPolicyTypes = settings.customRenamePolicyTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
@ -34,6 +34,7 @@ namespace Obfuz.Settings
|
||||||
public bool detectReflectionCompatibility;
|
public bool detectReflectionCompatibility;
|
||||||
public bool keepUnknownSymbolInSymbolMappingFile;
|
public bool keepUnknownSymbolInSymbolMappingFile;
|
||||||
public string symbolMappingFile;
|
public string symbolMappingFile;
|
||||||
|
public int nameRandomSeed;
|
||||||
public List<string> ruleFiles;
|
public List<string> ruleFiles;
|
||||||
public List<Type> customRenamePolicyTypes;
|
public List<Type> customRenamePolicyTypes;
|
||||||
}
|
}
|
||||||
|
|
@ -58,6 +59,9 @@ namespace Obfuz.Settings
|
||||||
[Tooltip("symbol mapping file path")]
|
[Tooltip("symbol mapping file path")]
|
||||||
public string symbolMappingFile = "Assets/Obfuz/SymbolObfus/symbol-mapping.xml";
|
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")]
|
[Tooltip("debug symbol mapping file path, used for debugging purposes")]
|
||||||
public string debugSymbolMappingFile = "Assets/Obfuz/SymbolObfus/symbol-mapping-debug.xml";
|
public string debugSymbolMappingFile = "Assets/Obfuz/SymbolObfus/symbol-mapping-debug.xml";
|
||||||
|
|
||||||
|
|
@ -82,6 +86,7 @@ namespace Obfuz.Settings
|
||||||
detectReflectionCompatibility = detectReflectionCompatibility,
|
detectReflectionCompatibility = detectReflectionCompatibility,
|
||||||
keepUnknownSymbolInSymbolMappingFile = keepUnknownSymbolInSymbolMappingFile,
|
keepUnknownSymbolInSymbolMappingFile = keepUnknownSymbolInSymbolMappingFile,
|
||||||
symbolMappingFile = GetSymbolMappingFile(),
|
symbolMappingFile = GetSymbolMappingFile(),
|
||||||
|
nameRandomSeed = nameRandomSeed,
|
||||||
ruleFiles = ruleFiles?.ToList() ?? new List<string>(),
|
ruleFiles = ruleFiles?.ToList() ?? new List<string>(),
|
||||||
customRenamePolicyTypes = customRenamePolicyTypes?.Select(typeName => ReflectionUtil.FindUniqueTypeInCurrentAppDomain(typeName)).ToList() ?? new List<Type>(),
|
customRenamePolicyTypes = customRenamePolicyTypes?.Select(typeName => ReflectionUtil.FindUniqueTypeInCurrentAppDomain(typeName)).ToList() ?? new List<Type>(),
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue