垃圾代码生成

dev
walon 2025-06-28 12:12:31 +08:00
parent a833cf26e1
commit 9d46b5438a
14 changed files with 403 additions and 0 deletions

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f47f2abd9eb7ba8469ba5cb1bb085d33
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,193 @@
using dnlib.DotNet;
using NUnit.Framework;
using Obfuz.Settings;
using Obfuz.Utils;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine;
namespace Obfuz.GarbageCodeGeneration
{
public abstract class SpecificGarbageCodeGeneratorBase : ISpecificGarbageCodeGenerator
{
protected interface IClassGenerationInfo
{
string Namespace { get; set; }
string Name { get; set; }
IList<object> Fields { get; set; }
IList<object> Methods { get; set; }
}
protected class ClassGenerationInfo : IClassGenerationInfo
{
public string Namespace { get; set; }
public string Name { get; set; }
public IList<object> Fields { get; set; } = new List<object>();
public IList<object> Methods { get; set; } = new List<object>();
}
public virtual void Generate(GenerationParameters parameters)
{
FileUtil.RecreateDir(parameters.outputPath);
for (int i = 0; i < parameters.classCount; i++)
{
Debug.Log($"[{GetType().Name}] Generating class {i}");
var localRandom = new RandomWithKey(((RandomWithKey)parameters.random).Key, parameters.random.NextInt());
string outputFile = $"{parameters.outputPath}/__GeneratedGarbageClass_{i}.cs";
var result = new StringBuilder(64 * 1024);
GenerateClass(i, localRandom, result, parameters);
File.WriteAllText(outputFile, result.ToString(), Encoding.UTF8);
Debug.Log($"[{GetType().Name}] Generated class {i} to {outputFile}");
}
}
protected virtual void GenerateClass(int classIndex, IRandom random, StringBuilder result, GenerationParameters parameters)
{
IClassGenerationInfo cgi = CreateClassGenerationInfo(parameters.classNamespace, $"{parameters.classNamePrefix}{classIndex}", random, parameters);
result.AppendLine("using System;");
result.AppendLine("using System.Collections.Generic;");
result.AppendLine("using System.Linq;");
result.AppendLine("using System.IO;");
result.AppendLine("using UnityEngine;");
GenerateUsings(result, cgi);
result.AppendLine($"namespace {cgi.Namespace}");
result.AppendLine("{");
result.AppendLine($" public class {cgi.Name}");
result.AppendLine(" {");
string indent = " ";
foreach (object field in cgi.Fields)
{
GenerateField(result, cgi, field, indent);
}
foreach (object method in cgi.Methods)
{
GenerateMethod(result, cgi, method, indent);
}
result.AppendLine(" }");
result.AppendLine("}");
}
protected abstract IClassGenerationInfo CreateClassGenerationInfo(string classNamespace, string className, IRandom random, GenerationParameters parameters);
protected abstract void GenerateUsings(StringBuilder result, IClassGenerationInfo cgi);
protected abstract void GenerateField(StringBuilder result, IClassGenerationInfo cgi, object field, string indent);
protected abstract void GenerateMethod(StringBuilder result, IClassGenerationInfo cgi, object method, string indent);
}
public class ConfigGarbageCodeGenerator : SpecificGarbageCodeGeneratorBase
{
class FieldGenerationInfo
{
public int index;
public string name;
public string type;
}
class MethodGenerationInfo
{
public int index;
public string name;
}
protected override IClassGenerationInfo CreateClassGenerationInfo(string classNamespace, string className, IRandom random, GenerationParameters parameters)
{
var cgi = new ClassGenerationInfo
{
Namespace = classNamespace,
Name = className,
};
for (int i = 0; i < parameters.fieldCountPerClass; i++)
{
var fieldInfo = new FieldGenerationInfo
{
index = i,
name = $"x{i}",
type = CreateRandomType(random),
};
cgi.Fields.Add(fieldInfo);
}
for (int i = 0; i < parameters.methodCountPerClass; i++)
{
var methodInfo = new MethodGenerationInfo
{
index = i,
name = $"Load{i}",
};
cgi.Methods.Add(methodInfo);
}
return cgi;
}
private readonly string[] _types = new string[]
{
"bool",
"byte",
"short",
"int",
"long",
"float",
"double",
};
private string CreateRandomType(IRandom random)
{
return _types[random.NextInt(_types.Length)];
}
protected override void GenerateUsings(StringBuilder result, IClassGenerationInfo cgi)
{
}
protected override void GenerateField(StringBuilder result, IClassGenerationInfo cgi, object field, string indent)
{
var fgi = (FieldGenerationInfo)field;
result.AppendLine($"{indent}public {fgi.type} {fgi.name};");
}
private string GetReadMethodNameOfType(string type)
{
switch (type)
{
case "bool": return "ReadBoolean";
case "byte": return "ReadByte";
case "short": return "ReadInt16";
case "int": return "ReadInt32";
case "long": return "ReadInt64";
case "float": return "ReadSingle";
case "double": return "ReadDouble";
default: throw new ArgumentException($"Unsupported type: {type}");
}
}
protected override void GenerateMethod(StringBuilder result, IClassGenerationInfo cgi, object method, string indent)
{
result.AppendLine($"{indent}void Load(BinaryReader reader)");
result.AppendLine($"{indent}{{");
string indent2 = indent + " ";
foreach (FieldGenerationInfo fgi in cgi.Fields)
{
result.AppendLine($"{indent2}this.{fgi.name} = reader.{GetReadMethodNameOfType(fgi.type)}();");
}
result.AppendLine($"{indent}}}");
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 327cb4a465ff23944a5fea30bf3beeeb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,73 @@
using Obfuz.Settings;
using Obfuz.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace Obfuz.GarbageCodeGeneration
{
public class GarbageCodeGenerator
{
private const int CodeGenerationSecretKeyLength = 1024;
private readonly GarbageCodeGeneratorSettings _settings;
private readonly int[] _intGenerationSecretKey;
public GarbageCodeGenerator(GarbageCodeGeneratorSettings settings)
{
_settings = settings;
byte[] byteGenerationSecretKey = KeyGenerator.GenerateKey(settings.codeGenerationSecret, CodeGenerationSecretKeyLength);
_intGenerationSecretKey = KeyGenerator.ConvertToIntKey(byteGenerationSecretKey);
}
public void Generate()
{
GenerateTask(_settings.defaultTask);
if (_settings.additionalTasks != null && _settings.additionalTasks.Length > 0)
{
foreach (var task in _settings.additionalTasks)
{
GenerateTask(task);
}
}
}
private void GenerateTask(GarbageCodeGenerationTask task)
{
Debug.Log($"Generating garbage code with seed: {task.codeGenerationRandomSeed}, class count: {task.classCount}, method count per class: {task.methodCountPerClass}, types: {task.garbageCodeTypes}, output path: {task.outputPath}");
var generator = CreateSpecificCodeGenerator(task.garbageCodeTypes);
var parameters = new GenerationParameters
{
random = new RandomWithKey(_intGenerationSecretKey, task.codeGenerationRandomSeed),
classNamespace = task.classNamespace,
classNamePrefix = task.classNamePrefix,
classCount = task.classCount,
methodCountPerClass = task.methodCountPerClass,
fieldCountPerClass = task.fieldCountPerClass,
outputPath = task.outputPath
};
generator.Generate(parameters);
Debug.Log($"Generate garbage code end.");
}
private ISpecificGarbageCodeGenerator CreateSpecificCodeGenerator(GarbageCodeType type)
{
switch (type)
{
case GarbageCodeType.Config:
return new ConfigGarbageCodeGenerator();
// Add cases for other types as needed
default:
throw new NotSupportedException($"Garbage code type {type} is not supported.");
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ff64fd1e6f7b8874db5a5228fab159f9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,22 @@
using Obfuz.Settings;
using Obfuz.Utils;
namespace Obfuz.GarbageCodeGeneration
{
public class GenerationParameters
{
public IRandom random;
public string classNamespace;
public string classNamePrefix;
public int classCount;
public int methodCountPerClass;
public int fieldCountPerClass;
public string outputPath;
}
public interface ISpecificGarbageCodeGenerator
{
void Generate(GenerationParameters parameters);
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 74a17802b5aab2e40a3c89e0ddbcec0d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -5,6 +5,7 @@ using UnityEngine;
namespace Obfuz.Settings namespace Obfuz.Settings
{ {
[Serializable] [Serializable]
public class AssemblySettings public class AssemblySettings
{ {

View File

@ -0,0 +1,41 @@
using System;
namespace Obfuz.Settings
{
public enum GarbageCodeType
{
None,
Config,
UI,
}
[Serializable]
public class GarbageCodeGenerationTask
{
public int codeGenerationRandomSeed;
public string classNamespace = "__GarbageCode";
public string classNamePrefix = "__GeneratedGarbageClass";
public int classCount = 100;
public int methodCountPerClass = 30;
public int fieldCountPerClass = 50;
public GarbageCodeType garbageCodeTypes = GarbageCodeType.Config;
public string outputPath = "Assets/Obfuz/GarbageCode";
}
[Serializable]
public class GarbageCodeGeneratorSettings
{
public string codeGenerationSecret = "Garbage Code";
public GarbageCodeGenerationTask defaultTask;
public GarbageCodeGenerationTask[] additionalTasks;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 220b44e477cfa2848bd287c38db4fd21
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -43,6 +43,9 @@ namespace Obfuz.Settings
[Tooltip("control flow obfuscation settings")] [Tooltip("control flow obfuscation settings")]
public ControlFlowObfuscationSettings controlFlowObfuscationSettings; public ControlFlowObfuscationSettings controlFlowObfuscationSettings;
[Tooltip("garbage code generator settings")]
public GarbageCodeGeneratorSettings garbageCodeGeneratorSettings;
public string ObfuzRootDir => $"Library/Obfuz"; public string ObfuzRootDir => $"Library/Obfuz";
public string GetObfuscatedAssemblyOutputPath(BuildTarget target) public string GetObfuscatedAssemblyOutputPath(BuildTarget target)

View File

@ -38,6 +38,8 @@ namespace Obfuz.Settings
private SerializedProperty _exprObfusSettings; private SerializedProperty _exprObfusSettings;
private SerializedProperty _controlFlowObfusSettings; private SerializedProperty _controlFlowObfusSettings;
private SerializedProperty _garbageCodeGeneratorSettings;
public ObfuzSettingsProvider() : base("Project/Obfuz", SettingsScope.Project) public ObfuzSettingsProvider() : base("Project/Obfuz", SettingsScope.Project)
{ {
} }
@ -72,6 +74,8 @@ namespace Obfuz.Settings
_fieldEncryptSettings = _serializedObject.FindProperty("fieldEncryptSettings"); _fieldEncryptSettings = _serializedObject.FindProperty("fieldEncryptSettings");
_callObfusSettings = _serializedObject.FindProperty("callObfusSettings"); _callObfusSettings = _serializedObject.FindProperty("callObfusSettings");
_controlFlowObfusSettings = _serializedObject.FindProperty("controlFlowObfuscationSettings"); _controlFlowObfusSettings = _serializedObject.FindProperty("controlFlowObfuscationSettings");
_garbageCodeGeneratorSettings = _serializedObject.FindProperty("garbageCodeGeneratorSettings");
} }
public override void OnGUI(string searchContext) public override void OnGUI(string searchContext)
@ -98,6 +102,7 @@ namespace Obfuz.Settings
EditorGUILayout.PropertyField(_callObfusSettings); EditorGUILayout.PropertyField(_callObfusSettings);
EditorGUILayout.PropertyField(_controlFlowObfusSettings); EditorGUILayout.PropertyField(_controlFlowObfusSettings);
EditorGUILayout.PropertyField(_garbageCodeGeneratorSettings);
if (EditorGUI.EndChangeCheck()) if (EditorGUI.EndChangeCheck())
{ {

View File

@ -1,4 +1,5 @@
using Obfuz.EncryptionVM; using Obfuz.EncryptionVM;
using Obfuz.GarbageCodeGeneration;
using Obfuz.Settings; using Obfuz.Settings;
using Obfuz.Utils; using Obfuz.Utils;
using System.IO; using System.IO;
@ -36,6 +37,16 @@ namespace Obfuz.Unity
AssetDatabase.Refresh(); AssetDatabase.Refresh();
} }
[MenuItem("Obfuz/GenerateGarbageCodes", priority = 100)]
public static void GenerateGarbageCodes()
{
Debug.Log($"Generating garbage codes begin.");
GarbageCodeGeneratorSettings settings = ObfuzSettings.Instance.garbageCodeGeneratorSettings;
var generator = new GarbageCodeGenerator(settings);
generator.Generate();
Debug.Log($"Generating garbage codes end.");
}
private static void SaveKey(byte[] secret, string secretOutputPath) private static void SaveKey(byte[] secret, string secretOutputPath)
{ {
FileUtil.CreateParentDir(secretOutputPath); FileUtil.CreateParentDir(secretOutputPath);

View File

@ -18,6 +18,8 @@
_seed = seed; _seed = seed;
} }
public int[] Key => _key;
public int NextInt(int min, int max) public int NextInt(int min, int max)
{ {
return min + NextInt(max - min); return min + NextInt(max - min);