Compare commits

..

No commits in common. "main" and "1.0.0-alpha" have entirely different histories.

510 changed files with 23296 additions and 13291 deletions

22
.gitignore vendored Normal file
View File

@ -0,0 +1,22 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
**/Library/
**/Logs/
**/Temp/
**/Build-*/
**/Release-*/
**/Debug-*/
**/.vs/
**/bin/
**/obj/
.vsconfig
**/UserSettings/
*.csproj
*.sln
packages-lock.json

View File

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable>
<Version>1.0.0</Version>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.9.1" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,24 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.13.35931.197
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeobfuscateStackTrace", "DeobfuscateStackTrace.csproj", "{B7192F39-1EEA-4F31-885B-B606D700FC79}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B7192F39-1EEA-4F31-885B-B606D700FC79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B7192F39-1EEA-4F31-885B-B606D700FC79}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B7192F39-1EEA-4F31-885B-B606D700FC79}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B7192F39-1EEA-4F31-885B-B606D700FC79}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9F39E3ED-EF31-43DE-B085-0F7BF60844E8}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,57 @@
using CommandLine;
namespace DeobfuscateStackTrace
{
internal class Program
{
private class CommandOptions
{
[Option('m', "mappingFile", Required = true, HelpText = "mapping xml file")]
public string MappingFile { get; set; }
[Option('i', "input", Required = true, HelpText = "input obfuscated log file")]
public string InputFile { get; set; }
[Option('o', "output", Required = true, HelpText = "output deobfuscated log file")]
public string OutputFile { get; set; }
}
static void Main(string[] args)
{
CommandOptions opt = ParseArgs(args);
if (!File.Exists(opt.MappingFile))
{
Console.Error.WriteLine($"Mapping file {opt.MappingFile} not found");
Environment.Exit(1);
}
if (!File.Exists(opt.InputFile))
{
Console.Error.WriteLine($"Input file {opt.InputFile} not found");
Environment.Exit(1);
}
var reader = new SymbolMappingReader(opt.MappingFile);
StackTraceDeObfuscator.Convert(reader, opt.InputFile, opt.OutputFile);
}
private static CommandOptions ParseArgs(string[] args)
{
var helpWriter = new StringWriter();
var parser = new Parser(settings =>
{
settings.AllowMultiInstance = true;
settings.HelpWriter = helpWriter;
});
var result = parser.ParseArguments<CommandOptions>(args);
if (result.Tag == ParserResultType.NotParsed)
{
Console.Error.WriteLine(helpWriter.ToString());
Environment.Exit(1);
}
return ((Parsed<CommandOptions>)result).Value;
}
}
}

View File

@ -0,0 +1,8 @@
{
"profiles": {
"DeobfuscateStackTrace": {
"commandName": "Project",
"commandLineArgs": "-m ../../../mapping.xml -i ../../../obfuscated.log -o ../../../deobfuscated.log"
}
}
}

View File

@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DeobfuscateStackTrace
{
public class StackTraceDeObfuscator
{
public static void Convert(SymbolMappingReader reader, string oldLogFile, string newLogFile)
{
var obfuscatedLines = File.ReadAllLines(oldLogFile, Encoding.UTF8);
var deObfuscatedLines = new List<string>();
bool logLineFound = false;
foreach (string line in obfuscatedLines)
{
if (TryConvertLine(line, reader, ref logLineFound, out var newLine))
{
deObfuscatedLines.Add(newLine);
}
else
{
deObfuscatedLines.Add(line);
}
}
File.WriteAllLines(newLogFile, deObfuscatedLines, Encoding.UTF8);
}
private static bool TryConvertLine(string line, SymbolMappingReader reader, ref bool logLineFound, out string deObfuscatedStackTrace)
{
deObfuscatedStackTrace = line;
if (string.IsNullOrEmpty(line))
{
logLineFound = false;
return false;
}
if (!logLineFound)
{
logLineFound = line.StartsWith("UnityEngine.DebugLogHandler:Internal_Log")
|| line.StartsWith("UnityEngine.DebugLogHandler:LogFormat")
|| line.StartsWith("UnityEngine.Logger:Log");
return false;
}
return reader.TryDeObfuscateStackTrace(line, out deObfuscatedStackTrace);
}
}
}

View File

@ -0,0 +1,128 @@
using System.Xml;
namespace DeobfuscateStackTrace
{
public class SymbolMappingReader
{
private readonly Dictionary<string, List<string>> _fullSignatureMapper = new Dictionary<string, List<string>>();
private readonly Dictionary<string, List<string>> _signatureWithParamsMapper = new Dictionary<string, List<string>>();
public SymbolMappingReader(string mappingFile)
{
LoadXmlMappingFile(mappingFile);
}
private void LoadXmlMappingFile(string mappingFile)
{
var doc = new XmlDocument();
doc.Load(mappingFile);
var root = doc.DocumentElement;
foreach (XmlNode node in root.ChildNodes)
{
if (!(node is XmlElement element))
{
continue;
}
LoadAssemblyMapping(element);
}
}
private void LoadAssemblyMapping(XmlElement ele)
{
if (ele.Name != "assembly")
{
throw new System.Exception($"Invalid node name: {ele.Name}. Expected 'assembly'.");
}
foreach (XmlNode node in ele.ChildNodes)
{
if (!(node is XmlElement element))
{
continue;
}
if (element.Name == "type")
{
LoadTypeMapping(element);
}
}
}
private void LoadTypeMapping(XmlElement ele)
{
foreach (XmlNode node in ele.ChildNodes)
{
if (!(node is XmlElement c))
{
continue;
}
if (node.Name == "method")
{
LoadMethodMapping(c);
}
}
}
private string GetMethodSignatureWithoutParams(string signature)
{
int index = signature.IndexOf('(');
if (index < 0)
{
return signature;
}
return signature.Substring(0, index);
}
private void LoadMethodMapping(XmlElement ele)
{
if (!ele.HasAttribute("oldStackTraceSignature"))
{
throw new System.Exception($"Invalid node name: {ele.Name}. attribute 'oldStackTraceSignature' missing.");
}
if (!ele.HasAttribute("newStackTraceSignature"))
{
throw new System.Exception($"Invalid node name: {ele.Name}. attribute 'newStackTraceSignature' missing.");
}
string oldStackTraceSignature = ele.Attributes["oldStackTraceSignature"].Value;
string newStackTraceSignature = ele.Attributes["newStackTraceSignature"].Value;
if (!_fullSignatureMapper.TryGetValue(newStackTraceSignature, out var oldFullSignatures))
{
oldFullSignatures = new List<string>();
_fullSignatureMapper[newStackTraceSignature] = oldFullSignatures;
}
oldFullSignatures.Add(oldStackTraceSignature);
string oldStackTraceSignatureWithoutParams = GetMethodSignatureWithoutParams(oldStackTraceSignature);
string newStackTraceSignatureWithoutParams = GetMethodSignatureWithoutParams(newStackTraceSignature);
if (!_signatureWithParamsMapper.TryGetValue(newStackTraceSignatureWithoutParams, out var oldSignaturesWithoutParams))
{
oldSignaturesWithoutParams = new List<string>();
_signatureWithParamsMapper[newStackTraceSignatureWithoutParams] = oldSignaturesWithoutParams;
}
oldSignaturesWithoutParams.Add(oldStackTraceSignatureWithoutParams);
}
public bool TryDeObfuscateStackTrace(string obfuscatedStackTraceLog, out string deObfuscatedStackTrace)
{
obfuscatedStackTraceLog = obfuscatedStackTraceLog.Trim();
if (_fullSignatureMapper.TryGetValue(obfuscatedStackTraceLog, out var oldFullSignatures))
{
deObfuscatedStackTrace = string.Join("|", oldFullSignatures);
return true;
}
string obfuscatedStackTraceSignatureWithoutParams = GetMethodSignatureWithoutParams(obfuscatedStackTraceLog);
if (_signatureWithParamsMapper.TryGetValue(obfuscatedStackTraceSignatureWithoutParams, out var oldSignaturesWithoutParams))
{
deObfuscatedStackTrace = obfuscatedStackTraceLog.Replace(obfuscatedStackTraceSignatureWithoutParams, string.Join("|", oldSignaturesWithoutParams));
return true;
}
deObfuscatedStackTrace = null;
return false;
}
}
}

View File

@ -0,0 +1,17 @@
test stack trace
UnityEngine.DebugLogHandler:Internal_Log(LogType, LogOption, String, Object)
UnityEngine.DebugLogHandler:LogFormat(LogType, Object, String, Object[])
UnityEngine.Logger:Log(LogType, Object)
UnityEngine.Debug:Log(Object)
Obfus2.TestStackTrace:Stack3()
Obfus2.NestedClass`1:Stack2(TestStackTrace, Int32[], List`1, Banana)
Obfus2.TestStackTrace:Stack1(Int64, UInt64, Single, Double, String, Object)
Obfus2.TestStackTrace:Stack0(Byte, SByte, Int16, UInt16, Int32, UInt32)
Tests.TC_StackTrace:PrintStackTrace()
System.Reflection.RuntimeMethodInfo:InternalInvoke(Object, Object[], Exception&)
System.Reflection.RuntimeMethodInfo:Invoke(Object, BindingFlags, Binder, Object[], CultureInfo)
System.Reflection.MethodBase:Invoke(Object, Object[])
SharpUnit.TestCase:Run(TestResult)
SharpUnit.TestSuite:Run(TestResult)
TestRunner:Run()
Bootstrap:Start()

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,17 @@
test stack trace
UnityEngine.DebugLogHandler:Internal_Log(LogType, LogOption, String, Object)
UnityEngine.DebugLogHandler:LogFormat(LogType, Object, String, Object[])
UnityEngine.Logger:Log(LogType, Object)
UnityEngine.Debug:Log(Object)
F.g:A()
F.G:a(g, Int32[], List`1, Banana)
F.g:a(Int64, UInt64, Single, Double, String, Object)
F.g:b(Byte, SByte, Int16, UInt16, Int32, UInt32)
Tests.TC_StackTrace:PrintStackTrace()
System.Reflection.RuntimeMethodInfo:InternalInvoke(Object, Object[], Exception&)
System.Reflection.RuntimeMethodInfo:Invoke(Object, BindingFlags, Binder, Object[], CultureInfo)
System.Reflection.MethodBase:Invoke(Object, Object[])
SharpUnit.TestCase:Run(TestResult)
SharpUnit.TestSuite:Run(TestResult)
TestRunner:Run()
Bootstrap:Start()

View File

@ -1,32 +0,0 @@
namespace Obfuz.Editor
{
public static class ConstValues
{
public const string ObfuzInternalSymbolNamePrefix = "$Obfuz$";
public const string ObfuzRuntimeAssemblyName = "Obfuz.Runtime";
public const string ObfuzIgnoreAttributeFullName = "Obfuz.ObfuzIgnoreAttribute";
public const string ObfuzScopeFullName = "Obfuz.ObfuzScope";
public const string EncryptFieldAttributeFullName = "Obfuz.EncryptFieldAttribute";
public const string GeneratedEncryptionVirtualMachineFullName = "Obfuz.EncryptionVM.GeneratedEncryptionVirtualMachine";
public const string EmbeddedAttributeFullName = "Microsoft.CodeAnalysis.EmbeddedAttribute";
public const string MonoPInvokeCallbackAttributeName = "MonoPInvokeCallbackAttribute";
public const string ZluaLuaInvokeAttributeFullName = "Zlua.LuaInvokeAttribute";
public const string ZluaLuaCallbackAttributeFullName = "Zlua.LuaCallbackAttribute";
public const string ZluaLuaMarshalAsAttributeFullName = "Zlua.LuaMarshalAsAttribute";
public const string BurstCompileFullName = "Unity.Burst.BurstCompileAttribute";
public const string DOTSCompilerGeneratedAttributeFullName = "Unity.Jobs.DOTSCompilerGeneratedAttribute";
public const string RuntimeInitializedOnLoadMethodAttributeFullName = "UnityEngine.RuntimeInitializeOnLoadMethodAttribute";
public const string BlackboardEnumAttributeFullName = "Unity.Behavior.BlackboardEnumAttribute";
public const string CompilerGeneratedAttributeFullName = "System.Runtime.CompilerServices.CompilerGeneratedAttribute";
}
}

View File

@ -1,323 +0,0 @@
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using Obfuz.Emit;
using Obfuz.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine.Assertions;
namespace Obfuz.Data
{
public struct RvaData
{
public readonly FieldDef field;
public readonly int offset;
public readonly int size;
public RvaData(FieldDef field, int offset, int size)
{
this.field = field;
this.offset = offset;
this.size = size;
}
}
public class RvaDataAllocator : GroupByModuleEntityBase
{
const int maxRvaDataSize = 2 * 1024;
// in HybridCLR version below 8.3.0, the max total static field size of a type is 16KB, so we limit the total size of RVA data to 16KB
const int maxTotalRvaDataFieldSizeInHybridCLR = 16 * 1024;
private IRandom _random;
class RvaField
{
public FieldDef holderDataField;
public FieldDef runtimeValueField;
public int encryptionOps;
public uint size;
public List<byte> bytes;
public int salt;
public void FillPaddingToSize(int newSize)
{
for (int i = bytes.Count; i < newSize; i++)
{
bytes.Add(0xAB);
}
}
public void FillPaddingToEnd()
{
// fill with random value
for (int i = bytes.Count; i < size; i++)
{
bytes.Add(0xAB);
}
}
}
private class RvaTypeDefInfo
{
public readonly TypeDef typeDef;
public readonly int index;
public readonly List<RvaField> rvaFields = new List<RvaField>();
public RvaTypeDefInfo(TypeDef typeDef, int index)
{
this.typeDef = typeDef;
this.index = index;
}
}
private RvaField _currentField;
private RvaTypeDefInfo _currentRvaType;
private readonly List<RvaTypeDefInfo> _rvaTypeDefs = new List<RvaTypeDefInfo>();
private readonly Dictionary<int, TypeDef> _dataHolderTypeBySizes = new Dictionary<int, TypeDef>();
private bool _done;
public RvaDataAllocator()
{
}
public override void Init()
{
_random = EncryptionScope.localRandomCreator(HashUtil.ComputeHash(Module.Name));
}
private (FieldDef, FieldDef) CreateDataHolderRvaField(TypeDef dataHolderType)
{
if (_currentRvaType == null || _currentRvaType.rvaFields.Count >= maxTotalRvaDataFieldSizeInHybridCLR / maxRvaDataSize - 1)
{
using (var scope = new DisableTypeDefFindCacheScope(Module))
{
var rvaTypeDef = new TypeDefUser($"$Obfuz$RVA${_rvaTypeDefs.Count}", Module.CorLibTypes.Object.ToTypeDefOrRef());
Module.Types.Add(rvaTypeDef);
_currentRvaType = new RvaTypeDefInfo(rvaTypeDef, _rvaTypeDefs.Count);
_rvaTypeDefs.Add(_currentRvaType);
}
}
var holderField = new FieldDefUser($"$RVA_Data{_currentRvaType.rvaFields.Count}", new FieldSig(dataHolderType.ToTypeSig()), FieldAttributes.InitOnly | FieldAttributes.Static | FieldAttributes.HasFieldRVA);
holderField.DeclaringType = _currentRvaType.typeDef;
var runtimeValueField = new FieldDefUser($"$RVA_Value{_currentRvaType.rvaFields.Count}", new FieldSig(new SZArraySig(Module.CorLibTypes.Byte)), FieldAttributes.Static | FieldAttributes.Public);
runtimeValueField.DeclaringType = _currentRvaType.typeDef;
return (holderField, runtimeValueField);
}
private TypeDef GetDataHolderType(int size)
{
size = (size + 15) & ~15; // align to 16 bytes
if (_dataHolderTypeBySizes.TryGetValue(size, out var type))
return type;
using (var scope = new DisableTypeDefFindCacheScope(Module))
{
var dataHolderType = new TypeDefUser($"$ObfuzRVA$DataHolder{size}", Module.Import(typeof(ValueType)));
dataHolderType.Attributes = TypeAttributes.Public | TypeAttributes.Sealed;
dataHolderType.Layout = TypeAttributes.ExplicitLayout;
dataHolderType.PackingSize = 1;
dataHolderType.ClassSize = (uint)size;
_dataHolderTypeBySizes.Add(size, dataHolderType);
Module.Types.Add(dataHolderType);
return dataHolderType;
}
}
private static int AlignTo(int size, int alignment)
{
return (size + alignment - 1) & ~(alignment - 1);
}
private RvaField CreateRvaField(int size)
{
TypeDef dataHolderType = GetDataHolderType(size);
var (holderDataField, runtimeValueField) = CreateDataHolderRvaField(dataHolderType);
var newRvaField = new RvaField
{
holderDataField = holderDataField,
runtimeValueField = runtimeValueField,
size = dataHolderType.ClassSize,
bytes = new List<byte>((int)dataHolderType.ClassSize),
encryptionOps = _random.NextInt(),
salt = _random.NextInt(),
};
_currentRvaType.rvaFields.Add(newRvaField);
return newRvaField;
}
private RvaField GetRvaField(int preservedSize, int alignment)
{
if (_done)
{
throw new Exception("can't GetRvaField after done");
}
Assert.IsTrue(preservedSize % alignment == 0);
// for big size, create a new field
if (preservedSize >= maxRvaDataSize)
{
return CreateRvaField(preservedSize);
}
if (_currentField != null)
{
int offset = AlignTo(_currentField.bytes.Count, alignment);
int expectedSize = offset + preservedSize;
if (expectedSize <= _currentField.size)
{
_currentField.FillPaddingToSize(offset);
return _currentField;
}
_currentField.FillPaddingToEnd();
}
_currentField = CreateRvaField(maxRvaDataSize);
return _currentField;
}
public RvaData Allocate(int value)
{
RvaField field = GetRvaField(4, 4);
int offset = field.bytes.Count;
Assert.IsTrue(offset % 4 == 0);
field.bytes.AddRange(BitConverter.GetBytes(value));
return new RvaData(field.runtimeValueField, offset, 4);
}
public RvaData Allocate(long value)
{
RvaField field = GetRvaField(8, 8);
int offset = field.bytes.Count;
Assert.IsTrue(offset % 8 == 0);
field.bytes.AddRange(BitConverter.GetBytes(value));
return new RvaData(field.runtimeValueField, offset, 8);
}
public RvaData Allocate(float value)
{
RvaField field = GetRvaField(4, 4);
int offset = field.bytes.Count;
Assert.IsTrue(offset % 4 == 0);
field.bytes.AddRange(BitConverter.GetBytes(value));
return new RvaData(field.runtimeValueField, offset, 4);
}
public RvaData Allocate(double value)
{
RvaField field = GetRvaField(8, 8);
int offset = field.bytes.Count;
Assert.IsTrue(offset % 8 == 0);
field.bytes.AddRange(BitConverter.GetBytes(value));
return new RvaData(field.runtimeValueField, offset, 8);
}
public RvaData Allocate(string value)
{
byte[] bytes = Encoding.UTF8.GetBytes(value);
return Allocate(bytes);
}
public RvaData Allocate(byte[] value)
{
RvaField field = GetRvaField(value.Length, 1);
int offset = field.bytes.Count;
field.bytes.AddRange(value);
return new RvaData(field.runtimeValueField, offset, value.Length);
}
private void AddVerifyCodes(IList<Instruction> insts, DefaultMetadataImporter importer)
{
int verifyIntValue = 0x12345678;
EncryptionScopeInfo encryptionScope = this.EncryptionScope;
IRandom verifyRandom = encryptionScope.localRandomCreator(verifyIntValue);
int verifyOps = EncryptionUtil.GenerateEncryptionOpCodes(verifyRandom, encryptionScope.encryptor, EncryptionScopeInfo.MaxEncryptionLevel, false);
int verifySalt = verifyRandom.NextInt();
int encryptedVerifyIntValue = encryptionScope.encryptor.Encrypt(verifyIntValue, verifyOps, verifySalt);
insts.Add(Instruction.Create(OpCodes.Ldc_I4, verifyIntValue));
insts.Add(Instruction.CreateLdcI4(encryptedVerifyIntValue));
insts.Add(Instruction.CreateLdcI4(verifyOps));
insts.Add(Instruction.CreateLdcI4(verifySalt));
insts.Add(Instruction.Create(OpCodes.Call, importer.DecryptInt));
insts.Add(Instruction.Create(OpCodes.Call, importer.VerifySecretKey));
}
private void CreateCCtorOfRvaTypeDef()
{
foreach (RvaTypeDefInfo rvaTypeDef in _rvaTypeDefs)
{
ModuleDef mod = rvaTypeDef.typeDef.Module;
var cctorMethod = new MethodDefUser(".cctor",
MethodSig.CreateStatic(Module.CorLibTypes.Void),
MethodImplAttributes.IL | MethodImplAttributes.Managed,
MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.Private);
cctorMethod.DeclaringType = rvaTypeDef.typeDef;
//_rvaTypeDef.Methods.Add(cctor);
var body = new CilBody();
cctorMethod.Body = body;
var ins = body.Instructions;
DefaultMetadataImporter importer = this.GetDefaultModuleMetadataImporter();
AddVerifyCodes(ins, importer);
foreach (var field in rvaTypeDef.rvaFields)
{
// ldc
// newarr
// dup
// stsfld
// ldtoken
// RuntimeHelpers.InitializeArray(array, fieldHandle);
ins.Add(Instruction.Create(OpCodes.Ldc_I4, (int)field.size));
ins.Add(Instruction.Create(OpCodes.Newarr, field.runtimeValueField.FieldType.Next.ToTypeDefOrRef()));
ins.Add(Instruction.Create(OpCodes.Dup));
ins.Add(Instruction.Create(OpCodes.Dup));
ins.Add(Instruction.Create(OpCodes.Stsfld, field.runtimeValueField));
ins.Add(Instruction.Create(OpCodes.Ldtoken, field.holderDataField));
ins.Add(Instruction.Create(OpCodes.Call, importer.InitializedArray));
// EncryptionService.DecryptBlock(array, field.encryptionOps, field.salt);
ins.Add(Instruction.CreateLdcI4(field.encryptionOps));
ins.Add(Instruction.Create(OpCodes.Ldc_I4, field.salt));
ins.Add(Instruction.Create(OpCodes.Call, importer.DecryptBlock));
}
ins.Add(Instruction.Create(OpCodes.Ret));
}
}
private void SetFieldsRVA()
{
foreach (var field in _rvaTypeDefs.SelectMany(t => t.rvaFields))
{
Assert.IsTrue(field.bytes.Count <= field.size);
if (field.bytes.Count < field.size)
{
field.FillPaddingToEnd();
}
byte[] data = field.bytes.ToArray();
EncryptionScope.encryptor.EncryptBlock(data, field.encryptionOps, field.salt);
field.holderDataField.InitialValue = data;
}
}
public override void Done()
{
if (_done)
{
throw new Exception("can't call Done twice");
}
_done = true;
SetFieldsRVA();
CreateCCtorOfRvaTypeDef();
}
}
}

View File

@ -1,423 +0,0 @@
using dnlib.DotNet;
using System;
using System.Reflection;
using UnityEngine.Assertions;
namespace Obfuz.Emit
{
public class EncryptionServiceMetadataImporter
{
private readonly ModuleDef _module;
private readonly Type _encryptionServiceType;
private IMethod _encryptBlock;
private IMethod _decryptBlock;
private IMethod _encryptInt;
private IMethod _decryptInt;
private IMethod _encryptLong;
private IMethod _decryptLong;
private IMethod _encryptFloat;
private IMethod _decryptFloat;
private IMethod _encryptDouble;
private IMethod _decryptDouble;
private IMethod _encryptString;
private IMethod _decryptString;
private IMethod _encryptBytes;
private IMethod _decryptBytes;
private IMethod _decryptFromRvaInt;
private IMethod _decryptFromRvaLong;
private IMethod _decryptFromRvaFloat;
private IMethod _decryptFromRvaDouble;
private IMethod _decryptFromRvaString;
private IMethod _decryptFromRvaBytes;
private IMethod _decryptInitializeArray;
public IMethod EncryptBlock => _encryptBlock;
public IMethod DecryptBlock => _decryptBlock;
public IMethod EncryptInt => _encryptInt;
public IMethod DecryptInt => _decryptInt;
public IMethod EncryptLong => _encryptLong;
public IMethod DecryptLong => _decryptLong;
public IMethod EncryptFloat => _encryptFloat;
public IMethod DecryptFloat => _decryptFloat;
public IMethod EncryptDouble => _encryptDouble;
public IMethod DecryptDouble => _decryptDouble;
public IMethod EncryptString => _encryptString;
public IMethod DecryptString => _decryptString;
public IMethod EncryptBytes => _encryptBytes;
public IMethod DecryptBytes => _decryptBytes;
public IMethod DecryptFromRvaInt => _decryptFromRvaInt;
public IMethod DecryptFromRvaLong => _decryptFromRvaLong;
public IMethod DecryptFromRvaFloat => _decryptFromRvaFloat;
public IMethod DecryptFromRvaDouble => _decryptFromRvaDouble;
public IMethod DecryptFromRvaBytes => _decryptFromRvaBytes;
public IMethod DecryptFromRvaString => _decryptFromRvaString;
public IMethod DecryptInitializeArray => _decryptInitializeArray;
public EncryptionServiceMetadataImporter(ModuleDef mod, Type encryptionServiceType)
{
_module = mod;
_encryptionServiceType = encryptionServiceType;
_encryptBlock = mod.Import(encryptionServiceType.GetMethod("EncryptBlock", new[] { typeof(byte[]), typeof(int), typeof(int) }));
Assert.IsNotNull(_encryptBlock);
_decryptBlock = mod.Import(encryptionServiceType.GetMethod("DecryptBlock", new[] { typeof(byte[]), typeof(int), typeof(int) }));
Assert.IsNotNull(_decryptBlock);
_encryptInt = mod.Import(encryptionServiceType.GetMethod("Encrypt", new[] { typeof(int), typeof(int), typeof(int) }));
Assert.IsNotNull(_encryptInt);
_decryptInt = mod.Import(encryptionServiceType.GetMethod("Decrypt", new[] { typeof(int), typeof(int), typeof(int) }));
Assert.IsNotNull(_decryptInt);
_encryptLong = mod.Import(encryptionServiceType.GetMethod("Encrypt", new[] { typeof(long), typeof(int), typeof(int) }));
Assert.IsNotNull(_encryptLong);
_decryptLong = mod.Import(encryptionServiceType.GetMethod("Decrypt", new[] { typeof(long), typeof(int), typeof(int) }));
Assert.IsNotNull(_decryptLong);
_encryptFloat = mod.Import(encryptionServiceType.GetMethod("Encrypt", new[] { typeof(float), typeof(int), typeof(int) }));
Assert.IsNotNull(_encryptFloat);
_decryptFloat = mod.Import(encryptionServiceType.GetMethod("Decrypt", new[] { typeof(float), typeof(int), typeof(int) }));
Assert.IsNotNull(_decryptFloat);
_encryptDouble = mod.Import(encryptionServiceType.GetMethod("Encrypt", new[] { typeof(double), typeof(int), typeof(int) }));
Assert.IsNotNull(_encryptDouble);
_decryptDouble = mod.Import(encryptionServiceType.GetMethod("Decrypt", new[] { typeof(double), typeof(int), typeof(int) }));
Assert.IsNotNull(_decryptDouble);
_encryptString = mod.Import(encryptionServiceType.GetMethod("Encrypt", new[] { typeof(string), typeof(int), typeof(int) }));
Assert.IsNotNull(_encryptString);
_decryptString = mod.Import(encryptionServiceType.GetMethod("DecryptString", new[] { typeof(byte[]), typeof(int), typeof(int), typeof(int), typeof(int) }));
Assert.IsNotNull(_decryptString);
_encryptBytes = mod.Import(encryptionServiceType.GetMethod("Encrypt", new[] { typeof(byte[]), typeof(int), typeof(int), typeof(int), typeof(int) }));
Assert.IsNotNull(_encryptBytes);
_decryptBytes = mod.Import(encryptionServiceType.GetMethod("Decrypt", new[] { typeof(byte[]), typeof(int), typeof(int), typeof(int), typeof(int) }));
Assert.IsNotNull(_decryptBytes);
_decryptFromRvaInt = mod.Import(encryptionServiceType.GetMethod("DecryptFromRvaInt", new[] { typeof(byte[]), typeof(int), typeof(int), typeof(int) }));
Assert.IsNotNull(_decryptFromRvaInt);
_decryptFromRvaLong = mod.Import(encryptionServiceType.GetMethod("DecryptFromRvaLong", new[] { typeof(byte[]), typeof(int), typeof(int), typeof(int) }));
Assert.IsNotNull(_decryptFromRvaLong);
_decryptFromRvaFloat = mod.Import(encryptionServiceType.GetMethod("DecryptFromRvaFloat", new[] { typeof(byte[]), typeof(int), typeof(int), typeof(int) }));
Assert.IsNotNull(_decryptFromRvaFloat);
_decryptFromRvaDouble = mod.Import(encryptionServiceType.GetMethod("DecryptFromRvaDouble", new[] { typeof(byte[]), typeof(int), typeof(int), typeof(int) }));
Assert.IsNotNull(_decryptFromRvaDouble);
_decryptFromRvaBytes = mod.Import(encryptionServiceType.GetMethod("DecryptFromRvaBytes", new[] { typeof(byte[]), typeof(int), typeof(int), typeof(int), typeof(int) }));
Assert.IsNotNull(_decryptFromRvaBytes);
_decryptFromRvaString = mod.Import(encryptionServiceType.GetMethod("DecryptFromRvaString", new[] { typeof(byte[]), typeof(int), typeof(int), typeof(int), typeof(int) }));
Assert.IsNotNull(_decryptFromRvaString);
_decryptInitializeArray = mod.Import(encryptionServiceType.GetMethod("DecryptInitializeArray", new[] { typeof(System.Array), typeof(System.RuntimeFieldHandle), typeof(int), typeof(int), typeof(int) }));
Assert.IsNotNull(_decryptInitializeArray);
}
}
public class DefaultMetadataImporter : GroupByModuleEntityBase
{
private EncryptionServiceMetadataImporter _defaultEncryptionServiceMetadataImporter;
private EncryptionServiceMetadataImporter _staticDefaultEncryptionServiceMetadataImporter;
private EncryptionServiceMetadataImporter _dynamicDefaultEncryptionServiceMetadataImporter;
public DefaultMetadataImporter()
{
}
public override void Init()
{
ModuleDef mod = Module;
var constUtilityType = typeof(ConstUtility);
_castIntAsFloat = mod.Import(constUtilityType.GetMethod("CastIntAsFloat"));
Assert.IsNotNull(_castIntAsFloat, "CastIntAsFloat not found");
_castLongAsDouble = mod.Import(constUtilityType.GetMethod("CastLongAsDouble"));
Assert.IsNotNull(_castLongAsDouble, "CastLongAsDouble not found");
_castFloatAsInt = mod.Import(constUtilityType.GetMethod("CastFloatAsInt"));
Assert.IsNotNull(_castFloatAsInt, "CastFloatAsInt not found");
_castDoubleAsLong = mod.Import(constUtilityType.GetMethod("CastDoubleAsLong"));
Assert.IsNotNull(_castDoubleAsLong, "CastDoubleAsLong not found");
_initializeArray = mod.Import(typeof(System.Runtime.CompilerServices.RuntimeHelpers).GetMethod("InitializeArray", new[] { typeof(Array), typeof(RuntimeFieldHandle) }));
Assert.IsNotNull(_initializeArray);
_verifySecretKey = mod.Import(typeof(AssertUtility).GetMethod("VerifySecretKey", new[] { typeof(int), typeof(int) }));
Assert.IsNotNull(_verifySecretKey, "VerifySecretKey not found");
_obfuscationTypeMapperRegisterType = mod.Import(typeof(ObfuscationTypeMapper).GetMethod("RegisterType", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(string) }, null));
Assert.IsNotNull(_obfuscationTypeMapperRegisterType, "ObfuscationTypeMapper.RegisterType not found");
var exprUtilityType = typeof(ExprUtility);
_addInt = mod.Import(exprUtilityType.GetMethod("Add", new[] { typeof(int), typeof(int) }));
Assert.IsNotNull(_addInt, "ExprUtility.Add(int, int) not found");
_addLong = mod.Import(exprUtilityType.GetMethod("Add", new[] { typeof(long), typeof(long) }));
Assert.IsNotNull(_addLong, "ExprUtility.Add(long, long) not found");
_addFloat = mod.Import(exprUtilityType.GetMethod("Add", new[] { typeof(float), typeof(float) }));
Assert.IsNotNull(_addFloat, "ExprUtility.Add(float, float) not found");
_addDouble = mod.Import(exprUtilityType.GetMethod("Add", new[] { typeof(double), typeof(double) }));
Assert.IsNotNull(_addDouble, "ExprUtility.Add(double, double) not found");
_addIntPtr = mod.Import(exprUtilityType.GetMethod("Add", new[] { typeof(IntPtr), typeof(IntPtr) }));
Assert.IsNotNull(_addIntPtr, "ExprUtility.Add(IntPtr, IntPtr) not found");
_addIntPtrInt = mod.Import(exprUtilityType.GetMethod("Add", new[] { typeof(IntPtr), typeof(int) }));
Assert.IsNotNull(_addIntPtrInt, "ExprUtility.Add(IntPtr, int) not found");
_subtractInt = mod.Import(exprUtilityType.GetMethod("Subtract", new[] { typeof(int), typeof(int) }));
Assert.IsNotNull(_subtractInt, "ExprUtility.Subtract(int, int) not found");
_subtractLong = mod.Import(exprUtilityType.GetMethod("Subtract", new[] { typeof(long), typeof(long) }));
Assert.IsNotNull(_subtractLong, "ExprUtility.Subtract(long, long) not found");
_subtractFloat = mod.Import(exprUtilityType.GetMethod("Subtract", new[] { typeof(float), typeof(float) }));
Assert.IsNotNull(_subtractFloat, "ExprUtility.Subtract(float, float) not found");
_subtractDouble = mod.Import(exprUtilityType.GetMethod("Subtract", new[] { typeof(double), typeof(double) }));
Assert.IsNotNull(_subtractDouble, "ExprUtility.Subtract(double, double) not found");
_subtractIntPtr = mod.Import(exprUtilityType.GetMethod("Subtract", new[] { typeof(IntPtr), typeof(IntPtr) }));
Assert.IsNotNull(_subtractIntPtr, "ExprUtility.Subtract(IntPtr, IntPtr) not found");
_subtractIntPtrInt = mod.Import(exprUtilityType.GetMethod("Subtract", new[] { typeof(IntPtr), typeof(int) }));
Assert.IsNotNull(_subtractIntPtrInt, "ExprUtility.Subtract(IntPtr, int) not found");
_multiplyInt = mod.Import(exprUtilityType.GetMethod("Multiply", new[] { typeof(int), typeof(int) }));
Assert.IsNotNull(_multiplyInt, "ExprUtility.Multiply(int, int) not found");
_multiplyLong = mod.Import(exprUtilityType.GetMethod("Multiply", new[] { typeof(long), typeof(long) }));
Assert.IsNotNull(_multiplyLong, "ExprUtility.Multiply(long, long) not found");
_multiplyFloat = mod.Import(exprUtilityType.GetMethod("Multiply", new[] { typeof(float), typeof(float) }));
Assert.IsNotNull(_multiplyFloat, "ExprUtility.Multiply(float, float) not found");
_multiplyDouble = mod.Import(exprUtilityType.GetMethod("Multiply", new[] { typeof(double), typeof(double) }));
Assert.IsNotNull(_multiplyDouble, "ExprUtility.Multiply(double, double) not found");
_multiplyIntPtr = mod.Import(exprUtilityType.GetMethod("Multiply", new[] { typeof(IntPtr), typeof(IntPtr) }));
Assert.IsNotNull(_multiplyIntPtr, "ExprUtility.Multiply(IntPtr, IntPtr) not found");
_multiplyIntPtrInt = mod.Import(exprUtilityType.GetMethod("Multiply", new[] { typeof(IntPtr), typeof(int) }));
Assert.IsNotNull(_multiplyIntPtrInt, "ExprUtility.Multiply(IntPtr, int) not found");
_divideInt = mod.Import(exprUtilityType.GetMethod("Divide", new[] { typeof(int), typeof(int) }));
Assert.IsNotNull(_divideInt, "ExprUtility.Divide(int, int) not found");
_divideLong = mod.Import(exprUtilityType.GetMethod("Divide", new[] { typeof(long), typeof(long) }));
Assert.IsNotNull(_divideLong);
_divideFloat = mod.Import(exprUtilityType.GetMethod("Divide", new[] { typeof(float), typeof(float) }));
Assert.IsNotNull(_divideFloat, "ExprUtility.Divide(float, float) not found");
_divideDouble = mod.Import(exprUtilityType.GetMethod("Divide", new[] { typeof(double), typeof(double) }));
Assert.IsNotNull(_divideDouble, "ExprUtility.Divide(double, double) not found");
_divideUnInt = mod.Import(exprUtilityType.GetMethod("DivideUn", new[] { typeof(int), typeof(int) }));
Assert.IsNotNull(_divideUnInt, "ExprUtility.DivideUn(int, int) not found");
_divideUnLong = mod.Import(exprUtilityType.GetMethod("DivideUn", new[] { typeof(long), typeof(long) }));
Assert.IsNotNull(_divideUnLong, "ExprUtility.DivideUn(long, long) not found");
_remInt = mod.Import(exprUtilityType.GetMethod("Rem", new[] { typeof(int), typeof(int) }));
Assert.IsNotNull(_remInt, "ExprUtility.Rem(int, int) not found");
_remLong = mod.Import(exprUtilityType.GetMethod("Rem", new[] { typeof(long), typeof(long) }));
Assert.IsNotNull(_remLong, "ExprUtility.Rem(long, long) not found");
_remFloat = mod.Import(exprUtilityType.GetMethod("Rem", new[] { typeof(float), typeof(float) }));
Assert.IsNotNull(_remFloat, "ExprUtility.Rem(float, float) not found");
_remDouble = mod.Import(exprUtilityType.GetMethod("Rem", new[] { typeof(double), typeof(double) }));
Assert.IsNotNull(_remDouble, "ExprUtility.Rem(double, double) not found");
_remUnInt = mod.Import(exprUtilityType.GetMethod("RemUn", new[] { typeof(int), typeof(int) }));
Assert.IsNotNull(_remUnInt, "ExprUtility.RemUn(int, int) not found");
_remUnLong = mod.Import(exprUtilityType.GetMethod("RemUn", new[] { typeof(long), typeof(long) }));
Assert.IsNotNull(_remUnLong, "ExprUtility.RemUn(long, long) not found");
_negInt = mod.Import(exprUtilityType.GetMethod("Negate", new[] { typeof(int) }));
Assert.IsNotNull(_negInt, "ExprUtility.Negate(int) not found");
_negLong = mod.Import(exprUtilityType.GetMethod("Negate", new[] { typeof(long) }));
Assert.IsNotNull(_negLong, "ExprUtility.Negate(long) not found");
_negFloat = mod.Import(exprUtilityType.GetMethod("Negate", new[] { typeof(float) }));
Assert.IsNotNull(_negFloat, "ExprUtility.Negate(float) not found");
_negDouble = mod.Import(exprUtilityType.GetMethod("Negate", new[] { typeof(double) }));
Assert.IsNotNull(_negDouble, "ExprUtility.Negate(double) not found");
_andInt = mod.Import(exprUtilityType.GetMethod("And", new[] { typeof(int), typeof(int) }));
Assert.IsNotNull(_andInt, "ExprUtility.And(int, int) not found");
_andLong = mod.Import(exprUtilityType.GetMethod("And", new[] { typeof(long), typeof(long) }));
Assert.IsNotNull(_andLong, "ExprUtility.And(long, long) not found");
_orInt = mod.Import(exprUtilityType.GetMethod("Or", new[] { typeof(int), typeof(int) }));
Assert.IsNotNull(_orInt, "ExprUtility.Or(int, int) not found");
_orLong = mod.Import(exprUtilityType.GetMethod("Or", new[] { typeof(long), typeof(long) }));
Assert.IsNotNull(_orLong, "ExprUtility.Or(long, long) not found");
_xorInt = mod.Import(exprUtilityType.GetMethod("Xor", new[] { typeof(int), typeof(int) }));
Assert.IsNotNull(_xorInt, "ExprUtility.Xor(int, int) not found");
_xorLong = mod.Import(exprUtilityType.GetMethod("Xor", new[] { typeof(long), typeof(long) }));
Assert.IsNotNull(_xorLong, "ExprUtility.Xor(long, long) not found");
_notInt = mod.Import(exprUtilityType.GetMethod("Not", new[] { typeof(int) }));
Assert.IsNotNull(_notInt, "ExprUtility.Not(int) not found");
_notLong = mod.Import(exprUtilityType.GetMethod("Not", new[] { typeof(long) }));
Assert.IsNotNull(_notLong, "ExprUtility.Not(long) not found");
_shlInt = mod.Import(exprUtilityType.GetMethod("ShiftLeft", new[] { typeof(int), typeof(int) }));
Assert.IsNotNull(_shlInt, "ExprUtility.ShiftLeft(int, int) not found");
_shlLong = mod.Import(exprUtilityType.GetMethod("ShiftLeft", new[] { typeof(long), typeof(int) }));
Assert.IsNotNull(_shlLong, "ExprUtility.ShiftLeft(long, int) not found");
_shrInt = mod.Import(exprUtilityType.GetMethod("ShiftRight", new[] { typeof(int), typeof(int) }));
Assert.IsNotNull(_shrInt, "ExprUtility.ShiftRight(int, int) not found");
_shrLong = mod.Import(exprUtilityType.GetMethod("ShiftRight", new[] { typeof(long), typeof(int) }));
Assert.IsNotNull(_shrLong, "ExprUtility.ShiftRight(long, int) not found");
_shrUnInt = mod.Import(exprUtilityType.GetMethod("ShiftRightUn", new[] { typeof(int), typeof(int) }));
Assert.IsNotNull(_shrUnInt, "ExprUtility.ShiftRightUn(int, int) not found");
_shrUnLong = mod.Import(exprUtilityType.GetMethod("ShiftRightUn", new[] { typeof(long), typeof(int) }));
Assert.IsNotNull(_shrUnLong, "ExprUtility.ShiftRightUn(long, int) not found");
_staticDefaultEncryptionServiceMetadataImporter = new EncryptionServiceMetadataImporter(mod, typeof(EncryptionService<DefaultStaticEncryptionScope>));
_dynamicDefaultEncryptionServiceMetadataImporter = new EncryptionServiceMetadataImporter(mod, typeof(EncryptionService<DefaultDynamicEncryptionScope>));
if (EncryptionScopeProvider.IsDynamicSecretAssembly(mod))
{
_defaultEncryptionServiceMetadataImporter = _dynamicDefaultEncryptionServiceMetadataImporter;
}
else
{
_defaultEncryptionServiceMetadataImporter = _staticDefaultEncryptionServiceMetadataImporter;
}
}
public override void Done()
{
}
public EncryptionServiceMetadataImporter GetEncryptionServiceMetadataImporterOfModule(ModuleDef mod)
{
return EncryptionScopeProvider.IsDynamicSecretAssembly(mod) ? _dynamicDefaultEncryptionServiceMetadataImporter : _staticDefaultEncryptionServiceMetadataImporter;
}
private ModuleDef _module;
private IMethod _castIntAsFloat;
private IMethod _castLongAsDouble;
private IMethod _castFloatAsInt;
private IMethod _castDoubleAsLong;
private IMethod _initializeArray;
private IMethod _verifySecretKey;
private IMethod _obfuscationTypeMapperRegisterType;
private IMethod _addInt;
private IMethod _addLong;
private IMethod _addFloat;
private IMethod _addDouble;
private IMethod _addIntPtr;
private IMethod _addIntPtrInt;
private IMethod _subtractInt;
private IMethod _subtractLong;
private IMethod _subtractFloat;
private IMethod _subtractDouble;
private IMethod _subtractIntPtr;
private IMethod _subtractIntPtrInt;
private IMethod _multiplyInt;
private IMethod _multiplyLong;
private IMethod _multiplyFloat;
private IMethod _multiplyDouble;
private IMethod _multiplyIntPtr;
private IMethod _multiplyIntPtrInt;
private IMethod _divideInt;
private IMethod _divideLong;
private IMethod _divideFloat;
private IMethod _divideDouble;
private IMethod _divideUnInt;
private IMethod _divideUnLong;
private IMethod _remInt;
private IMethod _remLong;
private IMethod _remFloat;
private IMethod _remDouble;
private IMethod _remUnInt;
private IMethod _remUnLong;
private IMethod _negInt;
private IMethod _negLong;
private IMethod _negFloat;
private IMethod _negDouble;
private IMethod _andInt;
private IMethod _andLong;
private IMethod _orInt;
private IMethod _orLong;
private IMethod _xorInt;
private IMethod _xorLong;
private IMethod _notInt;
private IMethod _notLong;
private IMethod _shlInt;
private IMethod _shlLong;
private IMethod _shrInt;
private IMethod _shrLong;
private IMethod _shrUnInt;
private IMethod _shrUnLong;
public IMethod CastIntAsFloat => _castIntAsFloat;
public IMethod CastLongAsDouble => _castLongAsDouble;
public IMethod CastFloatAsInt => _castFloatAsInt;
public IMethod CastDoubleAsLong => _castDoubleAsLong;
public IMethod InitializedArray => _initializeArray;
public IMethod VerifySecretKey => _verifySecretKey;
public IMethod ObfuscationTypeMapperRegisterType => _obfuscationTypeMapperRegisterType;
public IMethod EncryptBlock => _defaultEncryptionServiceMetadataImporter.EncryptBlock;
public IMethod DecryptBlock => _defaultEncryptionServiceMetadataImporter.DecryptBlock;
public IMethod EncryptInt => _defaultEncryptionServiceMetadataImporter.EncryptInt;
public IMethod DecryptInt => _defaultEncryptionServiceMetadataImporter.DecryptInt;
public IMethod EncryptLong => _defaultEncryptionServiceMetadataImporter.EncryptLong;
public IMethod DecryptLong => _defaultEncryptionServiceMetadataImporter.DecryptLong;
public IMethod EncryptFloat => _defaultEncryptionServiceMetadataImporter.EncryptFloat;
public IMethod DecryptFloat => _defaultEncryptionServiceMetadataImporter.DecryptFloat;
public IMethod EncryptDouble => _defaultEncryptionServiceMetadataImporter.EncryptDouble;
public IMethod DecryptDouble => _defaultEncryptionServiceMetadataImporter.DecryptDouble;
public IMethod EncryptString => _defaultEncryptionServiceMetadataImporter.EncryptString;
public IMethod DecryptString => _defaultEncryptionServiceMetadataImporter.DecryptString;
public IMethod EncryptBytes => _defaultEncryptionServiceMetadataImporter.EncryptBytes;
public IMethod DecryptBytes => _defaultEncryptionServiceMetadataImporter.DecryptBytes;
public IMethod DecryptFromRvaInt => _defaultEncryptionServiceMetadataImporter.DecryptFromRvaInt;
public IMethod DecryptFromRvaLong => _defaultEncryptionServiceMetadataImporter.DecryptFromRvaLong;
public IMethod DecryptFromRvaFloat => _defaultEncryptionServiceMetadataImporter.DecryptFromRvaFloat;
public IMethod DecryptFromRvaDouble => _defaultEncryptionServiceMetadataImporter.DecryptFromRvaDouble;
public IMethod DecryptFromRvaBytes => _defaultEncryptionServiceMetadataImporter.DecryptFromRvaBytes;
public IMethod DecryptFromRvaString => _defaultEncryptionServiceMetadataImporter.DecryptFromRvaString;
public IMethod DecryptInitializeArray => _defaultEncryptionServiceMetadataImporter.DecryptInitializeArray;
public IMethod AddInt => _addInt;
public IMethod AddLong => _addLong;
public IMethod AddFloat => _addFloat;
public IMethod AddDouble => _addDouble;
public IMethod AddIntPtr => _addIntPtr;
public IMethod AddIntPtrInt => _addIntPtrInt;
public IMethod SubtractInt => _subtractInt;
public IMethod SubtractLong => _subtractLong;
public IMethod SubtractFloat => _subtractFloat;
public IMethod SubtractDouble => _subtractDouble;
public IMethod SubtractIntPtr => _subtractIntPtr;
public IMethod SubtractIntPtrInt => _subtractIntPtrInt;
public IMethod MultiplyInt => _multiplyInt;
public IMethod MultiplyLong => _multiplyLong;
public IMethod MultiplyFloat => _multiplyFloat;
public IMethod MultiplyDouble => _multiplyDouble;
public IMethod MultiplyIntPtr => _multiplyIntPtr;
public IMethod MultiplyIntPtrInt => _multiplyIntPtrInt;
public IMethod DivideInt => _divideInt;
public IMethod DivideLong => _divideLong;
public IMethod DivideFloat => _divideFloat;
public IMethod DivideDouble => _divideDouble;
public IMethod DivideUnInt => _divideUnInt;
public IMethod DivideUnLong => _divideUnLong;
public IMethod RemInt => _remInt;
public IMethod RemLong => _remLong;
public IMethod RemFloat => _remFloat;
public IMethod RemDouble => _remDouble;
public IMethod RemUnInt => _remUnInt;
public IMethod RemUnLong => _remUnLong;
public IMethod NegInt => _negInt;
public IMethod NegLong => _negLong;
public IMethod NegFloat => _negFloat;
public IMethod NegDouble => _negDouble;
public IMethod AndInt => _andInt;
public IMethod AndLong => _andLong;
public IMethod OrInt => _orInt;
public IMethod OrLong => _orLong;
public IMethod XorInt => _xorInt;
public IMethod XorLong => _xorLong;
public IMethod NotInt => _notInt;
public IMethod NotLong => _notLong;
public IMethod ShlInt => _shlInt;
public IMethod ShlLong => _shlLong;
public IMethod ShrInt => _shrInt;
public IMethod ShrLong => _shrLong;
public IMethod ShrUnInt => _shrUnInt;
public IMethod ShrUnLong => _shrUnLong;
}
}

View File

@ -1,15 +0,0 @@
namespace Obfuz.Emit
{
public static class EntityExtensions
{
public static T GetEntity<T>(this IGroupByModuleEntity entity) where T : IGroupByModuleEntity, new()
{
return entity.Manager.GetEntity<T>(entity.Module);
}
public static DefaultMetadataImporter GetDefaultModuleMetadataImporter(this IGroupByModuleEntity entity)
{
return entity.GetEntity<DefaultMetadataImporter>();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,89 +0,0 @@
using dnlib.DotNet;
using System;
using System.Collections.Generic;
namespace Obfuz.Emit
{
public interface IGroupByModuleEntity
{
GroupByModuleEntityManager Manager { get; set; }
ModuleDef Module { get; set; }
EncryptionScopeProvider EncryptionScopeProvider { get; }
EncryptionScopeInfo EncryptionScope { get; set; }
void Init();
void Done();
}
public abstract class GroupByModuleEntityBase : IGroupByModuleEntity
{
public GroupByModuleEntityManager Manager { get; set; }
public ModuleDef Module { get; set; }
public EncryptionScopeInfo EncryptionScope { get; set; }
public EncryptionScopeProvider EncryptionScopeProvider => Manager.EncryptionScopeProvider;
public T GetEntity<T>() where T : IGroupByModuleEntity, new()
{
return Manager.GetEntity<T>(Module);
}
public abstract void Init();
public abstract void Done();
}
public class GroupByModuleEntityManager
{
private readonly Dictionary<(ModuleDef, Type), IGroupByModuleEntity> _moduleEntityManagers = new Dictionary<(ModuleDef, Type), IGroupByModuleEntity>();
public EncryptionScopeProvider EncryptionScopeProvider { get; set; }
public T GetEntity<T>(ModuleDef mod) where T : IGroupByModuleEntity, new()
{
var key = (mod, typeof(T));
if (_moduleEntityManagers.TryGetValue(key, out var emitManager))
{
return (T)emitManager;
}
else
{
T newEmitManager = new T();
newEmitManager.Manager = this;
newEmitManager.Module = mod;
newEmitManager.EncryptionScope = EncryptionScopeProvider.GetScope(mod);
newEmitManager.Init();
_moduleEntityManagers[key] = newEmitManager;
return newEmitManager;
}
}
public List<T> GetEntities<T>() where T : IGroupByModuleEntity, new()
{
var managers = new List<T>();
foreach (var kv in _moduleEntityManagers)
{
if (kv.Key.Item2 == typeof(T))
{
managers.Add((T)kv.Value);
}
}
return managers;
}
public void Done<T>() where T : IGroupByModuleEntity, new()
{
var managers = GetEntities<T>();
foreach (var manager in managers)
{
manager.Done();
}
}
}
}

View File

@ -1,74 +0,0 @@
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using System;
using System.Collections.Generic;
namespace Obfuz.Emit
{
class ScopeLocalVariables : IDisposable
{
private readonly LocalVariableAllocator _localVariableAllocator;
private readonly List<Local> _allocatedVars = new List<Local>();
public IReadOnlyList<Local> AllocatedLocals => _allocatedVars;
public ScopeLocalVariables(LocalVariableAllocator localVariableAllocator)
{
_localVariableAllocator = localVariableAllocator;
}
public Local AllocateLocal(TypeSig type)
{
var local = _localVariableAllocator.AllocateLocal(type);
_allocatedVars.Add(local);
return local;
}
public void Dispose()
{
foreach (var local in _allocatedVars)
{
_localVariableAllocator.ReturnLocal(local);
}
}
}
class LocalVariableAllocator
{
private readonly MethodDef _method;
private readonly List<Local> _freeLocals = new List<Local>();
public LocalVariableAllocator(MethodDef method)
{
_method = method;
}
public Local AllocateLocal(TypeSig type)
{
foreach (var local in _freeLocals)
{
if (TypeEqualityComparer.Instance.Equals(local.Type, type))
{
_freeLocals.Remove(local);
return local;
}
}
var newLocal = new Local(type);
// _freeLocals.Add(newLocal);
_method.Body.Variables.Add(newLocal);
return newLocal;
}
public void ReturnLocal(Local local)
{
_freeLocals.Add(local);
}
public ScopeLocalVariables CreateScope()
{
return new ScopeLocalVariables(this);
}
}
}

View File

@ -1,117 +0,0 @@
using Obfuz.Utils;
using System;
using System.Linq;
using System.Text;
namespace Obfuz.GarbageCodeGeneration
{
public class ConfigGarbageCodeGenerator : SpecificGarbageCodeGeneratorBase
{
private readonly string[] _types = new string[]
{
"bool",
"byte",
"short",
"int",
"long",
"float",
"double",
};
private string CreateRandomType(IRandom random)
{
return _types[random.NextInt(_types.Length)];
}
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}");
}
}
class FieldGenerationInfo
{
public int index;
public string name;
public string type;
}
class MethodGenerationInfo
{
public int index;
public string name;
}
protected override object CreateField(int index, IRandom random, GenerationParameters parameters)
{
return new FieldGenerationInfo
{
index = index,
name = $"x{index}",
type = CreateRandomType(random),
};
}
protected override object CreateMethod(int index, IRandom random, GenerationParameters parameters)
{
return new MethodGenerationInfo
{
index = index,
name = $"Load{index}",
};
}
protected override void GenerateUsings(StringBuilder result, IClassGenerationInfo cgi)
{
}
protected override void GenerateField(StringBuilder result, IClassGenerationInfo cgi, IRandom random, object field, string indent)
{
var fgi = (FieldGenerationInfo)field;
result.AppendLine($"{indent}public {fgi.type} {fgi.name};");
}
protected override void GenerateMethod(StringBuilder result, IClassGenerationInfo cgi, IRandom random, object method, string indent)
{
var mgi = (MethodGenerationInfo)method;
result.AppendLine($"{indent}public void {mgi.name}(BinaryReader reader)");
result.AppendLine($"{indent}{{");
string indent2 = indent + " ";
result.AppendLine($"{indent2}int a = 0;");
result.AppendLine($"{indent2}int b = 0;");
int maxN = 100;
var shuffledFields = cgi.Fields.ToList();
RandomUtil.ShuffleList(shuffledFields, random);
foreach (FieldGenerationInfo fgi in shuffledFields)
{
result.AppendLine($"{indent2}this.{fgi.name} = reader.{GetReadMethodNameOfType(fgi.type)}();");
if (random.NextInPercentage(0.5f))
{
result.AppendLine($"{indent2}a = b * {random.NextInt(maxN)} + reader.ReadInt32();");
result.AppendLine($"{indent2}b = a * reader.ReadInt32() + {random.NextInt(maxN)};");
}
if (random.NextInPercentage(0.5f))
{
result.AppendLine($"{indent2}a += {random.NextInt(0, 10000)};");
}
if (random.NextInPercentage(0.5f))
{
result.AppendLine($"{indent2}b += {random.NextInt(0, 10000)};");
}
}
result.AppendLine($"{indent}}}");
}
}
}

View File

@ -1,88 +0,0 @@
using Obfuz.Settings;
using Obfuz.Utils;
using System;
using UnityEngine;
namespace Obfuz.GarbageCodeGeneration
{
public class GarbageCodeGenerator
{
private const int CodeGenerationSecretKeyLength = 1024;
private readonly GarbageCodeGenerationSettings _settings;
private readonly int[] _intGenerationSecretKey;
public GarbageCodeGenerator(GarbageCodeGenerationSettings 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);
}
}
}
public void CleanCodes()
{
Debug.Log($"Cleaning generated garbage codes begin.");
if (_settings.defaultTask != null)
{
FileUtil.RemoveDir(_settings.defaultTask.outputPath, true);
}
if (_settings.additionalTasks != null && _settings.additionalTasks.Length > 0)
{
foreach (var task in _settings.additionalTasks)
{
FileUtil.RemoveDir(task.outputPath, true);
}
}
}
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.garbageCodeType}, output path: {task.outputPath}");
if (string.IsNullOrWhiteSpace(task.outputPath))
{
throw new Exception("outputPath of GarbageCodeGenerationTask is empty!");
}
var generator = CreateSpecificCodeGenerator(task.garbageCodeType);
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();
case GarbageCodeType.UI: return new UIGarbageCodeGenerator();
default: throw new NotSupportedException($"Garbage code type {type} is not supported.");
}
}
}
}

View File

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

View File

@ -1,21 +0,0 @@
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

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

View File

@ -1,106 +0,0 @@
using Obfuz.Utils;
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 abstract object CreateField(int index, IRandom random, GenerationParameters parameters);
protected abstract object CreateMethod(int index, IRandom random, GenerationParameters parameters);
protected virtual 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++)
{
cgi.Fields.Add(CreateField(i, random, parameters));
}
for (int i = 0; i < parameters.methodCountPerClass; i++)
{
cgi.Methods.Add(CreateMethod(i, random, parameters));
}
return cgi;
}
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, random, field, indent);
}
foreach (object method in cgi.Methods)
{
GenerateMethod(result, cgi, random, method, indent);
}
result.AppendLine(" }");
result.AppendLine("}");
}
protected abstract void GenerateUsings(StringBuilder result, IClassGenerationInfo cgi);
protected abstract void GenerateField(StringBuilder result, IClassGenerationInfo cgi, IRandom random, object field, string indent);
protected abstract void GenerateMethod(StringBuilder result, IClassGenerationInfo cgi, IRandom random, object method, string indent);
}
}

View File

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

View File

@ -1,157 +0,0 @@
using Obfuz.Utils;
using System;
using System.Linq;
using System.Text;
namespace Obfuz.GarbageCodeGeneration
{
public class UIGarbageCodeGenerator : SpecificGarbageCodeGeneratorBase
{
/*
*
* public Button b1;
public Image b2;
public RawImage b30;
public Text b3;
public Slider b4;
public ScrollRect b5;
public Scrollbar b6;
public Mask b7;
public RectMask2D b70;
public Canvas b8;
public CanvasGroup b9;
public RectTransform b10;
public Transform b11;
public GameObject b12;
*/
private readonly string[] _types = new string[]
{
"Button",
"Image",
"RawImage",
"Text",
"Slider",
"ScrollRect",
"Scrollbar",
"Mask",
"RectMask2D",
"Canvas",
"CanvasGroup",
"RectTransform",
//"Transform",
//"GameObject",
};
private string CreateRandomType(IRandom random)
{
return _types[random.NextInt(_types.Length)];
}
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}");
}
}
class FieldGenerationInfo
{
public int index;
public string name;
public string type;
}
class MethodGenerationInfo
{
public int index;
public string name;
}
protected override object CreateField(int index, IRandom random, GenerationParameters parameters)
{
return new FieldGenerationInfo
{
index = index,
name = $"x{index}",
type = CreateRandomType(random),
};
}
protected override object CreateMethod(int index, IRandom random, GenerationParameters parameters)
{
return new MethodGenerationInfo
{
index = index,
name = $"Init{index}",
};
}
protected override void GenerateUsings(StringBuilder result, IClassGenerationInfo cgi)
{
result.AppendLine("using UnityEngine.UI;");
}
protected override void GenerateField(StringBuilder result, IClassGenerationInfo cgi, IRandom random, object field, string indent)
{
var fgi = (FieldGenerationInfo)field;
result.AppendLine($"{indent}public {fgi.type} {fgi.name};");
}
protected override void GenerateMethod(StringBuilder result, IClassGenerationInfo cgi, IRandom random, object method, string indent)
{
var mgi = (MethodGenerationInfo)method;
result.AppendLine($"{indent}public void {mgi.name}(GameObject go)");
result.AppendLine($"{indent}{{");
string indent2 = indent + " ";
result.AppendLine($"{indent2}int a = 0;");
result.AppendLine($"{indent2}int b = 0;");
int maxN = 100;
var shuffledFields = cgi.Fields.ToList();
RandomUtil.ShuffleList(shuffledFields, random);
foreach (FieldGenerationInfo fgi in shuffledFields)
{
if (random.NextInPercentage(0.5f))
{
result.AppendLine($"{indent2}this.{fgi.name} = go.transform.Find(\"ui/{fgi.name}\").GetComponent<{fgi.type}>();");
}
else
{
result.AppendLine($"{indent2}this.{fgi.name} = go.GetComponent<{fgi.type}>();");
}
if (random.NextInPercentage(0.5f))
{
result.AppendLine($"{indent2}a = b * {random.NextInt(maxN)} + go.layer;");
result.AppendLine($"{indent2}b = a * go.layer + {random.NextInt(maxN)};");
}
if (random.NextInPercentage(0.5f))
{
result.AppendLine($"{indent2}a *= {random.NextInt(0, 10000)};");
}
if (random.NextInPercentage(0.5f))
{
result.AppendLine($"{indent2}b /= {random.NextInt(0, 10000)};");
}
if (random.NextInPercentage(0.5f))
{
result.AppendLine($"{indent2}a = a * b << {random.NextInt(0, 10000)};");
}
if (random.NextInPercentage(0.5f))
{
result.AppendLine($"{indent2}b = a / b & {random.NextInt(0, 10000)};");
}
}
result.AppendLine($"{indent}}}");
}
}
}

View File

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

View File

@ -1,166 +0,0 @@
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using Obfuz.Emit;
using Obfuz.Settings;
using Obfuz.Utils;
using System.Collections.Generic;
namespace Obfuz.ObfusPasses.CallObfus
{
class ObfusMethodContext
{
public MethodDef method;
public LocalVariableAllocator localVariableAllocator;
public IRandom localRandom;
public EncryptionScopeInfo encryptionScope;
}
public class CallObfusPass : ObfuscationMethodPassBase
{
public static CallObfuscationSettingsFacade CurrentSettings { get; private set; }
private readonly CallObfuscationSettingsFacade _settings;
private SpecialWhiteListMethodCalculator _specialWhiteListMethodCache;
private IObfuscator _dynamicProxyObfuscator;
private IObfuscationPolicy _dynamicProxyPolicy;
public override ObfuscationPassType Type => ObfuscationPassType.CallObfus;
public CallObfusPass(CallObfuscationSettingsFacade settings)
{
_settings = settings;
CurrentSettings = settings;
}
public override void Stop()
{
_dynamicProxyObfuscator.Done();
}
public override void Start()
{
var ctx = ObfuscationPassContext.Current;
_specialWhiteListMethodCache = new SpecialWhiteListMethodCalculator(ctx.coreSettings.targetRuntime, _settings.obfuscateCallToMethodInMscorlib);
_dynamicProxyObfuscator = CreateObfuscator(ctx, _settings.proxyMode);
_dynamicProxyPolicy = new ConfigurableObfuscationPolicy(ctx.coreSettings.assembliesToObfuscate, _settings.ruleFiles);
}
private IObfuscator CreateObfuscator(ObfuscationPassContext ctx, ProxyMode mode)
{
switch (mode)
{
case ProxyMode.Dispatch:
return new DispatchProxyObfuscator(ctx.moduleEntityManager);
case ProxyMode.Delegate:
return new DelegateProxyObfuscator(ctx.moduleEntityManager);
default:
throw new System.NotSupportedException($"Unsupported proxy mode: {mode}");
}
}
protected override void ObfuscateData(MethodDef method)
{
BasicBlockCollection bbc = new BasicBlockCollection(method, false);
IList<Instruction> instructions = method.Body.Instructions;
var outputInstructions = new List<Instruction>();
var totalFinalInstructions = new List<Instruction>();
ObfuscationPassContext ctx = ObfuscationPassContext.Current;
var encryptionScope = ctx.moduleEntityManager.EncryptionScopeProvider.GetScope(method.Module);
var localRandom = encryptionScope.localRandomCreator(MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method));
var omc = new ObfusMethodContext
{
method = method,
localVariableAllocator = new LocalVariableAllocator(method),
localRandom = localRandom,
encryptionScope = encryptionScope,
};
Instruction lastInst = null;
for (int i = 0; i < instructions.Count; i++)
{
Instruction inst = instructions[i];
BasicBlock block = bbc.GetBasicBlockByInstruction(inst);
outputInstructions.Clear();
if (TryObfuscateInstruction(method, lastInst, inst, outputInstructions, omc))
{
// current instruction may be the target of control flow instruction, so we can't remove it directly.
// we replace it with nop now, then remove it in CleanUpInstructionPass
inst.OpCode = outputInstructions[0].OpCode;
inst.Operand = outputInstructions[0].Operand;
totalFinalInstructions.Add(inst);
for (int k = 1; k < outputInstructions.Count; k++)
{
totalFinalInstructions.Add(outputInstructions[k]);
}
}
else
{
totalFinalInstructions.Add(inst);
}
lastInst = inst;
}
instructions.Clear();
foreach (var obInst in totalFinalInstructions)
{
instructions.Add(obInst);
}
}
protected override bool NeedObfuscateMethod(MethodDef method)
{
return _dynamicProxyPolicy.NeedObfuscateCallInMethod(method);
}
private bool TryObfuscateInstruction(MethodDef callerMethod, Instruction lastInst, Instruction inst, List<Instruction> outputInstructions, ObfusMethodContext ctx)
{
IMethod calledMethod = inst.Operand as IMethod;
if (calledMethod == null || !calledMethod.IsMethod)
{
return false;
}
if (MetaUtil.ContainsContainsGenericParameter(calledMethod))
{
return false;
}
bool callVir;
switch (inst.OpCode.Code)
{
case Code.Call:
{
callVir = false;
break;
}
case Code.Callvirt:
{
if (lastInst != null && lastInst.OpCode.Code == Code.Constrained)
{
return false;
}
callVir = true;
break;
}
default: return false;
}
if (_specialWhiteListMethodCache.IsInWhiteList(calledMethod))
{
return false;
}
if (!_dynamicProxyPolicy.NeedObfuscateCalledMethod(callerMethod, calledMethod, callVir))
{
return false;
}
return _dynamicProxyObfuscator.Obfuscate(callerMethod, calledMethod, callVir, outputInstructions);
}
}
}

View File

@ -1,265 +0,0 @@
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using Obfuz.Data;
using Obfuz.Emit;
using Obfuz.Settings;
using Obfuz.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Obfuz.ObfusPasses.CallObfus
{
struct DelegateProxyMethodData
{
public readonly FieldDef delegateInstanceField;
public readonly MethodDef delegateInvokeMethod;
public DelegateProxyMethodData(FieldDef delegateInstanceField, MethodDef delegateInvokeMethod)
{
this.delegateInstanceField = delegateInstanceField;
this.delegateInvokeMethod = delegateInvokeMethod;
}
}
class DelegateProxyAllocator : GroupByModuleEntityBase
{
private readonly CachedDictionary<MethodSig, TypeDef> _delegateTypes;
private readonly HashSet<string> _allocatedDelegateNames = new HashSet<string>();
private TypeDef _delegateInstanceHolderType;
private bool _done;
class CallInfo
{
public string key1;
public int key2;
public IMethod method;
public bool callVir;
public int index;
public TypeDef delegateType;
public FieldDef delegateInstanceField;
public MethodDef delegateInvokeMethod;
public MethodDef proxyMethod;
}
private readonly Dictionary<MethodKey, CallInfo> _callMethods = new Dictionary<MethodKey, CallInfo>();
private CallObfuscationSettingsFacade _settings;
public DelegateProxyAllocator()
{
_delegateTypes = new CachedDictionary<MethodSig, TypeDef>(SignatureEqualityComparer.Instance, CreateDelegateForSignature);
}
public override void Init()
{
_delegateInstanceHolderType = CreateDelegateInstanceHolderTypeDef();
_settings = CallObfusPass.CurrentSettings;
}
private string AllocateDelegateTypeName(MethodSig delegateInvokeSig)
{
uint hashCode = (uint)SignatureEqualityComparer.Instance.GetHashCode(delegateInvokeSig);
string typeName = $"$Obfuz$Delegate_{hashCode}";
if (_allocatedDelegateNames.Add(typeName))
{
return typeName;
}
for (int i = 0; ; i++)
{
typeName = $"$Obfuz$Delegate_{hashCode}_{i}";
if (_allocatedDelegateNames.Add(typeName))
{
return typeName;
}
}
}
private TypeDef CreateDelegateForSignature(MethodSig delegateInvokeSig)
{
ModuleDef mod = Module;
using (var scope = new DisableTypeDefFindCacheScope(mod))
{
string typeName = AllocateDelegateTypeName(delegateInvokeSig);
mod.Import(typeof(MulticastDelegate));
TypeDef delegateType = new TypeDefUser("", typeName, mod.CorLibTypes.GetTypeRef("System", "MulticastDelegate"));
delegateType.Attributes = TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.Public;
mod.Types.Add(delegateType);
MethodDef ctor = new MethodDefUser(
".ctor",
MethodSig.CreateInstance(mod.CorLibTypes.Void, mod.CorLibTypes.Object, mod.CorLibTypes.IntPtr),
MethodImplAttributes.Runtime,
MethodAttributes.RTSpecialName | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Public
);
ctor.DeclaringType = delegateType;
MethodDef invokeMethod = new MethodDefUser(
"Invoke",
MethodSig.CreateInstance(delegateInvokeSig.RetType, delegateInvokeSig.Params.ToArray()),
MethodImplAttributes.Runtime,
MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.NewSlot | MethodAttributes.Virtual
);
invokeMethod.DeclaringType = delegateType;
return delegateType;
}
}
private TypeDef CreateDelegateInstanceHolderTypeDef()
{
ModuleDef mod = Module;
using (var scope = new DisableTypeDefFindCacheScope(mod))
{
string typeName = "$Obfuz$DelegateInstanceHolder";
TypeDef holderType = new TypeDefUser("", typeName, mod.CorLibTypes.Object.ToTypeDefOrRef());
holderType.Attributes = TypeAttributes.Class | TypeAttributes.Public;
mod.Types.Add(holderType);
return holderType;
}
}
private string AllocateFieldName(IMethod method, bool callVir)
{
uint hashCode = (uint)MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method);
string typeName = $"$Obfuz$Delegate$Field_{hashCode}_{callVir}";
if (_allocatedDelegateNames.Add(typeName))
{
return typeName;
}
for (int i = 0; ; i++)
{
typeName = $"$Obfuz$Delegate$Field_{hashCode}_{callVir}_{i}";
if (_allocatedDelegateNames.Add(typeName))
{
return typeName;
}
}
}
private MethodDef CreateProxyMethod(string name, IMethod calledMethod, bool callVir, MethodSig delegateInvokeSig)
{
var proxyMethod = new MethodDefUser(name, delegateInvokeSig, MethodImplAttributes.Managed, MethodAttributes.Public | MethodAttributes.Static);
var body = new CilBody();
proxyMethod.Body = body;
var ins = body.Instructions;
foreach (Parameter param in proxyMethod.Parameters)
{
ins.Add(Instruction.Create(OpCodes.Ldarg, param));
}
ins.Add(Instruction.Create(callVir ? OpCodes.Callvirt : OpCodes.Call, calledMethod));
ins.Add(Instruction.Create(OpCodes.Ret));
return proxyMethod;
}
public DelegateProxyMethodData Allocate(IMethod method, bool callVir, MethodSig delegateInvokeSig)
{
var key = new MethodKey(method, callVir);
if (!_callMethods.TryGetValue(key, out var callInfo))
{
TypeDef delegateType = _delegateTypes.GetValue(delegateInvokeSig);
MethodDef delegateInvokeMethod = delegateType.FindMethod("Invoke");
string fieldName = AllocateFieldName(method, callVir);
FieldDef delegateInstanceField = new FieldDefUser(fieldName, new FieldSig(delegateType.ToTypeSig()), FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.InitOnly);
string key1 = $"{method.FullName}_{callVir}";
callInfo = new CallInfo
{
key1 = key1,
key2 = HashUtil.ComputePrimitiveOrStringOrBytesHashCode(key1) * 33445566,
method = method,
callVir = callVir,
delegateType = delegateType,
delegateInstanceField = delegateInstanceField,
delegateInvokeMethod = delegateInvokeMethod,
proxyMethod = CreateProxyMethod($"{fieldName}$Proxy", method, callVir, delegateInvokeSig),
};
_callMethods.Add(key, callInfo);
}
return new DelegateProxyMethodData(callInfo.delegateInstanceField, callInfo.delegateInvokeMethod);
}
public override void Done()
{
if (_done)
{
throw new Exception("Already done");
}
_done = true;
ModuleDef mod = Module;
// for stable order, we sort methods by name
List<CallInfo> callMethodList = _callMethods.Values.ToList();
callMethodList.Sort((a, b) => a.key1.CompareTo(b.key1));
var cctor = new MethodDefUser(".cctor",
MethodSig.CreateStatic(mod.CorLibTypes.Void),
MethodImplAttributes.IL | MethodImplAttributes.Managed,
MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.Private);
cctor.DeclaringType = _delegateInstanceHolderType;
//_rvaTypeDef.Methods.Add(cctor);
var body = new CilBody();
cctor.Body = body;
var ins = body.Instructions;
// var arr = new array[];
// var d = new delegate;
// arr[index] = d;
int index = 0;
ins.Add(Instruction.CreateLdcI4(callMethodList.Count));
ins.Add(Instruction.Create(OpCodes.Newarr, mod.CorLibTypes.Object));
foreach (CallInfo ci in callMethodList)
{
ci.index = index;
_delegateInstanceHolderType.Methods.Add(ci.proxyMethod);
ins.Add(Instruction.Create(OpCodes.Dup));
ins.Add(Instruction.CreateLdcI4(index));
ins.Add(Instruction.Create(OpCodes.Ldnull));
ins.Add(Instruction.Create(OpCodes.Ldftn, ci.proxyMethod));
MethodDef ctor = ci.delegateType.FindMethod(".ctor");
UnityEngine.Assertions.Assert.IsNotNull(ctor, $"Delegate type {ci.delegateType.FullName} does not have a constructor.");
ins.Add(Instruction.Create(OpCodes.Newobj, ctor));
ins.Add(Instruction.Create(OpCodes.Stelem_Ref));
++index;
}
List<CallInfo> callMethodList2 = callMethodList.ToList();
callMethodList2.Sort((a, b) => a.key2.CompareTo(b.key2));
EncryptionScopeInfo encryptionScope = EncryptionScope;
DefaultMetadataImporter importer = this.GetDefaultModuleMetadataImporter();
RvaDataAllocator rvaDataAllocator = this.GetEntity<RvaDataAllocator>();
foreach (CallInfo ci in callMethodList2)
{
_delegateInstanceHolderType.Fields.Add(ci.delegateInstanceField);
ins.Add(Instruction.Create(OpCodes.Dup));
IRandom localRandom = encryptionScope.localRandomCreator(HashUtil.ComputePrimitiveOrStringOrBytesHashCode(ci.key1));
int ops = EncryptionUtil.GenerateEncryptionOpCodes(localRandom, encryptionScope.encryptor, _settings.obfuscationLevel);
int salt = localRandom.NextInt();
int encryptedValue = encryptionScope.encryptor.Encrypt(ci.index, ops, salt);
RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue);
ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
ins.Add(Instruction.CreateLdcI4(rvaData.offset));
ins.Add(Instruction.CreateLdcI4(ops));
ins.Add(Instruction.CreateLdcI4(salt));
ins.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaInt));
ins.Add(Instruction.Create(OpCodes.Ldelem_Ref));
ins.Add(Instruction.Create(OpCodes.Stsfld, ci.delegateInstanceField));
}
ins.Add(Instruction.Create(OpCodes.Pop));
ins.Add(Instruction.Create(OpCodes.Ret));
}
}
}

View File

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

View File

@ -1,81 +0,0 @@
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using Obfuz.Emit;
using Obfuz.Utils;
using System.Collections.Generic;
using System.Linq;
namespace Obfuz.ObfusPasses.CallObfus
{
public class DelegateProxyObfuscator : ObfuscatorBase
{
private readonly GroupByModuleEntityManager _entityManager;
public DelegateProxyObfuscator(GroupByModuleEntityManager moduleEntityManager)
{
_entityManager = moduleEntityManager;
}
public override void Done()
{
_entityManager.Done<DelegateProxyAllocator>();
}
private MethodSig CreateProxyMethodSig(ModuleDef module, IMethod method)
{
MethodSig methodSig = MetaUtil.ToSharedMethodSig(module.CorLibTypes, MetaUtil.GetInflatedMethodSig(method, null));
//MethodSig methodSig = MetaUtil.GetInflatedMethodSig(method).Clone();
//methodSig.Params
switch (MetaUtil.GetThisArgType(method))
{
case ThisArgType.Class:
{
methodSig.Params.Insert(0, module.CorLibTypes.Object);
break;
}
case ThisArgType.ValueType:
{
methodSig.Params.Insert(0, module.CorLibTypes.IntPtr);
break;
}
}
return MethodSig.CreateStatic(methodSig.RetType, methodSig.Params.ToArray());
}
public override bool Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List<Instruction> obfuscatedInstructions)
{
DelegateProxyAllocator allocator = _entityManager.GetEntity<DelegateProxyAllocator>(callingMethod.Module);
LocalVariableAllocator localVarAllocator = new LocalVariableAllocator(callingMethod);
MethodSig methodSig = CreateProxyMethodSig(callingMethod.Module, calledMethod);
DelegateProxyMethodData proxyData = allocator.Allocate(calledMethod, callVir, methodSig);
bool isVoidReturn = MetaUtil.IsVoidType(methodSig.RetType);
using (var varScope = localVarAllocator.CreateScope())
{
List<Local> localVars = new List<Local>();
if (!isVoidReturn)
{
varScope.AllocateLocal(methodSig.RetType);
}
foreach (var p in methodSig.Params)
{
localVars.Add(varScope.AllocateLocal(p));
}
// save args
for (int i = localVars.Count - 1; i >= 0; i--)
{
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Stloc, localVars[i]));
}
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, proxyData.delegateInstanceField));
foreach (var local in localVars)
{
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldloc, local));
}
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Callvirt, proxyData.delegateInvokeMethod));
}
return true;
}
}
}

View File

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

View File

@ -1,52 +0,0 @@
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using Obfuz.Data;
using Obfuz.Emit;
using Obfuz.Utils;
using System.Collections.Generic;
namespace Obfuz.ObfusPasses.CallObfus
{
public class DispatchProxyObfuscator : ObfuscatorBase
{
private readonly GroupByModuleEntityManager _moduleEntityManager;
public DispatchProxyObfuscator(GroupByModuleEntityManager moduleEntityManager)
{
_moduleEntityManager = moduleEntityManager;
}
public override void Done()
{
_moduleEntityManager.Done<ModuleDispatchProxyAllocator>();
}
public override bool Obfuscate(MethodDef callerMethod, IMethod calledMethod, bool callVir, List<Instruction> obfuscatedInstructions)
{
ModuleDispatchProxyAllocator proxyCallAllocator = _moduleEntityManager.GetEntity<ModuleDispatchProxyAllocator>(callerMethod.Module);
MethodSig sharedMethodSig = MetaUtil.ToSharedMethodSig(calledMethod.Module.CorLibTypes, MetaUtil.GetInflatedMethodSig(calledMethod, null));
ProxyCallMethodData proxyCallMethodData = proxyCallAllocator.Allocate(calledMethod, callVir);
DefaultMetadataImporter importer = proxyCallAllocator.GetDefaultModuleMetadataImporter();
//if (needCacheCall)
//{
// FieldDef cacheField = _constFieldAllocator.Allocate(callerMethod.Module, proxyCallMethodData.index);
// obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField));
//}
//else
//{
// obfuscatedInstructions.Add(Instruction.CreateLdcI4(proxyCallMethodData.encryptedIndex));
// obfuscatedInstructions.Add(Instruction.CreateLdcI4(proxyCallMethodData.encryptOps));
// obfuscatedInstructions.Add(Instruction.CreateLdcI4(proxyCallMethodData.salt));
// obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, importer.DecryptInt));
//}
ConstFieldAllocator constFieldAllocator = proxyCallAllocator.GetEntity<ConstFieldAllocator>();
FieldDef cacheField = constFieldAllocator.Allocate(proxyCallMethodData.index);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField));
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, proxyCallMethodData.proxyMethod));
return true;
}
}
}

View File

@ -1,19 +0,0 @@
using dnlib.DotNet;
namespace Obfuz.ObfusPasses.CallObfus
{
public interface IObfuscationPolicy
{
bool NeedObfuscateCallInMethod(MethodDef method);
bool NeedObfuscateCalledMethod(MethodDef callerMethod, IMethod calledMethod, bool callVir);
}
public abstract class ObfuscationPolicyBase : IObfuscationPolicy
{
public abstract bool NeedObfuscateCallInMethod(MethodDef method);
public abstract bool NeedObfuscateCalledMethod(MethodDef callerMethod, IMethod calledMethod, bool callVir);
}
}

View File

@ -1,20 +0,0 @@
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using System.Collections.Generic;
namespace Obfuz.ObfusPasses.CallObfus
{
public interface IObfuscator
{
bool Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List<Instruction> obfuscatedInstructions);
void Done();
}
public abstract class ObfuscatorBase : IObfuscator
{
public abstract bool Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List<Instruction> obfuscatedInstructions);
public abstract void Done();
}
}

View File

@ -1,30 +0,0 @@
using dnlib.DotNet;
using Obfuz.Utils;
using System;
namespace Obfuz.ObfusPasses.CallObfus
{
class MethodKey : IEquatable<MethodKey>
{
public readonly IMethod _method;
public readonly bool _callVir;
private readonly int _hashCode;
public MethodKey(IMethod method, bool callVir)
{
_method = method;
_callVir = callVir;
_hashCode = HashUtil.CombineHash(MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method), callVir ? 1 : 0);
}
public override int GetHashCode()
{
return _hashCode;
}
public bool Equals(MethodKey other)
{
return MethodEqualityComparer.CompareDeclaringTypes.Equals(_method, other._method) && _callVir == other._callVir;
}
}
}

View File

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

View File

@ -1,125 +0,0 @@
using dnlib.DotNet;
using Obfuz.Settings;
using Obfuz.Utils;
using System.Collections.Generic;
namespace Obfuz.ObfusPasses.CallObfus
{
class SpecialWhiteListMethodCalculator
{
private readonly RuntimeType _targetRuntime;
private readonly bool _obfuscateCallToMethodInMscorlib;
private readonly CachedDictionary<IMethod, bool> _specialWhiteListMethodCache;
public SpecialWhiteListMethodCalculator(RuntimeType targetRuntime, bool obfuscateCallToMethodInMscorlib)
{
_targetRuntime = targetRuntime;
_obfuscateCallToMethodInMscorlib = obfuscateCallToMethodInMscorlib;
_specialWhiteListMethodCache = new CachedDictionary<IMethod, bool>(MethodEqualityComparer.CompareDeclaringTypes, this.ComputeIsInWhiteList);
}
public bool IsInWhiteList(IMethod calledMethod)
{
return _specialWhiteListMethodCache.GetValue(calledMethod);
}
private static readonly HashSet<string> _specialTypeFullNames = new HashSet<string>
{
"System.Enum",
"System.Delegate",
"System.MulticastDelegate",
"Obfuz.EncryptionService`1",
};
private static readonly HashSet<string> _specialMethodNames = new HashSet<string>
{
"GetEnumerator", // List<T>.Enumerator.GetEnumerator()
".ctor", // constructor
};
private static readonly HashSet<string> _specialMethodFullNames = new HashSet<string>
{
"System.Reflection.MethodBase.GetCurrentMethod",
"System.Reflection.Assembly.GetCallingAssembly",
"System.Reflection.Assembly.GetExecutingAssembly",
"System.Reflection.Assembly.GetEntryAssembly",
};
private bool ComputeIsInWhiteList(IMethod calledMethod)
{
MethodDef calledMethodDef = calledMethod.ResolveMethodDef();
// mono has more strict access control, calls non-public method will raise exception.
if (_targetRuntime == RuntimeType.Mono)
{
if (calledMethodDef != null && (!calledMethodDef.IsPublic || !IsTypeSelfAndParentPublic(calledMethodDef.DeclaringType)))
{
return true;
}
}
ITypeDefOrRef declaringType = calledMethod.DeclaringType;
TypeSig declaringTypeSig = calledMethod.DeclaringType.ToTypeSig();
declaringTypeSig = declaringTypeSig.RemovePinnedAndModifiers();
switch (declaringTypeSig.ElementType)
{
case ElementType.ValueType:
case ElementType.Class:
{
break;
}
case ElementType.GenericInst:
{
if (MetaUtil.ContainsContainsGenericParameter(calledMethod))
{
return true;
}
break;
}
default: return true;
}
TypeDef typeDef = declaringType.ResolveTypeDef();
if (!_obfuscateCallToMethodInMscorlib && typeDef.Module.IsCoreLibraryModule == true)
{
return true;
}
if (typeDef.IsDelegate || typeDef.IsEnum)
return true;
string fullName = typeDef.FullName;
if (_specialTypeFullNames.Contains(fullName))
{
return true;
}
//if (fullName.StartsWith("System.Runtime.CompilerServices."))
//{
// return true;
//}
string methodName = calledMethod.Name;
if (_specialMethodNames.Contains(methodName))
{
return true;
}
string methodFullName = $"{fullName}.{methodName}";
if (_specialMethodFullNames.Contains(methodFullName))
{
return true;
}
return false;
}
private bool IsTypeSelfAndParentPublic(TypeDef type)
{
if (type.DeclaringType != null && !IsTypeSelfAndParentPublic(type.DeclaringType))
{
return false;
}
return type.IsPublic;
}
}
}

View File

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

View File

@ -1,337 +0,0 @@
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using Obfuz.Data;
using Obfuz.Emit;
using Obfuz.Settings;
using Obfuz.Utils;
using System.Collections.Generic;
using System.Text;
using UnityEngine.Assertions;
namespace Obfuz.ObfusPasses.ConstEncrypt
{
public class DefaultConstEncryptor : IConstEncryptor
{
private readonly GroupByModuleEntityManager _moduleEntityManager;
private readonly ConstEncryptionSettingsFacade _settings;
public DefaultConstEncryptor(GroupByModuleEntityManager moduleEntityManager, ConstEncryptionSettingsFacade settings)
{
_moduleEntityManager = moduleEntityManager;
_settings = settings;
}
private IRandom CreateRandomForValue(EncryptionScopeInfo encryptionScope, int value)
{
return encryptionScope.localRandomCreator(value);
}
private int GenerateEncryptionOperations(EncryptionScopeInfo encryptionScope, IRandom random)
{
return EncryptionUtil.GenerateEncryptionOpCodes(random, encryptionScope.encryptor, _settings.encryptionLevel);
}
public int GenerateSalt(IRandom random)
{
return random.NextInt();
}
private DefaultMetadataImporter GetModuleMetadataImporter(MethodDef method)
{
return _moduleEntityManager.GetEntity<DefaultMetadataImporter>(method.Module);
}
public void ObfuscateInt(MethodDef method, bool needCacheValue, int value, List<Instruction> obfuscatedInstructions)
{
EncryptionScopeInfo encryptionScope = _moduleEntityManager.EncryptionScopeProvider.GetScope(method.Module);
IRandom random = CreateRandomForValue(encryptionScope, value.GetHashCode());
ConstFieldAllocator constFieldAllocator = _moduleEntityManager.GetEntity<ConstFieldAllocator>(method.Module);
RvaDataAllocator rvaDataAllocator = _moduleEntityManager.GetEntity<RvaDataAllocator>(method.Module);
DefaultMetadataImporter importer = GetModuleMetadataImporter(method);
switch (random.NextInt(5))
{
case 0:
{
// = c = encrypted static field
FieldDef cacheField = constFieldAllocator.Allocate(value);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField));
break;
}
case 1:
{
// c = a + b
int a = random.NextInt();
int b = value - a;
float constProbability = 0.5f;
ConstObfusUtil.LoadConstTwoInt(a, b, random, constProbability, constFieldAllocator, obfuscatedInstructions);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Add));
break;
}
case 2:
{
// c = a * b
int a = random.NextInt() | 0x1;
int ra = MathUtil.ModInverse32(a);
int b = ra * value;
float constProbability = 0.5f;
ConstObfusUtil.LoadConstTwoInt(a, b, random, constProbability, constFieldAllocator, obfuscatedInstructions);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Mul));
break;
}
case 3:
{
// c = a ^ b
int a = random.NextInt();
int b = a ^ value;
float constProbability = 0.5f;
ConstObfusUtil.LoadConstTwoInt(a, b, random, constProbability, constFieldAllocator, obfuscatedInstructions);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Xor));
break;
}
default:
{
if (needCacheValue)
{
FieldDef cacheField = constFieldAllocator.Allocate(value);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField));
return;
}
int ops = GenerateEncryptionOperations(encryptionScope, random);
int salt = GenerateSalt(random);
int encryptedValue = encryptionScope.encryptor.Encrypt(value, ops, salt);
RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(rvaData.offset));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(ops));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(salt));
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaInt));
break;
}
}
}
public void ObfuscateLong(MethodDef method, bool needCacheValue, long value, List<Instruction> obfuscatedInstructions)
{
EncryptionScopeInfo encryptionScope = _moduleEntityManager.EncryptionScopeProvider.GetScope(method.Module);
IRandom random = CreateRandomForValue(encryptionScope, value.GetHashCode());
ConstFieldAllocator constFieldAllocator = _moduleEntityManager.GetEntity<ConstFieldAllocator>(method.Module);
RvaDataAllocator rvaDataAllocator = _moduleEntityManager.GetEntity<RvaDataAllocator>(method.Module);
DefaultMetadataImporter importer = GetModuleMetadataImporter(method);
switch (random.NextInt(5))
{
case 0:
{
// c = encrypted static field
FieldDef cacheField = constFieldAllocator.Allocate(value);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField));
break;
}
case 1:
{
// c = a + b
long a = random.NextLong();
long b = value - a;
float constProbability = 0.5f;
ConstObfusUtil.LoadConstTwoLong(a, b, random, constProbability, constFieldAllocator, obfuscatedInstructions);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Add));
break;
}
case 2:
{
// c = a * b
long a = random.NextLong() | 0x1;
long ra = MathUtil.ModInverse64(a);
long b = ra * value;
float constProbability = 0.5f;
ConstObfusUtil.LoadConstTwoLong(a, b, random, constProbability, constFieldAllocator, obfuscatedInstructions);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Mul));
break;
}
case 3:
{
// c = a ^ b
long a = random.NextLong();
long b = a ^ value;
float constProbability = 0.5f;
ConstObfusUtil.LoadConstTwoLong(a, b, random, constProbability, constFieldAllocator, obfuscatedInstructions);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Xor));
break;
}
default:
{
if (needCacheValue)
{
FieldDef cacheField = constFieldAllocator.Allocate(value);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField));
return;
}
int ops = GenerateEncryptionOperations(encryptionScope, random);
int salt = GenerateSalt(random);
long encryptedValue = encryptionScope.encryptor.Encrypt(value, ops, salt);
RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(rvaData.offset));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(ops));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(salt));
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaLong));
break;
}
}
}
public void ObfuscateFloat(MethodDef method, bool needCacheValue, float value, List<Instruction> obfuscatedInstructions)
{
EncryptionScopeInfo encryptionScope = _moduleEntityManager.EncryptionScopeProvider.GetScope(method.Module);
IRandom random = CreateRandomForValue(encryptionScope, value.GetHashCode());
ConstFieldAllocator constFieldAllocator = _moduleEntityManager.GetEntity<ConstFieldAllocator>(method.Module);
RvaDataAllocator rvaDataAllocator = _moduleEntityManager.GetEntity<RvaDataAllocator>(method.Module);
DefaultMetadataImporter importer = GetModuleMetadataImporter(method);
if (needCacheValue)
{
FieldDef cacheField = constFieldAllocator.Allocate(value);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField));
return;
}
int ops = GenerateEncryptionOperations(encryptionScope, random);
int salt = GenerateSalt(random);
float encryptedValue = encryptionScope.encryptor.Encrypt(value, ops, salt);
RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(rvaData.offset));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(ops));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(salt));
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaFloat));
}
public void ObfuscateDouble(MethodDef method, bool needCacheValue, double value, List<Instruction> obfuscatedInstructions)
{
EncryptionScopeInfo encryptionScope = _moduleEntityManager.EncryptionScopeProvider.GetScope(method.Module);
IRandom random = CreateRandomForValue(encryptionScope, value.GetHashCode());
ConstFieldAllocator constFieldAllocator = _moduleEntityManager.GetEntity<ConstFieldAllocator>(method.Module);
RvaDataAllocator rvaDataAllocator = _moduleEntityManager.GetEntity<RvaDataAllocator>(method.Module);
DefaultMetadataImporter importer = GetModuleMetadataImporter(method);
if (needCacheValue)
{
FieldDef cacheField = constFieldAllocator.Allocate(value);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField));
return;
}
int ops = GenerateEncryptionOperations(encryptionScope, random);
int salt = GenerateSalt(random);
double encryptedValue = encryptionScope.encryptor.Encrypt(value, ops, salt);
RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(rvaData.offset));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(ops));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(salt));
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaDouble));
}
class EncryptedRvaDataInfo
{
public readonly FieldDef fieldDef;
public readonly byte[] originalBytes;
public readonly byte[] encryptedBytes;
public readonly int opts;
public readonly int salt;
public EncryptedRvaDataInfo(FieldDef fieldDef, byte[] originalBytes, byte[] encryptedBytes, int opts, int salt)
{
this.fieldDef = fieldDef;
this.originalBytes = originalBytes;
this.encryptedBytes = encryptedBytes;
this.opts = opts;
this.salt = salt;
}
}
private readonly Dictionary<FieldDef, EncryptedRvaDataInfo> _encryptedRvaFields = new Dictionary<FieldDef, EncryptedRvaDataInfo>();
private EncryptedRvaDataInfo GetEncryptedRvaData(FieldDef fieldDef)
{
if (!_encryptedRvaFields.TryGetValue(fieldDef, out var encryptedRvaData))
{
EncryptionScopeInfo encryptionScope = _moduleEntityManager.EncryptionScopeProvider.GetScope(fieldDef.Module);
IRandom random = CreateRandomForValue(encryptionScope, FieldEqualityComparer.CompareDeclaringTypes.GetHashCode(fieldDef));
int ops = GenerateEncryptionOperations(encryptionScope, random);
int salt = GenerateSalt(random);
byte[] originalBytes = fieldDef.InitialValue;
byte[] encryptedBytes = (byte[])originalBytes.Clone();
encryptionScope.encryptor.EncryptBlock(encryptedBytes, ops, salt);
Assert.AreNotEqual(originalBytes, encryptedBytes, "Original bytes should not be the same as encrypted bytes.");
encryptedRvaData = new EncryptedRvaDataInfo(fieldDef, originalBytes, encryptedBytes, ops, salt);
_encryptedRvaFields.Add(fieldDef, encryptedRvaData);
fieldDef.InitialValue = encryptedBytes;
byte[] decryptedBytes = (byte[])encryptedBytes.Clone();
encryptionScope.encryptor.DecryptBlock(decryptedBytes, ops, salt);
AssertUtil.AreArrayEqual(originalBytes, decryptedBytes, "Decrypted bytes should match the original bytes after encryption and decryption.");
}
return encryptedRvaData;
}
public void ObfuscateBytes(MethodDef method, bool needCacheValue, FieldDef field, byte[] value, List<Instruction> obfuscatedInstructions)
{
EncryptedRvaDataInfo encryptedData = GetEncryptedRvaData(field);
Assert.AreEqual(value.Length, encryptedData.encryptedBytes.Length);
DefaultMetadataImporter importer = GetModuleMetadataImporter(method);
obfuscatedInstructions.Add(Instruction.CreateLdcI4(encryptedData.encryptedBytes.Length));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(encryptedData.opts));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(encryptedData.salt));
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, importer.DecryptInitializeArray));
}
public void ObfuscateString(MethodDef method, bool needCacheValue, string value, List<Instruction> obfuscatedInstructions)
{
EncryptionScopeInfo encryptionScope = _moduleEntityManager.EncryptionScopeProvider.GetScope(method.Module);
IRandom random = CreateRandomForValue(encryptionScope, value.GetHashCode());
ConstFieldAllocator constFieldAllocator = _moduleEntityManager.GetEntity<ConstFieldAllocator>(method.Module);
RvaDataAllocator rvaDataAllocator = _moduleEntityManager.GetEntity<RvaDataAllocator>(method.Module);
DefaultMetadataImporter importer = GetModuleMetadataImporter(method);
if (needCacheValue)
{
FieldDef cacheField = constFieldAllocator.Allocate(value);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField));
return;
}
int ops = GenerateEncryptionOperations(encryptionScope, random);
int salt = GenerateSalt(random);
int stringByteLength = Encoding.UTF8.GetByteCount(value);
byte[] encryptedValue = encryptionScope.encryptor.Encrypt(value, ops, salt);
Assert.AreEqual(stringByteLength, encryptedValue.Length);
RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(rvaData.offset));
// should use stringByteLength, can't use rvaData.size, because rvaData.size is align to 4, it's not the actual length.
obfuscatedInstructions.Add(Instruction.CreateLdcI4(stringByteLength));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(ops));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(salt));
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaString));
}
public void Done()
{
}
}
}

View File

@ -1,133 +0,0 @@
using dnlib.DotNet;
using Obfuz.Conf;
using Obfuz.Settings;
using Obfuz.Utils;
using System;
using System.Collections.Generic;
using System.Xml;
namespace Obfuz.ObfusPasses.ControlFlowObfus
{
struct ObfuscationRuleData
{
public readonly ObfuscationLevel obfuscationLevel;
public ObfuscationRuleData(ObfuscationLevel level)
{
obfuscationLevel = level;
}
}
interface IObfuscationPolicy
{
bool NeedObfuscate(MethodDef method);
ObfuscationRuleData GetObfuscationRuleData(MethodDef method);
}
abstract class ObfuscationPolicyBase : IObfuscationPolicy
{
public abstract bool NeedObfuscate(MethodDef method);
public abstract ObfuscationRuleData GetObfuscationRuleData(MethodDef method);
}
class ConfigurableObfuscationPolicy : ObfuscationPolicyBase
{
class ObfuscationRule : IRule<ObfuscationRule>
{
public ObfuscationLevel? obfuscationLevel;
public void InheritParent(ObfuscationRule parentRule)
{
if (obfuscationLevel == null)
obfuscationLevel = parentRule.obfuscationLevel;
}
}
class MethodSpec : MethodRuleBase<ObfuscationRule>
{
}
class TypeSpec : TypeRuleBase<MethodSpec, ObfuscationRule>
{
}
class AssemblySpec : AssemblyRuleBase<TypeSpec, MethodSpec, ObfuscationRule>
{
}
private static readonly ObfuscationRule s_default = new ObfuscationRule()
{
obfuscationLevel = ObfuscationLevel.Basic,
};
private ObfuscationRule _global;
private readonly XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule> _xmlParser;
private readonly Dictionary<MethodDef, ObfuscationRule> _methodRuleCache = new Dictionary<MethodDef, ObfuscationRule>();
public ConfigurableObfuscationPolicy(List<string> toObfuscatedAssemblyNames, List<string> xmlConfigFiles)
{
_xmlParser = new XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule>(
toObfuscatedAssemblyNames, ParseObfuscationRule, ParseGlobal);
LoadConfigs(xmlConfigFiles);
}
private void LoadConfigs(List<string> configFiles)
{
_xmlParser.LoadConfigs(configFiles);
if (_global == null)
{
_global = s_default;
}
else
{
_global.InheritParent(s_default);
}
_xmlParser.InheritParentRules(_global);
}
private void ParseGlobal(string configFile, XmlElement ele)
{
switch (ele.Name)
{
case "global": _global = ParseObfuscationRule(configFile, ele); break;
default: throw new Exception($"Invalid xml file {configFile}, unknown node {ele.Name}");
}
}
private ObfuscationRule ParseObfuscationRule(string configFile, XmlElement ele)
{
var rule = new ObfuscationRule();
if (ele.HasAttribute("obfuscationLevel"))
{
rule.obfuscationLevel = ConfigUtil.ParseObfuscationLevel(ele.GetAttribute("obfuscationLevel"));
}
return rule;
}
private ObfuscationRule GetMethodObfuscationRule(MethodDef method)
{
if (!_methodRuleCache.TryGetValue(method, out var rule))
{
rule = _xmlParser.GetMethodRule(method, _global);
_methodRuleCache[method] = rule;
}
return rule;
}
public override bool NeedObfuscate(MethodDef method)
{
ObfuscationRule rule = GetMethodObfuscationRule(method);
return rule.obfuscationLevel.Value > ObfuscationLevel.None;
}
public override ObfuscationRuleData GetObfuscationRuleData(MethodDef method)
{
var rule = GetMethodObfuscationRule(method);
return new ObfuscationRuleData(rule.obfuscationLevel.Value);
}
}
}

View File

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

View File

@ -1,80 +0,0 @@
using dnlib.DotNet;
using Obfuz.Data;
using Obfuz.Emit;
using Obfuz.Settings;
using Obfuz.Utils;
namespace Obfuz.ObfusPasses.ControlFlowObfus
{
class ObfusMethodContext
{
public MethodDef method;
public LocalVariableAllocator localVariableAllocator;
public IRandom localRandom;
public EncryptionScopeInfo encryptionScope;
public DefaultMetadataImporter importer;
public ConstFieldAllocator constFieldAllocator;
public int minInstructionCountOfBasicBlockToObfuscate;
public IRandom CreateRandom()
{
return encryptionScope.localRandomCreator(MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method));
}
}
internal class ControlFlowObfusPass : ObfuscationMethodPassBase
{
private readonly ControlFlowObfuscationSettingsFacade _settings;
private IObfuscationPolicy _obfuscationPolicy;
private IObfuscator _obfuscator;
public ControlFlowObfusPass(ControlFlowObfuscationSettingsFacade settings)
{
_settings = settings;
_obfuscator = new DefaultObfuscator();
}
public override ObfuscationPassType Type => ObfuscationPassType.ControlFlowObfus;
public override void Start()
{
ObfuscationPassContext ctx = ObfuscationPassContext.Current;
_obfuscationPolicy = new ConfigurableObfuscationPolicy(
ctx.coreSettings.assembliesToObfuscate,
_settings.ruleFiles);
}
public override void Stop()
{
}
protected override bool NeedObfuscateMethod(MethodDef method)
{
return _obfuscationPolicy.NeedObfuscate(method);
}
protected override void ObfuscateData(MethodDef method)
{
//Debug.Log($"Obfuscating method: {method.FullName} with EvalStackObfusPass");
ObfuscationPassContext ctx = ObfuscationPassContext.Current;
GroupByModuleEntityManager moduleEntityManager = ctx.moduleEntityManager;
var encryptionScope = moduleEntityManager.EncryptionScopeProvider.GetScope(method.Module);
var ruleData = _obfuscationPolicy.GetObfuscationRuleData(method);
var localRandom = encryptionScope.localRandomCreator(MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method));
var obfusMethodCtx = new ObfusMethodContext
{
method = method,
localVariableAllocator = new LocalVariableAllocator(method),
encryptionScope = encryptionScope,
constFieldAllocator = moduleEntityManager.GetEntity<ConstFieldAllocator>(method.Module),
localRandom = localRandom,
importer = moduleEntityManager.GetEntity<DefaultMetadataImporter>(method.Module),
minInstructionCountOfBasicBlockToObfuscate = _settings.minInstructionCountOfBasicBlockToObfuscate,
};
_obfuscator.Obfuscate(method, obfusMethodCtx);
}
}
}

View File

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

View File

@ -1,19 +0,0 @@
using dnlib.DotNet;
namespace Obfuz.ObfusPasses.ControlFlowObfus
{
class DefaultObfuscator : ObfuscatorBase
{
public override bool Obfuscate(MethodDef method, ObfusMethodContext ctx)
{
//Debug.Log($"Obfuscating method: {method.FullName} with ControlFlowObfusPass");
var mcfc = new MethodControlFlowCalculator(method, ctx.CreateRandom(), ctx.constFieldAllocator, ctx.minInstructionCountOfBasicBlockToObfuscate);
if (!mcfc.TryObfus())
{
//Debug.LogWarning($"not obfuscate method: {method.FullName}");
return false;
}
return true;
}
}
}

View File

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

View File

@ -1,14 +0,0 @@
using dnlib.DotNet;
namespace Obfuz.ObfusPasses.ControlFlowObfus
{
interface IObfuscator
{
bool Obfuscate(MethodDef method, ObfusMethodContext ctx);
}
abstract class ObfuscatorBase : IObfuscator
{
public abstract bool Obfuscate(MethodDef method, ObfusMethodContext ctx);
}
}

View File

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

View File

@ -1,947 +0,0 @@
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using Obfuz.Data;
using Obfuz.Emit;
using Obfuz.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Assertions;
namespace Obfuz.ObfusPasses.ControlFlowObfus
{
class MethodControlFlowCalculator
{
class BasicBlockInputOutputArguments
{
public readonly List<Local> locals = new List<Local>();
public BasicBlockInputOutputArguments()
{
}
public BasicBlockInputOutputArguments(MethodDef method, List<EvalDataTypeWithSig> inputStackDatas)
{
ICorLibTypes corLibTypes = method.Module.CorLibTypes;
foreach (var data in inputStackDatas)
{
Local local = new Local(GetLocalTypeSig(corLibTypes, data));
locals.Add(local);
method.Body.Variables.Add(local);
}
}
private TypeSig GetLocalTypeSig(ICorLibTypes corLibTypes, EvalDataTypeWithSig type)
{
TypeSig typeSig = type.typeSig;
switch (type.type)
{
case EvalDataType.Int32: return corLibTypes.Int32;
case EvalDataType.Int64: return corLibTypes.Int64;
case EvalDataType.Float: return corLibTypes.Single;
case EvalDataType.Double: return corLibTypes.Double;
case EvalDataType.I: return typeSig ?? corLibTypes.IntPtr;
case EvalDataType.Ref: return typeSig == null || MetaUtil.IsValueType(typeSig) ? corLibTypes.Object : typeSig;
case EvalDataType.ValueType: Assert.IsNotNull(typeSig); return typeSig;
case EvalDataType.Token: throw new System.NotSupportedException("Token type is not supported in BasicBlockInputOutputArguments");
default: throw new System.NotSupportedException("not supported EvalDataType");
}
}
}
class BasicBlockInfo
{
public BlockGroup group;
//public int order;
public bool isSaveStackBlock;
public BasicBlockInfo prev;
public BasicBlockInfo next;
public List<Instruction> instructions;
public List<EvalDataTypeWithSig> inputStackDatas;
public List<EvalDataTypeWithSig> outputStackDatas;
public List<BasicBlockInfo> inBasicBlocks = new List<BasicBlockInfo>();
public List<BasicBlockInfo> outBasicBlocks = new List<BasicBlockInfo>();
public BasicBlockInputOutputArguments inputArgs;
public BasicBlockInputOutputArguments outputArgs;
public Instruction FirstInstruction => instructions[0];
public Instruction LastInstruction => instructions[instructions.Count - 1];
public Instruction GroupFirstInstruction => group.basicBlocks[0].FirstInstruction;
//public void InsertNext(BasicBlockInfo nextBb)
//{
// if (next != null)
// {
// next.prev = nextBb;
// nextBb.next = next;
// }
// nextBb.prev = this;
// next = nextBb;
//}
public void InsertBefore(BasicBlockInfo prevBb)
{
prev.next = prevBb;
prevBb.prev = prev;
prevBb.next = this;
this.prev = prevBb;
}
public void AddOutBasicBlock(BasicBlockInfo outBb)
{
if (!outBasicBlocks.Contains(outBb))
{
outBasicBlocks.Add(outBb);
outBb.inBasicBlocks.Add(this);
}
}
public void ClearInBasicBlocks()
{
foreach (var inBb in inBasicBlocks)
{
inBb.outBasicBlocks.Remove(this);
}
inBasicBlocks.Clear();
}
public void RetargetInBasicBlocksTo(BasicBlockInfo prevBb, Dictionary<Instruction, BasicBlockInfo> inst2bb)
{
var oldInBlocks = new List<BasicBlockInfo>(inBasicBlocks);
ClearInBasicBlocks();
foreach (var oldInBb in oldInBlocks)
{
oldInBb.AddOutBasicBlock(prevBb);
}
// inBB => saveBb => cur
foreach (BasicBlockInfo inBb in prevBb.inBasicBlocks)
{
if (inBb.instructions.Count == 0)
{
// empty block, no need to retarget
continue;
}
Instruction lastInst = inBb.instructions.Last();
if (lastInst.Operand is Instruction targetInst)
{
if (inst2bb.TryGetValue(targetInst, out BasicBlockInfo targetBb) && targetBb == this)
{
// retarget to prevBb
lastInst.Operand = prevBb.FirstInstruction;
}
}
else if (lastInst.Operand is Instruction[] targetInsts)
{
for (int i = 0; i < targetInsts.Length; i++)
{
targetInst = targetInsts[i];
if (inst2bb.TryGetValue(targetInst, out BasicBlockInfo targetBb) && targetBb == this)
{
targetInsts[i] = prevBb.FirstInstruction;
}
}
}
}
}
}
private readonly MethodDef _method;
private readonly IRandom _random;
private readonly ConstFieldAllocator _constFieldAllocator;
private readonly int _minInstructionCountOfBasicBlockToObfuscate;
private readonly BasicBlockInfo _bbHead;
public MethodControlFlowCalculator(MethodDef method, IRandom random, ConstFieldAllocator constFieldAllocator, int minInstructionCountOfBasicBlockToObfuscate)
{
_method = method;
_random = random;
_constFieldAllocator = constFieldAllocator;
_minInstructionCountOfBasicBlockToObfuscate = minInstructionCountOfBasicBlockToObfuscate;
_bbHead = new BasicBlockInfo()
{
instructions = new List<Instruction>(),
inputStackDatas = new List<EvalDataTypeWithSig>(),
outputStackDatas = new List<EvalDataTypeWithSig>(),
};
}
private void BuildBasicBlockLink(EvalStackCalculator evc)
{
BasicBlockInfo prev = _bbHead;
var bb2bb = new Dictionary<BasicBlock, BasicBlockInfo>();
foreach (BasicBlock bb in evc.BasicBlockCollection.Blocks)
{
EvalStackState ess = evc.GetEvalStackState(bb);
var newBB = new BasicBlockInfo
{
prev = prev,
next = null,
instructions = bb.instructions,
inputStackDatas = ess.inputStackDatas,
outputStackDatas = ess.runStackDatas,
};
prev.next = newBB;
prev = newBB;
bb2bb.Add(bb, newBB);
}
foreach (BasicBlock bb in evc.BasicBlockCollection.Blocks)
{
BasicBlockInfo bbi = bb2bb[bb];
foreach (var inBb in bb.inBlocks)
{
bbi.inBasicBlocks.Add(bb2bb[inBb]);
}
foreach (var outBb in bb.outBlocks)
{
bbi.outBasicBlocks.Add(bb2bb[outBb]);
}
}
// let _bbHead point to the first basic block
//_bbHead.instructions.Add(Instruction.Create(OpCodes.Br, _bbHead.next.FirstInstruction));
_bbHead.next.inBasicBlocks.Add(_bbHead);
_bbHead.outBasicBlocks.Add(_bbHead.next);
}
private bool CheckNotContainsNotSupportedEvalStackData()
{
for (BasicBlockInfo cur = _bbHead; cur != null; cur = cur.next)
{
foreach (var data in cur.inputStackDatas)
{
if (data.type == EvalDataType.Unknown || data.type == EvalDataType.Token)
{
Debug.LogError($"NotSupported EvalStackData found in method: {_method.FullName}, type: {data.type}");
return false;
}
}
}
return true;
}
private void WalkInputArgumentGroup(BasicBlockInfo cur, BasicBlockInputOutputArguments inputArgs)
{
if (cur.inputArgs != null)
{
Assert.AreEqual(cur.inputArgs, inputArgs, "input arguments not match");
return;
}
cur.inputArgs = inputArgs;
foreach (BasicBlockInfo inputBB in cur.inBasicBlocks)
{
if (inputBB.outputArgs != null)
{
Assert.AreEqual(inputBB.outputArgs, inputArgs, $"Input BB {inputBB} outputArgs does not match in method: {_method.FullName}");
continue;
}
inputBB.outputArgs = cur.inputArgs;
foreach (var outBB in inputBB.outBasicBlocks)
{
WalkInputArgumentGroup(outBB, inputArgs);
}
}
}
private readonly BasicBlockInputOutputArguments emptyEvalStackArgs = new BasicBlockInputOutputArguments();
private void ComputeInputOutputArguments()
{
for (BasicBlockInfo cur = _bbHead; cur != null; cur = cur.next)
{
if (cur.inputArgs == null)
{
if (cur.inputStackDatas.Count == 0)
{
cur.inputArgs = emptyEvalStackArgs;
}
else
{
var inputArgs = new BasicBlockInputOutputArguments(_method, cur.inputStackDatas);
WalkInputArgumentGroup(cur, inputArgs);
}
}
if (cur.outputArgs == null && cur.outputStackDatas.Count == 0)
{
cur.outputArgs = emptyEvalStackArgs;
}
}
for (BasicBlockInfo cur = _bbHead; cur != null; cur = cur.next)
{
if (cur.inputArgs == null)
{
throw new System.Exception($"Input arguments for BasicBlock {cur} in method {_method.FullName} is null");
}
if (cur.outputArgs == null)
{
if (cur.instructions.Count > 0)
{
Code lastInstCode = cur.LastInstruction.OpCode.Code;
Assert.IsTrue(lastInstCode == Code.Throw || lastInstCode == Code.Rethrow);
cur.outputStackDatas = new List<EvalDataTypeWithSig>();
}
cur.outputArgs = emptyEvalStackArgs;
}
}
}
private BasicBlockInfo CreateSaveStackBasicBlock(BasicBlockInfo to)
{
if (to.group == null)
{
throw new Exception($"BasicBlock {to} in method {_method.FullName} does not belong to any group. This should not happen.");
}
var saveLocalBasicBlock = new BasicBlockInfo
{
group = to.group,
isSaveStackBlock = true,
inputStackDatas = to.inputStackDatas,
inputArgs = to.inputArgs,
outputStackDatas = new List<EvalDataTypeWithSig>(),
outputArgs = emptyEvalStackArgs,
instructions = new List<Instruction>(),
};
var locals = to.inputArgs.locals;
if (locals.Count > 0)
{
to.instructions.InsertRange(0, locals.Select(l => Instruction.Create(OpCodes.Ldloc, l)));
}
for (int i = locals.Count - 1; i >= 0; i--)
{
saveLocalBasicBlock.instructions.Add(Instruction.Create(OpCodes.Stloc, locals[i]));
}
to.inputArgs = emptyEvalStackArgs;
to.inputStackDatas = new List<EvalDataTypeWithSig>();
BlockGroup group = to.group;
group.basicBlocks.Insert(group.basicBlocks.IndexOf(to), saveLocalBasicBlock);
group.switchMachineCases.Add(new SwitchMachineCase { index = -1, prepareBlock = saveLocalBasicBlock, targetBlock = to });
saveLocalBasicBlock.instructions.Add(Instruction.Create(OpCodes.Ldsfld, (FieldDef)null));
saveLocalBasicBlock.instructions.Add(Instruction.Create(OpCodes.Stloc, GlobalSwitchIndexLocal));
saveLocalBasicBlock.instructions.Add(Instruction.Create(OpCodes.Br, group.switchMachineEntryInst));
return saveLocalBasicBlock;
}
private void AdjustInputOutputEvalStack()
{
Dictionary<Instruction, BasicBlockInfo> inst2bb = BuildInstructionToBasicBlockInfoDic();
for (BasicBlockInfo cur = _bbHead.next; cur != null; cur = cur.next)
{
if (cur.inputArgs.locals.Count == 0 && cur.instructions.Count < _minInstructionCountOfBasicBlockToObfuscate)
{
// small block, no need to save stack
continue;
}
BasicBlockInfo saveBb = CreateSaveStackBasicBlock(cur);
cur.InsertBefore(saveBb);
cur.RetargetInBasicBlocksTo(saveBb, inst2bb);
//saveBb.AddOutBasicBlock(cur);
}
}
private void InsertSwitchMachineBasicBlockForGroups(BlockGroup rootGroup)
{
Dictionary<Instruction, BasicBlockInfo> inst2bb = BuildInstructionToBasicBlockInfoDic();
InsertSwitchMachineBasicBlockForGroup(rootGroup, inst2bb);
}
private void ShuffleBasicBlocks0(List<BasicBlockInfo> bbs)
{
if (bbs.Count <= 2)
{
return;
}
var subBlocksExcludeFirstLast = bbs.GetRange(1, bbs.Count - 2);
var blocksInputArgsCountZero = new List<BasicBlockInfo>();
var blocksInputArgsCountNonZero = new List<BasicBlockInfo>();
foreach (var bb in subBlocksExcludeFirstLast)
{
if (bb.inputArgs.locals.Count == 0)
{
blocksInputArgsCountZero.Add(bb);
}
else
{
blocksInputArgsCountNonZero.Add(bb);
}
}
RandomUtil.ShuffleList(blocksInputArgsCountZero, _random);
int index = 1;
foreach (var bb in blocksInputArgsCountZero)
{
bbs[index++] = bb;
}
foreach (var bb in blocksInputArgsCountNonZero)
{
bbs[index++] = bb;
}
Assert.AreEqual(bbs.Count - 1, index, "Shuffled basic blocks count should be the same as original count minus first and last blocks");
//var firstSection = new List<BasicBlockInfo>() { bbs[0] };
//var sectionsExcludeFirstLast = new List<List<BasicBlockInfo>>();
//List<BasicBlockInfo> currentSection = firstSection;
//for (int i = 1; i < n; i++)
//{
// BasicBlockInfo cur = bbs[i];
// if (cur.inputArgs.locals.Count == 0)
// {
// currentSection = new List<BasicBlockInfo>() { cur };
// sectionsExcludeFirstLast.Add(currentSection);
// }
// else
// {
// currentSection.Add(cur);
// }
//}
//if (sectionsExcludeFirstLast.Count <= 1)
//{
// return;
//}
//var lastSection = sectionsExcludeFirstLast.Last();
//sectionsExcludeFirstLast.RemoveAt(sectionsExcludeFirstLast.Count - 1);
//RandomUtil.ShuffleList(sectionsExcludeFirstLast, _random);
//bbs.Clear();
//bbs.AddRange(firstSection);
//bbs.AddRange(sectionsExcludeFirstLast.SelectMany(section => section));
//bbs.AddRange(lastSection);
//Assert.AreEqual(n, bbs.Count, "Shuffled basic blocks count should be the same as original count");
}
private void ShuffleBasicBlocks(List<BasicBlockInfo> bbs)
{
// TODO
int n = bbs.Count;
BasicBlockInfo groupPrev = bbs[0].prev;
BasicBlockInfo groupNext = bbs[n - 1].next;
//RandomUtil.ShuffleList(bbs, _random);
ShuffleBasicBlocks0(bbs);
BasicBlockInfo prev = groupPrev;
for (int i = 0; i < n; i++)
{
BasicBlockInfo cur = bbs[i];
cur.prev = prev;
prev.next = cur;
prev = cur;
}
prev.next = groupNext;
if (groupNext != null)
{
groupNext.prev = prev;
}
}
private Local _globalSwitchIndexLocal;
Local GlobalSwitchIndexLocal
{
get
{
if (_globalSwitchIndexLocal == null)
{
_globalSwitchIndexLocal = new Local(_method.Module.CorLibTypes.Int32);
_method.Body.Variables.Add(_globalSwitchIndexLocal);
}
return _globalSwitchIndexLocal;
}
}
private void InsertSwitchMachineBasicBlockForGroup(BlockGroup group, Dictionary<Instruction, BasicBlockInfo> inst2bb)
{
if (group.subGroups != null && group.subGroups.Count > 0)
{
foreach (var subGroup in group.subGroups)
{
InsertSwitchMachineBasicBlockForGroup(subGroup, inst2bb);
}
}
else if (group.switchMachineCases.Count > 0)
{
Assert.IsTrue(group.basicBlocks.Count > 0, "Group should contain at least one basic block");
BasicBlockInfo firstBlock = group.basicBlocks[0];
var firstCase = group.switchMachineCases[0];
//Assert.AreEqual(firstCase.prepareBlock, firstBlock, "First case prepare block should be the first basic block in group");
Assert.IsTrue(firstCase.targetBlock.inputArgs.locals.Count == 0);
Assert.IsTrue(firstCase.targetBlock.inputStackDatas.Count == 0);
var instructions = new List<Instruction>()
{
Instruction.Create(OpCodes.Ldsfld, (FieldDef)null),
Instruction.Create(OpCodes.Stloc, GlobalSwitchIndexLocal),
group.switchMachineEntryInst,
group.switchMachineInst,
Instruction.Create(OpCodes.Br, firstCase.targetBlock.FirstInstruction),
};
if (firstCase.prepareBlock != firstBlock || firstBlock.inputStackDatas.Count != 0)
{
instructions.Insert(0, Instruction.Create(OpCodes.Br, firstBlock.FirstInstruction));
}
var switchMachineBb = new BasicBlockInfo()
{
group = group,
inputArgs = firstBlock.inputArgs,
outputArgs = emptyEvalStackArgs,
inputStackDatas = firstBlock.inputStackDatas,
outputStackDatas = new List<EvalDataTypeWithSig>(),
instructions = instructions,
};
firstBlock.InsertBefore(switchMachineBb);
group.basicBlocks.Insert(0, switchMachineBb);
ShuffleBasicBlocks(group.basicBlocks);
List<Instruction> switchTargets = (List<Instruction>)group.switchMachineInst.Operand;
RandomUtil.ShuffleList(group.switchMachineCases, _random);
for (int i = 0, n = group.switchMachineCases.Count; i < n; i++)
{
SwitchMachineCase switchMachineCase = group.switchMachineCases[i];
switchMachineCase.index = i;
List<Instruction> prepareBlockInstructions = switchMachineCase.prepareBlock.instructions;
Instruction setBranchIndexInst = prepareBlockInstructions[prepareBlockInstructions.Count - 3];
Assert.AreEqual(setBranchIndexInst.OpCode, OpCodes.Ldsfld, "first instruction of prepareBlock should be Ldsfld");
//setBranchIndexInst.Operand = i;
var indexField = _constFieldAllocator.Allocate(i);
setBranchIndexInst.Operand = indexField;
switchTargets.Add(switchMachineCase.targetBlock.FirstInstruction);
}
// after shuffle
//Assert.IsTrue(instructions.Count == 4 || instructions.Count == 5, "Switch machine basic block should contain 4 or 5 instructions");
Instruction loadFirstIndex = instructions[instructions.Count - 5];
Assert.AreEqual(Code.Ldsfld, loadFirstIndex.OpCode.Code, "First instruction should be Ldsfld");
loadFirstIndex.Operand = _constFieldAllocator.Allocate(firstCase.index);
}
}
private bool IsPrevBasicBlockControlFlowNextToThis(BasicBlockInfo cur)
{
Instruction lastInst = cur.prev.LastInstruction;
switch (lastInst.OpCode.FlowControl)
{
case FlowControl.Cond_Branch:
case FlowControl.Call:
case FlowControl.Next:
case FlowControl.Break:
{
return true;
}
default: return false;
}
}
private void InsertBrInstructionForConjoinedBasicBlocks()
{
for (BasicBlockInfo cur = _bbHead.next.next; cur != null; cur = cur.next)
{
if (cur.group == cur.prev.group && IsPrevBasicBlockControlFlowNextToThis(cur))
{
cur.prev.instructions.Add(Instruction.Create(OpCodes.Br, cur.FirstInstruction));
}
}
}
private Dictionary<Instruction, BasicBlockInfo> BuildInstructionToBasicBlockInfoDic()
{
var inst2bb = new Dictionary<Instruction, BasicBlockInfo>();
for (BasicBlockInfo cur = _bbHead.next; cur != null; cur = cur.next)
{
foreach (var inst in cur.instructions)
{
inst2bb[inst] = cur;
}
}
return inst2bb;
}
private class SwitchMachineCase
{
public int index;
public BasicBlockInfo prepareBlock;
public BasicBlockInfo targetBlock;
}
private class BlockGroup
{
public BlockGroup parent;
public List<Instruction> instructions;
public List<BlockGroup> subGroups;
public List<BasicBlockInfo> basicBlocks;
public Instruction switchMachineEntryInst;
public Instruction switchMachineInst;
public List<SwitchMachineCase> switchMachineCases;
public BlockGroup(List<Instruction> instructions, Dictionary<Instruction, BlockGroup> inst2group)
{
this.instructions = instructions;
UpdateInstructionGroup(inst2group);
}
public BlockGroup(BlockGroup parent, List<Instruction> instructions, Dictionary<Instruction, BlockGroup> inst2group)
{
this.instructions = instructions;
UpdateInstructionGroup(parent, inst2group);
}
public BlockGroup RootParent => parent == null ? this : parent.RootParent;
public void SetParent(BlockGroup newParent)
{
if (parent != null)
{
Assert.IsTrue(parent != newParent, "Parent group should not be the same as new parent");
Assert.IsTrue(parent.subGroups.Contains(this), "Parent group should already contain this group");
parent.subGroups.Remove(this);
}
parent = newParent;
if (newParent.subGroups == null)
{
newParent.subGroups = new List<BlockGroup>();
}
Assert.IsFalse(newParent.subGroups.Contains(this), "New parent group should not already contain this group");
newParent.subGroups.Add(this);
}
private void UpdateInstructionGroup(Dictionary<Instruction, BlockGroup> inst2group)
{
foreach (var inst in instructions)
{
if (inst2group.TryGetValue(inst, out BlockGroup existGroup))
{
if (this != existGroup)
{
BlockGroup rootParent = existGroup.RootParent;
if (rootParent != this)
{
rootParent.SetParent(this);
}
}
}
else
{
inst2group[inst] = this;
}
}
}
private void UpdateInstructionGroup(BlockGroup parentGroup, Dictionary<Instruction, BlockGroup> inst2group)
{
foreach (var inst in instructions)
{
BlockGroup existGroup = inst2group[inst];
Assert.AreEqual(parentGroup, existGroup, "Instruction group parent should be the same as parent group");
inst2group[inst] = this;
}
SetParent(parentGroup);
}
public void SplitInstructionsNotInAnySubGroupsToIndividualGroups(Dictionary<Instruction, BlockGroup> inst2group)
{
if (subGroups == null || subGroups.Count == 0 || instructions.Count == 0)
{
return;
}
foreach (var subGroup in subGroups)
{
subGroup.SplitInstructionsNotInAnySubGroupsToIndividualGroups(inst2group);
}
var finalGroupList = new List<BlockGroup>();
var curGroupInstructions = new List<Instruction>();
var firstInst2SubGroup = subGroups.ToDictionary(g => g.instructions[0]);
foreach (var inst in instructions)
{
BlockGroup group = inst2group[inst];
if (group == this)
{
curGroupInstructions.Add(inst);
}
else
{
if (curGroupInstructions.Count > 0)
{
finalGroupList.Add(new BlockGroup(this, curGroupInstructions, inst2group));
curGroupInstructions = new List<Instruction>();
}
if (firstInst2SubGroup.TryGetValue(inst, out var subGroup))
{
finalGroupList.Add(subGroup);
}
}
}
if (curGroupInstructions.Count > 0)
{
finalGroupList.Add(new BlockGroup(this, curGroupInstructions, inst2group));
}
this.subGroups = finalGroupList;
}
public void ComputeBasicBlocks(Dictionary<Instruction, BasicBlockInfo> inst2bb, Func<Local> switchIndexLocalGetter)
{
if (subGroups == null || subGroups.Count == 0)
{
basicBlocks = new List<BasicBlockInfo>();
foreach (var inst in instructions)
{
BasicBlockInfo block = inst2bb[inst];
if (block.group != null)
{
if (block.group != this)
{
throw new Exception("BasicBlockInfo group should be the same as this BlockGroup");
}
}
else
{
block.group = this;
basicBlocks.Add(block);
}
}
switchMachineEntryInst = Instruction.Create(OpCodes.Ldloc, switchIndexLocalGetter());
switchMachineInst = Instruction.Create(OpCodes.Switch, new List<Instruction>());
switchMachineCases = new List<SwitchMachineCase>();
return;
}
foreach (var subGroup in subGroups)
{
subGroup.ComputeBasicBlocks(inst2bb, switchIndexLocalGetter);
}
}
}
private class TryBlockGroup : BlockGroup
{
public TryBlockGroup(List<Instruction> instructions, Dictionary<Instruction, BlockGroup> inst2group) : base(instructions, inst2group)
{
}
}
private class ExceptionHandlerGroup : BlockGroup
{
public readonly ExceptionHandler exceptionHandler;
public ExceptionHandlerGroup(ExceptionHandler exceptionHandler, List<Instruction> instructions, Dictionary<Instruction, BlockGroup> inst2group) : base(instructions, inst2group)
{
this.exceptionHandler = exceptionHandler;
}
}
private class ExceptionFilterGroup : BlockGroup
{
public readonly ExceptionHandler exceptionHandler;
public ExceptionFilterGroup(ExceptionHandler exceptionHandler, List<Instruction> instructions, Dictionary<Instruction, BlockGroup> inst2group) : base(instructions, inst2group)
{
this.exceptionHandler = exceptionHandler;
}
}
private class ExceptionHandlerWithFilterGroup : BlockGroup
{
public readonly ExceptionHandler exceptionHandler;
//public readonly ExceptionFilterGroup filterGroup;
//public readonly ExceptionHandlerGroup handlerGroup;
public ExceptionHandlerWithFilterGroup(ExceptionHandler exceptionHandler, List<Instruction> filterInstructions, List<Instruction> handlerInstructions, List<Instruction> allInstructions, Dictionary<Instruction, BlockGroup> inst2group) : base(allInstructions, inst2group)
{
this.exceptionHandler = exceptionHandler;
var filterGroup = new ExceptionFilterGroup(exceptionHandler, filterInstructions, inst2group);
var handlerGroup = new ExceptionHandlerGroup(exceptionHandler, handlerInstructions, inst2group);
}
}
class TryBlockInfo
{
public Instruction tryStart;
public Instruction tryEnd;
public TryBlockGroup blockGroup;
}
private Dictionary<Instruction, int> BuildInstruction2Index()
{
IList<Instruction> instructions = _method.Body.Instructions;
var inst2Index = new Dictionary<Instruction, int>(instructions.Count);
for (int i = 0; i < instructions.Count; i++)
{
Instruction inst = instructions[i];
inst2Index.Add(inst, i);
}
return inst2Index;
}
private BlockGroup SplitBasicBlockGroup()
{
Dictionary<Instruction, int> inst2Index = BuildInstruction2Index();
var inst2blockGroup = new Dictionary<Instruction, BlockGroup>();
List<Instruction> instructions = (List<Instruction>)_method.Body.Instructions;
var tryBlocks = new List<TryBlockInfo>();
foreach (var ex in _method.Body.ExceptionHandlers)
{
TryBlockInfo tryBlock = tryBlocks.Find(block => block.tryStart == ex.TryStart && block.tryEnd == ex.TryEnd);
if (tryBlock == null)
{
int startIndex = inst2Index[ex.TryStart];
int endIndex = ex.TryEnd != null ? inst2Index[ex.TryEnd] : inst2Index.Count;
TryBlockGroup blockGroup = new TryBlockGroup(instructions.GetRange(startIndex, endIndex - startIndex), inst2blockGroup);
tryBlock = new TryBlockInfo
{
tryStart = ex.TryStart,
tryEnd = ex.TryEnd,
blockGroup = blockGroup,
};
tryBlocks.Add(tryBlock);
}
if (ex.FilterStart != null)
{
int filterStartIndex = inst2Index[ex.FilterStart];
int filterEndIndex = ex.HandlerStart != null ? inst2Index[ex.HandlerStart] : inst2Index.Count;
int handlerStartIndex = filterEndIndex;
int handlerEndIndex = ex.HandlerEnd != null ? inst2Index[ex.HandlerEnd] : inst2Index.Count;
var filterHandlerGroup = new ExceptionHandlerWithFilterGroup(ex,
instructions.GetRange(filterStartIndex, filterEndIndex - filterStartIndex),
instructions.GetRange(handlerStartIndex, handlerEndIndex - handlerStartIndex),
instructions.GetRange(filterStartIndex, handlerEndIndex - filterStartIndex), inst2blockGroup);
}
else
{
int handlerStartIndex = inst2Index[ex.HandlerStart];
int handlerEndIndex = ex.HandlerEnd != null ? inst2Index[ex.HandlerEnd] : inst2Index.Count;
ExceptionHandlerGroup handlerGroup = new ExceptionHandlerGroup(ex, instructions.GetRange(handlerStartIndex, handlerEndIndex - handlerStartIndex), inst2blockGroup);
}
}
var rootGroup = new BlockGroup(new List<Instruction>(instructions), inst2blockGroup);
rootGroup.SplitInstructionsNotInAnySubGroupsToIndividualGroups(inst2blockGroup);
rootGroup.ComputeBasicBlocks(BuildInstructionToBasicBlockInfoDic(), () => GlobalSwitchIndexLocal);
return rootGroup;
}
private void FixInstructionTargets()
{
var inst2bb = BuildInstructionToBasicBlockInfoDic();
foreach (var ex in _method.Body.ExceptionHandlers)
{
if (ex.TryStart != null)
{
ex.TryStart = inst2bb[ex.TryStart].GroupFirstInstruction;
}
if (ex.TryEnd != null)
{
ex.TryEnd = inst2bb[ex.TryEnd].GroupFirstInstruction;
}
if (ex.HandlerStart != null)
{
ex.HandlerStart = inst2bb[ex.HandlerStart].GroupFirstInstruction;
}
if (ex.HandlerEnd != null)
{
ex.HandlerEnd = inst2bb[ex.HandlerEnd].GroupFirstInstruction;
}
if (ex.FilterStart != null)
{
ex.FilterStart = inst2bb[ex.FilterStart].GroupFirstInstruction;
}
}
//foreach (var inst in inst2bb.Keys)
//{
// if (inst.Operand is Instruction targetInst)
// {
// inst.Operand = inst2bb[targetInst].FirstInstruction;
// }
// else if (inst.Operand is Instruction[] targetInsts)
// {
// for (int i = 0; i < targetInsts.Length; i++)
// {
// targetInsts[i] = inst2bb[targetInsts[i]].FirstInstruction;
// }
// }
//}
}
private void BuildInstructions()
{
IList<Instruction> methodInstructions = _method.Body.Instructions;
methodInstructions.Clear();
for (BasicBlockInfo cur = _bbHead.next; cur != null; cur = cur.next)
{
foreach (Instruction inst in cur.instructions)
{
methodInstructions.Add(inst);
}
}
_method.Body.InitLocals = true;
//_method.Body.MaxStack = Math.Max(_method.Body.MaxStack , (ushort)1); // TODO: set to a reasonable value
//_method.Body.KeepOldMaxStack = true;
//_method.Body.UpdateInstructionOffsets();
}
public bool TryObfus()
{
// TODO: TEMP
//if (_method.Body.HasExceptionHandlers)
//{
// return false;
//}
if (_method.HasGenericParameters || _method.DeclaringType.HasGenericParameters)
{
return false;
}
var evc = new EvalStackCalculator(_method);
BuildBasicBlockLink(evc);
if (!CheckNotContainsNotSupportedEvalStackData())
{
Debug.LogError($"Method {_method.FullName} contains unsupported EvalStackData, obfuscation skipped.");
return false;
}
BlockGroup rootGroup = SplitBasicBlockGroup();
if (rootGroup.basicBlocks != null && rootGroup.basicBlocks.Count == 1)
{
return false;
}
ComputeInputOutputArguments();
AdjustInputOutputEvalStack();
InsertBrInstructionForConjoinedBasicBlocks();
InsertSwitchMachineBasicBlockForGroups(rootGroup);
FixInstructionTargets();
BuildInstructions();
return true;
}
}
}

View File

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

View File

@ -1,147 +0,0 @@
using dnlib.DotNet;
using Obfuz.Conf;
using Obfuz.Settings;
using Obfuz.Utils;
using System;
using System.Collections.Generic;
using System.Xml;
namespace Obfuz.ObfusPasses.EvalStackObfus
{
struct ObfuscationRuleData
{
public readonly ObfuscationLevel obfuscationLevel;
public readonly float obfuscationPercentage;
public ObfuscationRuleData(ObfuscationLevel level, float percentage)
{
obfuscationLevel = level;
obfuscationPercentage = percentage;
}
}
interface IObfuscationPolicy
{
bool NeedObfuscate(MethodDef method);
ObfuscationRuleData GetObfuscationRuleData(MethodDef method);
}
abstract class ObfuscationPolicyBase : IObfuscationPolicy
{
public abstract bool NeedObfuscate(MethodDef method);
public abstract ObfuscationRuleData GetObfuscationRuleData(MethodDef method);
}
class ConfigurableObfuscationPolicy : ObfuscationPolicyBase
{
class ObfuscationRule : IRule<ObfuscationRule>
{
public ObfuscationLevel? obfuscationLevel;
public float? obfuscationPercentage;
public void InheritParent(ObfuscationRule parentRule)
{
if (obfuscationLevel == null)
obfuscationLevel = parentRule.obfuscationLevel;
if (obfuscationPercentage == null)
obfuscationPercentage = parentRule.obfuscationPercentage;
}
}
class MethodSpec : MethodRuleBase<ObfuscationRule>
{
}
class TypeSpec : TypeRuleBase<MethodSpec, ObfuscationRule>
{
}
class AssemblySpec : AssemblyRuleBase<TypeSpec, MethodSpec, ObfuscationRule>
{
}
private static readonly ObfuscationRule s_default = new ObfuscationRule()
{
obfuscationLevel = ObfuscationLevel.Basic,
obfuscationPercentage = 0.05f,
};
private ObfuscationRule _global;
private readonly XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule> _xmlParser;
private readonly Dictionary<MethodDef, ObfuscationRule> _methodRuleCache = new Dictionary<MethodDef, ObfuscationRule>();
public ConfigurableObfuscationPolicy(List<string> toObfuscatedAssemblyNames, List<string> xmlConfigFiles)
{
_xmlParser = new XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule>(
toObfuscatedAssemblyNames, ParseObfuscationRule, ParseGlobal);
LoadConfigs(xmlConfigFiles);
}
private void LoadConfigs(List<string> configFiles)
{
_xmlParser.LoadConfigs(configFiles);
if (_global == null)
{
_global = s_default;
}
else
{
_global.InheritParent(s_default);
}
if (_global.obfuscationPercentage.Value > 0.1f)
{
UnityEngine.Debug.LogWarning($"EvalStackObfus significantly increases the size of the obfuscated hot-update DLL. It is recommended to keep the obfuscationPercentage ≤ 0.1 (currently set to {_global.obfuscationPercentage.Value}).");
}
_xmlParser.InheritParentRules(_global);
}
private void ParseGlobal(string configFile, XmlElement ele)
{
switch (ele.Name)
{
case "global": _global = ParseObfuscationRule(configFile, ele); break;
default: throw new Exception($"Invalid xml file {configFile}, unknown node {ele.Name}");
}
}
private ObfuscationRule ParseObfuscationRule(string configFile, XmlElement ele)
{
var rule = new ObfuscationRule();
if (ele.HasAttribute("obfuscationLevel"))
{
rule.obfuscationLevel = ConfigUtil.ParseObfuscationLevel(ele.GetAttribute("obfuscationLevel"));
}
if (ele.HasAttribute("obfuscationPercentage"))
{
rule.obfuscationPercentage = float.Parse(ele.GetAttribute("obfuscationPercentage"));
}
return rule;
}
private ObfuscationRule GetMethodObfuscationRule(MethodDef method)
{
if (!_methodRuleCache.TryGetValue(method, out var rule))
{
rule = _xmlParser.GetMethodRule(method, _global);
_methodRuleCache[method] = rule;
}
return rule;
}
public override bool NeedObfuscate(MethodDef method)
{
ObfuscationRule rule = GetMethodObfuscationRule(method);
return rule.obfuscationLevel.Value > ObfuscationLevel.None;
}
public override ObfuscationRuleData GetObfuscationRuleData(MethodDef method)
{
var rule = GetMethodObfuscationRule(method);
return new ObfuscationRuleData(rule.obfuscationLevel.Value, rule.obfuscationPercentage.Value);
}
}
}

View File

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

View File

@ -1,225 +0,0 @@
using dnlib.DotNet.Emit;
using Obfuz.Utils;
using System.Collections.Generic;
namespace Obfuz.ObfusPasses.EvalStackObfus
{
class DefaultObfuscator : ObfuscatorBase
{
public override bool ObfuscateInt(Instruction inst, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
IRandom random = ctx.localRandom;
switch (random.NextInt(4))
{
case 0:
{
// x = x + a
int a = 0;
float constProbability = 0f;
ConstObfusUtil.LoadConstInt(a, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
return true;
}
case 1:
{
// x = x * a * ra
int a = random.NextInt() | 0x1; // Ensure a is not zero
int ra = MathUtil.ModInverse32(a);
float constProbability = 0.5f;
ConstObfusUtil.LoadConstInt(a, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
ConstObfusUtil.LoadConstInt(ra, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
return true;
}
case 2:
{
// x = (x * a + b) * ra - (b * ra)
int a = random.NextInt() | 0x1; // Ensure a is not zero
int ra = MathUtil.ModInverse32(a);
int b = random.NextInt();
int b_ra = -b * ra;
float constProbability = 0.5f;
ConstObfusUtil.LoadConstInt(a, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
ConstObfusUtil.LoadConstInt(b, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
ConstObfusUtil.LoadConstInt(ra, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
ConstObfusUtil.LoadConstInt(b_ra, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
return true;
}
case 3:
{
// x = ((x + a) * b + c) * rb - (a*b + c) * rb
int a = random.NextInt();
int b = random.NextInt() | 0x1; // Ensure b is not zero
int rb = MathUtil.ModInverse32(b);
int c = random.NextInt();
int r = -(a * b + c) * rb;
float constProbability = 0.5f;
ConstObfusUtil.LoadConstInt(a, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
ConstObfusUtil.LoadConstInt(b, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
ConstObfusUtil.LoadConstInt(c, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
ConstObfusUtil.LoadConstInt(rb, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
ConstObfusUtil.LoadConstInt(r, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
return true;
}
default: return false;
}
}
public override bool ObfuscateLong(Instruction inst, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
IRandom random = ctx.localRandom;
switch (random.NextInt(4))
{
case 0:
{
// x = x + a
long a = 0;
float constProbability = 0f;
ConstObfusUtil.LoadConstLong(a, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
return true;
}
case 1:
{
// x = x * a * ra
long a = random.NextLong() | 0x1L; // Ensure a is not zero
long ra = MathUtil.ModInverse64(a);
float constProbability = 0.5f;
ConstObfusUtil.LoadConstLong(a, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
ConstObfusUtil.LoadConstLong(ra, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
return true;
}
case 2:
{
// x = (x * a + b) * ra - (b * ra)
long a = random.NextLong() | 0x1L; // Ensure a is not zero
long ra = MathUtil.ModInverse64(a);
long b = random.NextLong();
long b_ra = -b * ra;
float constProbability = 0.5f;
ConstObfusUtil.LoadConstLong(a, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
ConstObfusUtil.LoadConstLong(b, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
ConstObfusUtil.LoadConstLong(ra, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
ConstObfusUtil.LoadConstLong(b_ra, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
return true;
}
case 3:
{
// x = ((x + a) * b + c) * rb - (a*b + c) * rb
long a = random.NextLong();
long b = random.NextLong() | 0x1L; // Ensure b is not zero
long rb = MathUtil.ModInverse64(b);
long c = random.NextLong();
long r = -(a * b + c) * rb;
float constProbability = 0.5f;
ConstObfusUtil.LoadConstLong(a, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
ConstObfusUtil.LoadConstLong(b, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
ConstObfusUtil.LoadConstLong(c, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
ConstObfusUtil.LoadConstLong(rb, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
ConstObfusUtil.LoadConstLong(r, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
return true;
}
default: return false;
}
}
public override bool ObfuscateFloat(Instruction inst, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
IRandom random = ctx.localRandom;
switch (random.NextInt(3))
{
case 0:
{
// x = x + 0f
float a = 0.0f;
float constProbability = 0f;
ConstObfusUtil.LoadConstFloat(a, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
return true;
}
case 1:
{
// x = x * 1f;
float a = 1.0f;
float constProbability = 0f;
ConstObfusUtil.LoadConstFloat(a, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
return true;
}
case 2:
{
// x = (x + a) * b; a = 0.0f, b = 1.0f
float a = 0.0f;
float b = 1.0f;
float constProbability = 0f;
ConstObfusUtil.LoadConstFloat(a, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
ConstObfusUtil.LoadConstFloat(b, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
return true;
}
default: return false;
}
}
public override bool ObfuscateDouble(Instruction inst, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
IRandom random = ctx.localRandom;
switch (random.NextInt(3))
{
case 0:
{
// x = x + 0.0
double a = 0.0;
float constProbability = 0f;
ConstObfusUtil.LoadConstDouble(a, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
return true;
}
case 1:
{
// x = x * 1.0;
double a = 1.0;
float constProbability = 0f;
ConstObfusUtil.LoadConstDouble(a, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
return true;
}
case 2:
{
// x = (x + a) * b; a = 0.0, b = 1.0
double a = 0.0;
double b = 1.0;
float constProbability = 0f;
ConstObfusUtil.LoadConstDouble(a, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
ConstObfusUtil.LoadConstDouble(b, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
return true;
}
default: return false;
}
}
}
}

View File

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

View File

@ -1,114 +0,0 @@
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using Obfuz.Data;
using Obfuz.Emit;
using Obfuz.Settings;
using Obfuz.Utils;
using System.Collections.Generic;
namespace Obfuz.ObfusPasses.EvalStackObfus
{
class ObfusMethodContext
{
public MethodDef method;
public EvalStackCalculator evalStackCalculator;
public LocalVariableAllocator localVariableAllocator;
public IRandom localRandom;
public EncryptionScopeInfo encryptionScope;
public DefaultMetadataImporter importer;
public ConstFieldAllocator constFieldAllocator;
public float obfuscationPercentage;
}
internal class EvalStackObfusPass : ObfuscationMethodPassBase
{
private readonly EvalStackObfuscationSettingsFacade _settings;
private IObfuscationPolicy _obfuscationPolicy;
private IObfuscator _obfuscator;
public EvalStackObfusPass(EvalStackObfuscationSettingsFacade settings)
{
_settings = settings;
_obfuscator = new DefaultObfuscator();
}
public override ObfuscationPassType Type => ObfuscationPassType.EvalStackObfus;
public override void Start()
{
ObfuscationPassContext ctx = ObfuscationPassContext.Current;
_obfuscationPolicy = new ConfigurableObfuscationPolicy(
ctx.coreSettings.assembliesToObfuscate,
_settings.ruleFiles);
}
public override void Stop()
{
}
protected override bool NeedObfuscateMethod(MethodDef method)
{
return _obfuscationPolicy.NeedObfuscate(method);
}
protected bool TryObfuscateInstruction(Instruction inst, EvalDataType dataType, List<Instruction> outputInstructions, ObfusMethodContext ctx)
{
switch (dataType)
{
case EvalDataType.Int32: return _obfuscator.ObfuscateInt(inst, outputInstructions, ctx);
case EvalDataType.Int64: return _obfuscator.ObfuscateLong(inst, outputInstructions, ctx);
case EvalDataType.Float: return _obfuscator.ObfuscateFloat(inst, outputInstructions, ctx);
case EvalDataType.Double: return _obfuscator.ObfuscateDouble(inst, outputInstructions, ctx);
default: return false;
}
}
protected override void ObfuscateData(MethodDef method)
{
//Debug.Log($"Obfuscating method: {method.FullName} with EvalStackObfusPass");
IList<Instruction> instructions = method.Body.Instructions;
var outputInstructions = new List<Instruction>();
var totalFinalInstructions = new List<Instruction>();
ObfuscationPassContext ctx = ObfuscationPassContext.Current;
var calc = new EvalStackCalculator(method);
GroupByModuleEntityManager moduleEntityManager = ctx.moduleEntityManager;
var encryptionScope = moduleEntityManager.EncryptionScopeProvider.GetScope(method.Module);
var ruleData = _obfuscationPolicy.GetObfuscationRuleData(method);
var localRandom = encryptionScope.localRandomCreator(MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method));
var obfusMethodCtx = new ObfusMethodContext
{
method = method,
evalStackCalculator = calc,
localVariableAllocator = new LocalVariableAllocator(method),
encryptionScope = encryptionScope,
constFieldAllocator = moduleEntityManager.GetEntity<ConstFieldAllocator>(method.Module),
localRandom = localRandom,
importer = moduleEntityManager.GetEntity<DefaultMetadataImporter>(method.Module),
obfuscationPercentage = ruleData.obfuscationPercentage,
};
for (int i = 0; i < instructions.Count; i++)
{
Instruction inst = instructions[i];
totalFinalInstructions.Add(inst);
if (calc.TryGetPushResult(inst, out EvalDataType dataType) && localRandom.NextInPercentage(ruleData.obfuscationPercentage))
{
outputInstructions.Clear();
if (TryObfuscateInstruction(inst, dataType, outputInstructions, obfusMethodCtx))
{
totalFinalInstructions.AddRange(outputInstructions);
}
}
}
instructions.Clear();
foreach (var obInst in totalFinalInstructions)
{
instructions.Add(obInst);
}
}
}
}

View File

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

View File

@ -1,24 +0,0 @@
using dnlib.DotNet.Emit;
using System.Collections.Generic;
namespace Obfuz.ObfusPasses.EvalStackObfus
{
interface IObfuscator
{
bool ObfuscateInt(Instruction inst, List<Instruction> outputInsts, ObfusMethodContext ctx);
bool ObfuscateLong(Instruction inst, List<Instruction> outputInsts, ObfusMethodContext ctx);
bool ObfuscateFloat(Instruction inst, List<Instruction> outputInsts, ObfusMethodContext ctx);
bool ObfuscateDouble(Instruction inst, List<Instruction> outputInsts, ObfusMethodContext ctx);
}
abstract class ObfuscatorBase : IObfuscator
{
public abstract bool ObfuscateInt(Instruction inst, List<Instruction> outputInsts, ObfusMethodContext ctx);
public abstract bool ObfuscateLong(Instruction inst, List<Instruction> outputInsts, ObfusMethodContext ctx);
public abstract bool ObfuscateFloat(Instruction inst, List<Instruction> outputInsts, ObfusMethodContext ctx);
public abstract bool ObfuscateDouble(Instruction inst, List<Instruction> outputInsts, ObfusMethodContext ctx);
}
}

View File

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

View File

@ -1,143 +0,0 @@
using dnlib.DotNet;
using Obfuz.Conf;
using Obfuz.Settings;
using Obfuz.Utils;
using System;
using System.Collections.Generic;
using System.Xml;
namespace Obfuz.ObfusPasses.ExprObfus
{
struct ObfuscationRuleData
{
public readonly ObfuscationLevel obfuscationLevel;
public readonly float obfuscationPercentage;
public ObfuscationRuleData(ObfuscationLevel level, float percentage)
{
obfuscationLevel = level;
obfuscationPercentage = percentage;
}
}
interface IObfuscationPolicy
{
bool NeedObfuscate(MethodDef method);
ObfuscationRuleData GetObfuscationRuleData(MethodDef method);
}
abstract class ObfuscationPolicyBase : IObfuscationPolicy
{
public abstract bool NeedObfuscate(MethodDef method);
public abstract ObfuscationRuleData GetObfuscationRuleData(MethodDef method);
}
class ConfigurableObfuscationPolicy : ObfuscationPolicyBase
{
class ObfuscationRule : IRule<ObfuscationRule>
{
public ObfuscationLevel? obfuscationLevel;
public float? obfuscationPercentage;
public void InheritParent(ObfuscationRule parentRule)
{
if (obfuscationLevel == null)
obfuscationLevel = parentRule.obfuscationLevel;
if (obfuscationPercentage == null)
obfuscationPercentage = parentRule.obfuscationPercentage;
}
}
class MethodSpec : MethodRuleBase<ObfuscationRule>
{
}
class TypeSpec : TypeRuleBase<MethodSpec, ObfuscationRule>
{
}
class AssemblySpec : AssemblyRuleBase<TypeSpec, MethodSpec, ObfuscationRule>
{
}
private static readonly ObfuscationRule s_default = new ObfuscationRule()
{
obfuscationLevel = ObfuscationLevel.Basic,
obfuscationPercentage = 0.3f,
};
private ObfuscationRule _global;
private readonly XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule> _xmlParser;
private readonly Dictionary<MethodDef, ObfuscationRule> _methodRuleCache = new Dictionary<MethodDef, ObfuscationRule>();
public ConfigurableObfuscationPolicy(List<string> toObfuscatedAssemblyNames, List<string> xmlConfigFiles)
{
_xmlParser = new XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule>(
toObfuscatedAssemblyNames, ParseObfuscationRule, ParseGlobal);
LoadConfigs(xmlConfigFiles);
}
private void LoadConfigs(List<string> configFiles)
{
_xmlParser.LoadConfigs(configFiles);
if (_global == null)
{
_global = s_default;
}
else
{
_global.InheritParent(s_default);
}
_xmlParser.InheritParentRules(_global);
}
private void ParseGlobal(string configFile, XmlElement ele)
{
switch (ele.Name)
{
case "global": _global = ParseObfuscationRule(configFile, ele); break;
default: throw new Exception($"Invalid xml file {configFile}, unknown node {ele.Name}");
}
}
private ObfuscationRule ParseObfuscationRule(string configFile, XmlElement ele)
{
var rule = new ObfuscationRule();
if (ele.HasAttribute("obfuscationLevel"))
{
rule.obfuscationLevel = ConfigUtil.ParseObfuscationLevel(ele.GetAttribute("obfuscationLevel"));
}
if (ele.HasAttribute("obfuscationPercentage"))
{
rule.obfuscationPercentage = float.Parse(ele.GetAttribute("obfuscationPercentage"));
}
return rule;
}
private ObfuscationRule GetMethodObfuscationRule(MethodDef method)
{
if (!_methodRuleCache.TryGetValue(method, out var rule))
{
rule = _xmlParser.GetMethodRule(method, _global);
_methodRuleCache[method] = rule;
}
return rule;
}
public override bool NeedObfuscate(MethodDef method)
{
ObfuscationRule rule = GetMethodObfuscationRule(method);
return rule.obfuscationLevel.Value > ObfuscationLevel.None;
}
public override ObfuscationRuleData GetObfuscationRuleData(MethodDef method)
{
var rule = GetMethodObfuscationRule(method);
return new ObfuscationRuleData(rule.obfuscationLevel.Value, rule.obfuscationPercentage.Value);
}
}
}

View File

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

View File

@ -1,173 +0,0 @@
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using Obfuz.Data;
using Obfuz.Emit;
using Obfuz.ObfusPasses.ExprObfus.Obfuscators;
using Obfuz.Settings;
using Obfuz.Utils;
using System.Collections.Generic;
namespace Obfuz.ObfusPasses.ExprObfus
{
class ObfusMethodContext
{
public MethodDef method;
public EvalStackCalculator evalStackCalculator;
public LocalVariableAllocator localVariableAllocator;
public IRandom localRandom;
public EncryptionScopeInfo encryptionScope;
public DefaultMetadataImporter importer;
public ConstFieldAllocator constFieldAllocator;
public float obfuscationPercentage;
}
class ExprObfusPass : ObfuscationMethodPassBase
{
private readonly ExprObfuscationSettingsFacade _settings;
private readonly IObfuscator _basicObfuscator;
private readonly IObfuscator _advancedObfuscator;
private readonly IObfuscator _mostAdvancedObfuscator;
private IObfuscationPolicy _obfuscationPolicy;
public ExprObfusPass(ExprObfuscationSettingsFacade settings)
{
_settings = settings;
_basicObfuscator = new BasicObfuscator();
_advancedObfuscator = new AdvancedObfuscator();
_mostAdvancedObfuscator = new MostAdvancedObfuscator();
}
public override ObfuscationPassType Type => ObfuscationPassType.ExprObfus;
public override void Start()
{
ObfuscationPassContext ctx = ObfuscationPassContext.Current;
_obfuscationPolicy = new ConfigurableObfuscationPolicy(
ctx.coreSettings.assembliesToObfuscate,
_settings.ruleFiles);
}
private IObfuscator GetObfuscator(ObfuscationLevel level)
{
switch (level)
{
case ObfuscationLevel.None: return null;
case ObfuscationLevel.Basic: return _basicObfuscator;
case ObfuscationLevel.Advanced: return _advancedObfuscator;
case ObfuscationLevel.MostAdvanced: return _mostAdvancedObfuscator;
default: throw new System.ArgumentOutOfRangeException(nameof(level), level, "Unknown obfuscation level");
}
}
public override void Stop()
{
}
protected override bool NeedObfuscateMethod(MethodDef method)
{
return _obfuscationPolicy.NeedObfuscate(method);
}
protected bool TryObfuscateInstruction(IObfuscator obfuscator, InstructionParameterInfo pi, Instruction inst, List<Instruction> outputInstructions, ObfusMethodContext ctx)
{
//Debug.Log($"Obfuscating instruction: {inst} in method: {ctx.method.FullName}");
IRandom localRandom = ctx.localRandom;
float obfuscationPercentage = ctx.obfuscationPercentage;
switch (inst.OpCode.Code)
{
case Code.Neg:
{
return localRandom.NextInPercentage(obfuscationPercentage) && obfuscator.ObfuscateBasicUnaryOp(inst, pi.op1, pi.retType, outputInstructions, ctx);
}
case Code.Add:
case Code.Sub:
case Code.Mul:
case Code.Div:
case Code.Div_Un:
case Code.Rem:
case Code.Rem_Un:
{
return localRandom.NextInPercentage(obfuscationPercentage) && obfuscator.ObfuscateBasicBinOp(inst, pi.op1, pi.op2, pi.retType, outputInstructions, ctx);
}
case Code.And:
case Code.Or:
case Code.Xor:
{
return localRandom.NextInPercentage(obfuscationPercentage) && obfuscator.ObfuscateBinBitwiseOp(inst, pi.op1, pi.op2, pi.retType, outputInstructions, ctx);
}
case Code.Not:
{
return localRandom.NextInPercentage(obfuscationPercentage) && obfuscator.ObfuscateUnaryBitwiseOp(inst, pi.op1, pi.retType, outputInstructions, ctx);
}
case Code.Shl:
case Code.Shr:
case Code.Shr_Un:
{
return localRandom.NextInPercentage(obfuscationPercentage) && obfuscator.ObfuscateBitShiftOp(inst, pi.op1, pi.op2, pi.retType, outputInstructions, ctx);
}
}
return false;
}
protected override void ObfuscateData(MethodDef method)
{
//Debug.Log($"Obfuscating method: {method.FullName} with ExprObfusPass");
IList<Instruction> instructions = method.Body.Instructions;
var outputInstructions = new List<Instruction>();
var totalFinalInstructions = new List<Instruction>();
ObfuscationPassContext ctx = ObfuscationPassContext.Current;
var calc = new EvalStackCalculator(method);
GroupByModuleEntityManager moduleEntityManager = ctx.moduleEntityManager;
var encryptionScope = moduleEntityManager.EncryptionScopeProvider.GetScope(method.Module);
var ruleData = _obfuscationPolicy.GetObfuscationRuleData(method);
var obfuscator = GetObfuscator(ruleData.obfuscationLevel);
var obfusMethodCtx = new ObfusMethodContext
{
method = method,
evalStackCalculator = calc,
localVariableAllocator = new LocalVariableAllocator(method),
encryptionScope = encryptionScope,
constFieldAllocator = moduleEntityManager.GetEntity<ConstFieldAllocator>(method.Module),
localRandom = encryptionScope.localRandomCreator(MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method)),
importer = moduleEntityManager.GetEntity<DefaultMetadataImporter>(method.Module),
obfuscationPercentage = ruleData.obfuscationPercentage,
};
for (int i = 0; i < instructions.Count; i++)
{
Instruction inst = instructions[i];
bool add = false;
if (calc.TryGetParameterInfo(inst, out InstructionParameterInfo pi))
{
outputInstructions.Clear();
if (TryObfuscateInstruction(obfuscator, pi, inst, outputInstructions, obfusMethodCtx))
{
// current instruction may be the target of control flow instruction, so we can't remove it directly.
// we replace it with nop now, then remove it in CleanUpInstructionPass
inst.OpCode = outputInstructions[0].OpCode;
inst.Operand = outputInstructions[0].Operand;
totalFinalInstructions.Add(inst);
for (int k = 1; k < outputInstructions.Count; k++)
{
totalFinalInstructions.Add(outputInstructions[k]);
}
add = true;
}
}
if (!add)
{
totalFinalInstructions.Add(inst);
}
}
instructions.Clear();
foreach (var obInst in totalFinalInstructions)
{
instructions.Add(obInst);
}
}
}
}

View File

@ -1,28 +0,0 @@
using dnlib.DotNet.Emit;
using Obfuz.Emit;
using System.Collections.Generic;
namespace Obfuz.ObfusPasses.ExprObfus
{
interface IObfuscator
{
bool ObfuscateBasicUnaryOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx);
bool ObfuscateBasicBinOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx);
bool ObfuscateUnaryBitwiseOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx);
bool ObfuscateBinBitwiseOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx);
bool ObfuscateBitShiftOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx);
}
abstract class ObfuscatorBase : IObfuscator
{
public abstract bool ObfuscateBasicUnaryOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx);
public abstract bool ObfuscateBasicBinOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx);
public abstract bool ObfuscateUnaryBitwiseOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx);
public abstract bool ObfuscateBinBitwiseOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx);
public abstract bool ObfuscateBitShiftOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx);
}
}

View File

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

View File

@ -1,110 +0,0 @@
using dnlib.DotNet.Emit;
using Obfuz.Data;
using Obfuz.Emit;
using Obfuz.Utils;
using System.Collections.Generic;
namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators
{
class AdvancedObfuscator : BasicObfuscator
{
protected bool GenerateIdentityTransformForArgument(Instruction inst, EvalDataType op, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
IRandom random = ctx.localRandom;
ConstFieldAllocator constFieldAllocator = ctx.constFieldAllocator;
switch (op)
{
case EvalDataType.Int32:
{
// = x + y = x + (y * a + b) * ra + (-b * ra)
int a = random.NextInt() | 0x1;
int ra = MathUtil.ModInverse32(a);
int b = random.NextInt();
int b_ra = -b * ra;
float constProbability = 0.5f;
ConstObfusUtil.LoadConstInt(a, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
ConstObfusUtil.LoadConstInt(b, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
ConstObfusUtil.LoadConstInt(ra, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
ConstObfusUtil.LoadConstInt(b_ra, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
outputInsts.Add(inst.Clone());
return true;
}
case EvalDataType.Int64:
{
// = x + y = x + (y * a + b) * ra + (-b * ra)
long a = random.NextLong() | 0x1L;
long ra = MathUtil.ModInverse64(a);
long b = random.NextLong();
long b_ra = -b * ra;
float constProbability = 0.5f;
ConstObfusUtil.LoadConstLong(a, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
ConstObfusUtil.LoadConstLong(b, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
ConstObfusUtil.LoadConstLong(ra, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
ConstObfusUtil.LoadConstLong(b_ra, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
outputInsts.Add(inst.Clone());
return true;
}
case EvalDataType.Float:
{
// = x + y = x + (y + a) * b; a = 0.0f, b = 1.0f
float a = 0.0f;
float b = 1.0f;
float constProbability = 0f;
ConstObfusUtil.LoadConstFloat(a, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
ConstObfusUtil.LoadConstFloat(b, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
outputInsts.Add(inst.Clone());
return true;
}
case EvalDataType.Double:
{
// = x + y = x + (y + a) * b; a = 0.0, b = 1.0
double a = 0.0;
double b = 1.0;
float constProbability = 0f;
ConstObfusUtil.LoadConstDouble(a, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
ConstObfusUtil.LoadConstDouble(b, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
outputInsts.Add(inst.Clone());
return true;
}
default: return false;
}
}
public override bool ObfuscateBasicUnaryOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
return GenerateIdentityTransformForArgument(inst, op, outputInsts, ctx) || base.ObfuscateBasicUnaryOp(inst, op, ret, outputInsts, ctx);
}
public override bool ObfuscateBasicBinOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
return GenerateIdentityTransformForArgument(inst, op2, outputInsts, ctx) || base.ObfuscateBasicBinOp(inst, op1, op2, ret, outputInsts, ctx);
}
public override bool ObfuscateUnaryBitwiseOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
return GenerateIdentityTransformForArgument(inst, op, outputInsts, ctx) || base.ObfuscateUnaryBitwiseOp(inst, op, ret, outputInsts, ctx);
}
public override bool ObfuscateBinBitwiseOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
return GenerateIdentityTransformForArgument(inst, op2, outputInsts, ctx) || base.ObfuscateBinBitwiseOp(inst, op1, op2, ret, outputInsts, ctx);
}
public override bool ObfuscateBitShiftOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
return GenerateIdentityTransformForArgument(inst, op2, outputInsts, ctx) || base.ObfuscateBitShiftOp(inst, op1, op2, ret, outputInsts, ctx);
}
}
}

View File

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

View File

@ -1,282 +0,0 @@
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using Obfuz.Emit;
using System.Collections.Generic;
using UnityEngine;
namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators
{
class BasicObfuscator : ObfuscatorBase
{
private IMethod GetUnaryOpMethod(DefaultMetadataImporter importer, Code code, EvalDataType op1)
{
switch (code)
{
case Code.Neg:
{
switch (op1)
{
case EvalDataType.Int32: return importer.NegInt;
case EvalDataType.Int64: return importer.NegLong;
case EvalDataType.Float: return importer.NegFloat;
case EvalDataType.Double: return importer.NegDouble;
default: return null;
}
}
case Code.Not:
{
switch (op1)
{
case EvalDataType.Int32: return importer.NotInt;
case EvalDataType.Int64: return importer.NotLong;
default: return null;
}
}
default: return null;
}
}
private IMethod GetBinaryOpMethod(DefaultMetadataImporter importer, Code code, EvalDataType op1, EvalDataType op2)
{
switch (code)
{
case Code.Add:
{
switch (op1)
{
case EvalDataType.Int32: return op2 == op1 ? importer.AddInt : null;
case EvalDataType.Int64: return op2 == op1 ? importer.AddLong : null;
case EvalDataType.Float: return op2 == op1 ? importer.AddFloat : null;
case EvalDataType.Double: return op2 == op1 ? importer.AddDouble : null;
case EvalDataType.I:
{
switch (op2)
{
case EvalDataType.I: return importer.AddIntPtr;
case EvalDataType.Int32: return importer.AddIntPtrInt;
default: return null;
}
}
default: return null;
}
}
case Code.Sub:
{
switch (op1)
{
case EvalDataType.Int32: return op2 == op1 ? importer.SubtractInt : null;
case EvalDataType.Int64: return op2 == op1 ? importer.SubtractLong : null;
case EvalDataType.Float: return op2 == op1 ? importer.SubtractFloat : null;
case EvalDataType.Double: return op2 == op1 ? importer.SubtractDouble : null;
case EvalDataType.I:
{
switch (op2)
{
case EvalDataType.I: return importer.SubtractIntPtr;
case EvalDataType.Int32: return importer.SubtractIntPtrInt;
default: return null;
}
}
default: return null;
}
}
case Code.Mul:
{
switch (op1)
{
case EvalDataType.Int32: return op2 == op1 ? importer.MultiplyInt : null;
case EvalDataType.Int64: return op2 == op1 ? importer.MultiplyLong : null;
case EvalDataType.Float: return op2 == op1 ? importer.MultiplyFloat : null;
case EvalDataType.Double: return op2 == op1 ? importer.MultiplyDouble : null;
case EvalDataType.I:
{
switch (op2)
{
case EvalDataType.I: return importer.MultiplyIntPtr;
case EvalDataType.Int32: return importer.MultiplyIntPtrInt;
default: return null;
}
}
default: return null;
}
}
case Code.Div:
{
switch (op1)
{
case EvalDataType.Int32: return importer.DivideInt;
case EvalDataType.Int64: return importer.DivideLong;
case EvalDataType.Float: return importer.DivideFloat;
case EvalDataType.Double: return importer.DivideDouble;
default: return null;
}
}
case Code.Div_Un:
{
switch (op1)
{
case EvalDataType.Int32: return importer.DivideUnInt;
case EvalDataType.Int64: return importer.DivideUnLong;
default: return null;
}
}
case Code.Rem:
{
switch (op1)
{
case EvalDataType.Int32: return importer.RemInt;
case EvalDataType.Int64: return importer.RemLong;
case EvalDataType.Float: return importer.RemFloat;
case EvalDataType.Double: return importer.RemDouble;
default: return null;
}
}
case Code.Rem_Un:
{
switch (op1)
{
case EvalDataType.Int32: return importer.RemUnInt;
case EvalDataType.Int64: return importer.RemUnLong;
default: return null;
}
}
case Code.Neg:
{
switch (op1)
{
case EvalDataType.Int32: return importer.NegInt;
case EvalDataType.Int64: return importer.NegLong;
case EvalDataType.Float: return importer.NegFloat;
case EvalDataType.Double: return importer.NegDouble;
default: return null;
}
}
case Code.And:
{
switch (op1)
{
case EvalDataType.Int32: return importer.AndInt;
case EvalDataType.Int64: return importer.AndLong;
default: return null;
}
}
case Code.Or:
{
switch (op1)
{
case EvalDataType.Int32: return importer.OrInt;
case EvalDataType.Int64: return importer.OrLong;
default: return null;
}
}
case Code.Xor:
{
switch (op1)
{
case EvalDataType.Int32: return importer.XorInt;
case EvalDataType.Int64: return importer.XorLong;
default: return null;
}
}
case Code.Not:
{
switch (op1)
{
case EvalDataType.Int32: return importer.NotInt;
case EvalDataType.Int64: return importer.NotLong;
default: return null;
}
}
case Code.Shl:
{
switch (op1)
{
case EvalDataType.Int32: return importer.ShlInt;
case EvalDataType.Int64: return importer.ShlLong;
default: return null;
}
}
case Code.Shr:
{
switch (op1)
{
case EvalDataType.Int32: return importer.ShrInt;
case EvalDataType.Int64: return importer.ShrLong;
default: return null;
}
}
case Code.Shr_Un:
{
switch (op1)
{
case EvalDataType.Int32: return importer.ShrUnInt;
case EvalDataType.Int64: return importer.ShrUnLong;
default: return null;
}
}
default: return null;
}
}
public override bool ObfuscateBasicUnaryOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
IMethod opMethod = GetUnaryOpMethod(ctx.importer, inst.OpCode.Code, op);
if (opMethod == null)
{
Debug.LogWarning($"BasicObfuscator: Cannot obfuscate unary operation {inst.OpCode.Code} with different operand types: op={op}. This is a limitation of the BasicObfuscator.");
return false;
}
outputInsts.Add(Instruction.Create(OpCodes.Call, opMethod));
return true;
}
public override bool ObfuscateBasicBinOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
IMethod opMethod = GetBinaryOpMethod(ctx.importer, inst.OpCode.Code, op1, op2);
if (opMethod == null)
{
Debug.LogWarning($"BasicObfuscator: Cannot obfuscate binary operation {inst.OpCode.Code} with different operand types: op1={op1}, op2={op2}, ret={ret}. This is a limitation of the BasicObfuscator.");
return false;
}
outputInsts.Add(Instruction.Create(OpCodes.Call, opMethod));
return true;
}
public override bool ObfuscateUnaryBitwiseOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
IMethod opMethod = GetUnaryOpMethod(ctx.importer, inst.OpCode.Code, op);
if (opMethod == null)
{
Debug.LogWarning($"BasicObfuscator: Cannot obfuscate unary operation {inst.OpCode.Code} with different operand types: op={op}. This is a limitation of the BasicObfuscator.");
return false;
}
outputInsts.Add(Instruction.Create(OpCodes.Call, opMethod));
return true;
}
public override bool ObfuscateBinBitwiseOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
IMethod opMethod = GetBinaryOpMethod(ctx.importer, inst.OpCode.Code, op1, op2);
if (opMethod == null)
{
Debug.LogWarning($"BasicObfuscator: Cannot obfuscate binary operation {inst.OpCode.Code} with different operand types: op1={op1}, op2={op2}, ret={ret}. This is a limitation of the BasicObfuscator.");
return false;
}
outputInsts.Add(Instruction.Create(OpCodes.Call, opMethod));
return true;
}
public override bool ObfuscateBitShiftOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
IMethod opMethod = GetBinaryOpMethod(ctx.importer, inst.OpCode.Code, op1, op2);
if (opMethod == null)
{
Debug.LogWarning($"BasicObfuscator: Cannot obfuscate binary operation {inst.OpCode.Code} with operand type {op2}. This is a limitation of the BasicObfuscator.");
return false;
}
outputInsts.Add(Instruction.Create(OpCodes.Call, opMethod));
return true;
}
}
}

View File

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

View File

@ -1,83 +0,0 @@
using dnlib.DotNet.Emit;
using Obfuz.Emit;
using System.Collections.Generic;
using System.Linq;
namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators
{
class MostAdvancedObfuscator : AdvancedObfuscator
{
private readonly BasicObfuscator _basicObfuscator = new BasicObfuscator();
public override bool ObfuscateBasicUnaryOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
if (!base.ObfuscateBasicUnaryOp(inst, op, ret, outputInsts, ctx))
{
return false;
}
if (outputInsts.Last().OpCode.Code != inst.OpCode.Code)
{
return false;
}
outputInsts.RemoveAt(outputInsts.Count - 1);
return _basicObfuscator.ObfuscateBasicUnaryOp(inst, op, ret, outputInsts, ctx);
}
public override bool ObfuscateBasicBinOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
if (!base.ObfuscateBasicBinOp(inst, op1, op2, ret, outputInsts, ctx))
{
return false;
}
if (outputInsts.Last().OpCode.Code != inst.OpCode.Code)
{
return false;
}
outputInsts.RemoveAt(outputInsts.Count - 1);
return _basicObfuscator.ObfuscateBasicBinOp(inst, op1, op2, ret, outputInsts, ctx);
}
public override bool ObfuscateUnaryBitwiseOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
if (!base.ObfuscateUnaryBitwiseOp(inst, op, ret, outputInsts, ctx))
{
return false;
}
if (outputInsts.Last().OpCode.Code != inst.OpCode.Code)
{
return false;
}
outputInsts.RemoveAt(outputInsts.Count - 1);
return _basicObfuscator.ObfuscateUnaryBitwiseOp(inst, op, ret, outputInsts, ctx);
}
public override bool ObfuscateBinBitwiseOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
if (!base.ObfuscateBinBitwiseOp(inst, op1, op2, ret, outputInsts, ctx))
{
return false;
}
if (outputInsts.Last().OpCode.Code != inst.OpCode.Code)
{
return false;
}
outputInsts.RemoveAt(outputInsts.Count - 1);
return _basicObfuscator.ObfuscateBinBitwiseOp(inst, op1, op2, ret, outputInsts, ctx);
}
public override bool ObfuscateBitShiftOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
if (!base.ObfuscateBitShiftOp(inst, op1, op2, ret, outputInsts, ctx))
{
return false;
}
if (outputInsts.Last().OpCode.Code != inst.OpCode.Code)
{
return false;
}
outputInsts.RemoveAt(outputInsts.Count - 1);
return _basicObfuscator.ObfuscateBitShiftOp(inst, op1, op2, ret, outputInsts, ctx);
}
}
}

View File

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

View File

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

View File

@ -1,138 +0,0 @@
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using Obfuz.Editor;
using Obfuz.Emit;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine.Assertions;
namespace Obfuz.ObfusPasses.Instinct
{
public class InstinctPass : InstructionObfuscationPassBase
{
public override ObfuscationPassType Type => ObfuscationPassType.None;
protected override bool ForceProcessAllAssembliesAndIgnoreAllPolicy => true;
public InstinctPass()
{
}
public override void Start()
{
}
public override void Stop()
{
}
protected override bool NeedObfuscateMethod(MethodDef method)
{
return true;
}
private string GetTypeName(TypeSig type)
{
type = type.RemovePinnedAndModifiers();
switch (type.ElementType)
{
case ElementType.Class:
case ElementType.ValueType:
{
return type.ReflectionName;
}
case ElementType.GenericInst:
{
type = ((GenericInstSig)type).GenericType;
return type.ReflectionName;
}
default: return type.ReflectionName;
}
}
private string GetTypeFullName(TypeSig type)
{
type = type.RemovePinnedAndModifiers();
switch (type.ElementType)
{
case ElementType.Class:
case ElementType.ValueType:
{
return type.ReflectionFullName;
}
case ElementType.GenericInst:
{
GenericInstSig genericInstSig = (GenericInstSig)type;
var typeName = new StringBuilder(genericInstSig.GenericType.ReflectionFullName);
typeName.Append("<").Append(string.Join(",", genericInstSig.GenericArguments.Select(GetTypeFullName))).Append(">");
return typeName.ToString();
}
default: return type.ReflectionFullName;
}
}
protected override bool TryObfuscateInstruction(MethodDef callingMethod, Instruction inst, IList<Instruction> instructions, int instructionIndex, List<Instruction> outputInstructions, List<Instruction> totalFinalInstructions)
{
Code code = inst.OpCode.Code;
if (!(inst.Operand is IMethod method) || !method.IsMethod)
{
return false;
}
MethodDef methodDef = method.ResolveMethodDef();
if (methodDef == null || methodDef.DeclaringType.Name != "ObfuscationInstincts" || methodDef.DeclaringType.DefinitionAssembly.Name != ConstValues.ObfuzRuntimeAssemblyName)
{
return false;
}
ObfuscationPassContext ctx = ObfuscationPassContext.Current;
var importer = ctx.moduleEntityManager.GetEntity<DefaultMetadataImporter>(callingMethod.Module);
string methodName = methodDef.Name;
switch (methodName)
{
case "FullNameOf":
case "NameOf":
case "RegisterReflectionType":
{
MethodSpec methodSpec = (MethodSpec)method;
GenericInstMethodSig gims = methodSpec.GenericInstMethodSig;
Assert.AreEqual(1, gims.GenericArguments.Count, "FullNameOf should have exactly one generic argument");
TypeSig type = gims.GenericArguments[0];
switch (methodName)
{
case "FullNameOf":
{
string typeFullName = GetTypeFullName(type);
outputInstructions.Add(Instruction.Create(OpCodes.Ldstr, typeFullName));
break;
}
case "NameOf":
{
string typeName = GetTypeName(type);
outputInstructions.Add(Instruction.Create(OpCodes.Ldstr, typeName));
break;
}
case "RegisterReflectionType":
{
string typeFullName = GetTypeFullName(type);
outputInstructions.Add(Instruction.Create(OpCodes.Ldstr, typeFullName));
var finalMethod = new MethodSpecUser((IMethodDefOrRef)importer.ObfuscationTypeMapperRegisterType, gims);
outputInstructions.Add(Instruction.Create(OpCodes.Call, finalMethod));
break;
}
default: throw new NotSupportedException($"Unsupported instinct method: {methodDef.FullName}");
}
break;
}
default: throw new NotSupportedException($"Unsupported instinct method: {methodDef.FullName}");
}
//Debug.Log($"memory encrypt field: {field}");
return true;
}
}
}

View File

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

View File

@ -1,46 +0,0 @@
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using System.Collections.Generic;
namespace Obfuz.ObfusPasses
{
public abstract class InstructionObfuscationPassBase : ObfuscationMethodPassBase
{
protected abstract bool TryObfuscateInstruction(MethodDef callingMethod, Instruction inst, IList<Instruction> instructions, int instructionIndex,
List<Instruction> outputInstructions, List<Instruction> totalFinalInstructions);
protected override void ObfuscateData(MethodDef method)
{
IList<Instruction> instructions = method.Body.Instructions;
var outputInstructions = new List<Instruction>();
var totalFinalInstructions = new List<Instruction>();
for (int i = 0; i < instructions.Count; i++)
{
Instruction inst = instructions[i];
outputInstructions.Clear();
if (TryObfuscateInstruction(method, inst, instructions, i, outputInstructions, totalFinalInstructions))
{
// current instruction may be the target of control flow instruction, so we can't remove it directly.
// we replace it with nop now, then remove it in CleanUpInstructionPass
inst.OpCode = outputInstructions[0].OpCode;
inst.Operand = outputInstructions[0].Operand;
totalFinalInstructions.Add(inst);
for (int k = 1; k < outputInstructions.Count; k++)
{
totalFinalInstructions.Add(outputInstructions[k]);
}
}
else
{
totalFinalInstructions.Add(inst);
}
}
instructions.Clear();
foreach (var obInst in totalFinalInstructions)
{
instructions.Add(obInst);
}
}
}
}

View File

@ -1,47 +0,0 @@
using dnlib.DotNet;
using System.Linq;
namespace Obfuz.ObfusPasses
{
public abstract class ObfuscationMethodPassBase : ObfuscationPassBase
{
protected virtual bool ForceProcessAllAssembliesAndIgnoreAllPolicy => false;
protected abstract bool NeedObfuscateMethod(MethodDef method);
protected abstract void ObfuscateData(MethodDef method);
public override void Process()
{
var ctx = ObfuscationPassContext.Current;
var modules = ForceProcessAllAssembliesAndIgnoreAllPolicy ? ctx.allObfuscationRelativeModules : ctx.modulesToObfuscate;
ObfuscationMethodWhitelist whiteList = ctx.whiteList;
ConfigurablePassPolicy passPolicy = ctx.passPolicy;
foreach (ModuleDef mod in modules)
{
if (!ForceProcessAllAssembliesAndIgnoreAllPolicy && whiteList.IsInWhiteList(mod))
{
continue;
}
// ToArray to avoid modify list exception
foreach (TypeDef type in mod.GetTypes().ToArray())
{
if (!ForceProcessAllAssembliesAndIgnoreAllPolicy && whiteList.IsInWhiteList(type))
{
continue;
}
// ToArray to avoid modify list exception
foreach (MethodDef method in type.Methods.ToArray())
{
if (!method.HasBody || (!ForceProcessAllAssembliesAndIgnoreAllPolicy && (ctx.whiteList.IsInWhiteList(method) || !Support(passPolicy.GetMethodObfuscationPasses(method)) || !NeedObfuscateMethod(method))))
{
continue;
}
// TODO if isGeneratedBy Obfuscator, continue
ObfuscateData(method);
}
}
}
}
}
}

View File

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

View File

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

View File

@ -1,34 +0,0 @@
using dnlib.DotNet;
using Obfuz.Conf;
using System.Collections.Generic;
using System.Xml;
namespace Obfuz.ObfusPasses.RemoveConstField
{
public class ConfigurableRemoveConstFieldPolicy : RemoveConstFieldBase
{
class ObfuscationRule
{
}
private readonly XmlFieldRuleParser<ObfuscationRule> _configParser;
public ConfigurableRemoveConstFieldPolicy(List<string> toObfuscatedAssemblyNames, List<string> configFiles)
{
_configParser = new XmlFieldRuleParser<ObfuscationRule>(toObfuscatedAssemblyNames, ParseRule, null);
_configParser.LoadConfigs(configFiles);
}
private ObfuscationRule ParseRule(string configFile, XmlElement ele)
{
return new ObfuscationRule();
}
public override bool NeedPreserved(FieldDef field)
{
var rule = _configParser.GetFieldRule(field);
return rule != null;
}
}
}

View File

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

View File

@ -1,14 +0,0 @@
using dnlib.DotNet;
namespace Obfuz.ObfusPasses.RemoveConstField
{
public interface IRemoveConstFieldPolicy
{
bool NeedPreserved(FieldDef field);
}
public abstract class RemoveConstFieldBase : IRemoveConstFieldPolicy
{
public abstract bool NeedPreserved(FieldDef field);
}
}

View File

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

View File

@ -1,73 +0,0 @@
using dnlib.DotNet;
using Obfuz.Settings;
using Obfuz.Utils;
using System.Linq;
namespace Obfuz.ObfusPasses.RemoveConstField
{
public class RemoveConstFieldPass : ObfuscationPassBase
{
private RemoveConstFieldSettingsFacade _settings;
private ObfuzIgnoreScopeComputeCache _obfuzIgnoreScopeComputeCache;
private IRemoveConstFieldPolicy _removeConstFieldPolicy;
public override ObfuscationPassType Type => ObfuscationPassType.RemoveConstField;
public RemoveConstFieldPass(RemoveConstFieldSettingsFacade settings)
{
_settings = settings;
}
public override void Start()
{
var ctx = ObfuscationPassContext.Current;
_obfuzIgnoreScopeComputeCache = ctx.obfuzIgnoreScopeComputeCache;
_removeConstFieldPolicy = new ConfigurableRemoveConstFieldPolicy(ctx.coreSettings.assembliesToObfuscate, _settings.ruleFiles);
}
public override void Stop()
{
}
public override void Process()
{
var ctx = ObfuscationPassContext.Current;
var modules = ctx.modulesToObfuscate;
ConfigurablePassPolicy passPolicy = ctx.passPolicy;
foreach (ModuleDef mod in modules)
{
// ToArray to avoid modify list exception
foreach (TypeDef type in mod.GetTypes())
{
if (type.IsEnum)
{
continue;
}
foreach (FieldDef field in type.Fields.ToArray())
{
if (!field.IsLiteral)
{
continue;
}
if (!Support(passPolicy.GetFieldObfuscationPasses(field)))
{
continue;
}
if (_obfuzIgnoreScopeComputeCache.HasSelfOrDeclaringOrEnclosingOrInheritObfuzIgnoreScope(field, field.DeclaringType, ObfuzScope.Field))
{
continue;
}
if (_removeConstFieldPolicy.NeedPreserved(field))
{
continue;
}
field.DeclaringType = null;
//Debug.Log($"Remove const field {field.FullName} in type {type.FullName} in module {mod.Name}");
}
}
}
}
}
}

View File

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

View File

@ -1,29 +0,0 @@
namespace Obfuz.ObfusPasses.SymbolObfus.NameMakers
{
public class DebugNameMaker : NameMakerBase
{
private class DebugNameScope : INameScope
{
public bool AddPreservedName(string name)
{
return true;
}
public string GetNewName(string originalName, bool reuse)
{
return $"${originalName}";
}
public bool IsNamePreserved(string name)
{
return false;
}
}
protected override INameScope CreateNameScope()
{
return new DebugNameScope();
}
}
}

View File

@ -1,814 +0,0 @@
using dnlib.DotNet;
using Obfuz.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Obfuz.ObfusPasses.SymbolObfus.Policies
{
public class ConfigurableRenamePolicy : ObfuscationPolicyBase
{
enum ModifierType
{
None = 0x0,
Private = 0x1,
Protected = 0x2,
Public = 0x4,
}
class MethodRuleSpec
{
public NameMatcher nameMatcher;
public ModifierType? modifierType;
public bool? obfuscateName;
}
class FieldRuleSpec
{
public NameMatcher nameMatcher;
public ModifierType? modifierType;
public bool? obfuscateName;
}
class PropertyRuleSpec
{
public NameMatcher nameMatcher;
public ModifierType? modifierType;
public bool? obfuscateName;
public ObfuzScope? applyToMembers;
}
class EventRuleSpec
{
public NameMatcher nameMatcher;
public ModifierType? modifierType;
public bool? obfuscateName;
public ObfuzScope? applyToMembers;
}
class TypeRuleSpec
{
public NameMatcher nameMatcher;
public ModifierType? modifierType;
public ClassType? classType;
public List<string> inheritTypes;
public List<string> hasCustomAttributes;
public bool? obfuscateName;
public ObfuzScope? applyToMembers;
public bool applyToNestedTypes;
public List<FieldRuleSpec> fields;
public List<MethodRuleSpec> methods;
public List<PropertyRuleSpec> properties;
public List<EventRuleSpec> events;
}
class AssemblyRuleSpec
{
public string assemblyName;
public List<TypeRuleSpec> types;
}
private readonly Dictionary<string, List<AssemblyRuleSpec>> _assemblyRuleSpecs = new Dictionary<string, List<AssemblyRuleSpec>>();
private AssemblyRuleSpec ParseAssembly(XmlElement ele)
{
string assemblyName = ele.GetAttribute("name");
if (string.IsNullOrEmpty(assemblyName))
{
throw new Exception($"Invalid xml file, assembly name is empty");
}
if (!_obfuscationAssemblyNames.Contains(assemblyName))
{
throw new Exception($"unknown assembly name:{assemblyName}, not in ObfuzSettings.obfuscationAssemblyNames");
}
var rule = new AssemblyRuleSpec()
{
assemblyName = assemblyName,
types = new List<TypeRuleSpec>(),
};
foreach (XmlNode node in ele.ChildNodes)
{
if (!(node is XmlElement childElement))
{
continue;
}
if (childElement.Name != "type")
{
throw new Exception($"Invalid xml file, unknown node {childElement.Name}");
}
TypeRuleSpec type = ParseType(childElement);
rule.types.Add(type);
}
return rule;
}
private enum ClassType
{
None = 0x0,
Class = 0x1,
Struct = 0x2,
Interface = 0x4,
Enum = 0x8,
Delegate = 0x10,
}
private ClassType? ParseClassType(string classType)
{
if (string.IsNullOrEmpty(classType))
{
return null;
}
ClassType type = ClassType.None;
foreach (var s in classType.Split(','))
{
switch (s)
{
case "class": type |= ClassType.Class; break;
case "struct": type |= ClassType.Struct; break;
case "interface": type |= ClassType.Interface; break;
case "enum": type |= ClassType.Enum; break;
case "delegate": type |= ClassType.Delegate; break;
default: throw new Exception($"Invalid class type {s}");
}
}
return type;
}
private ModifierType? ParseModifierType(string modifierType)
{
if (string.IsNullOrEmpty(modifierType))
{
return null;
}
ModifierType type = ModifierType.None;
foreach (var s in modifierType.Split(','))
{
switch (s)
{
case "public": type |= ModifierType.Public; break;
case "protected": type |= ModifierType.Protected; break;
case "private": type |= ModifierType.Private; break;
default: throw new Exception($"Invalid modifier type {s}");
}
}
return type;
}
private ObfuzScope? ParseApplyToMembersScope(string membersScopeStr)
{
if (string.IsNullOrWhiteSpace(membersScopeStr))
{
return null;
}
ObfuzScope scope = ObfuzScope.None;
foreach (string s in membersScopeStr.Split(','))
{
var s2 = s.Trim().ToLowerInvariant();
switch (s2)
{
case "none": break;
case "field": scope |= ObfuzScope.Field; break;
case "eventname": scope |= ObfuzScope.EventName; break;
case "eventaddremovefirename": scope |= ObfuzScope.EventAddRemoveFireName; break;
case "event": scope |= ObfuzScope.Event; break;
case "methodname": scope |= ObfuzScope.MethodName; break;
case "method": scope |= ObfuzScope.MethodName; break;
case "propertyname": scope |= ObfuzScope.PropertyName; break;
case "propertygettersettername": scope |= ObfuzScope.PropertyGetterSetterName; break;
case "property": scope |= ObfuzScope.Property; break;
case "all":
case "*": scope |= ObfuzScope.All; break;
default:
{
throw new Exception($"Invalid applyToMembers scope {s2}");
}
}
}
return scope;
}
private List<string> ParseTypes(string inheritStr)
{
if (string.IsNullOrWhiteSpace(inheritStr))
{
return null;
}
var inheritTypes = new List<string>();
foreach (var s in inheritStr.Split(','))
{
var trimmed = s.Trim();
if (!string.IsNullOrEmpty(trimmed))
{
inheritTypes.Add(trimmed);
}
}
return inheritTypes;
}
private TypeRuleSpec ParseType(XmlElement element)
{
var rule = new TypeRuleSpec();
rule.nameMatcher = new NameMatcher(element.GetAttribute("name"));
rule.obfuscateName = ConfigUtil.ParseNullableBool(element.GetAttribute("obName"));
rule.applyToMembers = ParseApplyToMembersScope(element.GetAttribute("applyToMembers"));
rule.applyToNestedTypes = ConfigUtil.ParseNullableBool(element.GetAttribute("applyToNestedTypes")) ?? true;
rule.modifierType = ParseModifierType(element.GetAttribute("modifier"));
rule.classType = ParseClassType(element.GetAttribute("classType"));
rule.inheritTypes = ParseTypes(element.GetAttribute("inherit"));
rule.hasCustomAttributes = ParseTypes(element.GetAttribute("hasCustomAttributes"));
//rule.nestTypeRuleSpecs = new List<TypeRuleSpec>();
rule.fields = new List<FieldRuleSpec>();
rule.methods = new List<MethodRuleSpec>();
rule.properties = new List<PropertyRuleSpec>();
rule.events = new List<EventRuleSpec>();
foreach (XmlNode node in element.ChildNodes)
{
if (!(node is XmlElement childElement))
{
continue;
}
switch (childElement.Name)
{
case "field":
{
var fieldRuleSpec = new FieldRuleSpec();
fieldRuleSpec.nameMatcher = new NameMatcher(childElement.GetAttribute("name"));
fieldRuleSpec.modifierType = ParseModifierType(childElement.GetAttribute("modifier"));
fieldRuleSpec.obfuscateName = ConfigUtil.ParseNullableBool(childElement.GetAttribute("obName"));
rule.fields.Add(fieldRuleSpec);
break;
}
case "method":
{
var methodRuleSpec = new MethodRuleSpec();
methodRuleSpec.nameMatcher = new NameMatcher(childElement.GetAttribute("name"));
methodRuleSpec.modifierType = ParseModifierType(childElement.GetAttribute("modifier"));
methodRuleSpec.obfuscateName = ConfigUtil.ParseNullableBool(childElement.GetAttribute("obName"));
rule.methods.Add(methodRuleSpec);
break;
}
case "property":
{
var propertyRulerSpec = new PropertyRuleSpec();
propertyRulerSpec.nameMatcher = new NameMatcher(childElement.GetAttribute("name"));
propertyRulerSpec.modifierType = ParseModifierType(childElement.GetAttribute("modifier"));
propertyRulerSpec.obfuscateName = ConfigUtil.ParseNullableBool(childElement.GetAttribute("obName"));
propertyRulerSpec.applyToMembers = ParseApplyToMembersScope(childElement.GetAttribute("applyToMembers"));
rule.properties.Add(propertyRulerSpec);
break;
}
case "event":
{
var eventRuleSpec = new EventRuleSpec();
eventRuleSpec.nameMatcher = new NameMatcher(childElement.GetAttribute("name"));
eventRuleSpec.modifierType = ParseModifierType(childElement.GetAttribute("modifier"));
eventRuleSpec.obfuscateName = ConfigUtil.ParseNullableBool(childElement.GetAttribute("obName"));
eventRuleSpec.applyToMembers = ParseApplyToMembersScope(childElement.GetAttribute("applyToMembers"));
rule.events.Add(eventRuleSpec);
break;
}
default: throw new Exception($"Invalid xml file, unknown node {childElement.Name} in type node");
}
}
return rule;
}
private void LoadXmls(List<string> xmlFiles)
{
var rawAssemblySpecElements = new List<XmlElement>();
foreach (string file in xmlFiles)
{
LoadRawXml(file, rawAssemblySpecElements);
}
ResolveAssemblySpecs(rawAssemblySpecElements);
}
private void ResolveAssemblySpecs(List<XmlElement> rawAssemblySpecElements)
{
foreach (XmlElement ele in rawAssemblySpecElements)
{
var assemblyRule = ParseAssembly(ele);
if (!_assemblyRuleSpecs.TryGetValue(assemblyRule.assemblyName, out var existAssemblyRules))
{
existAssemblyRules = new List<AssemblyRuleSpec>();
_assemblyRuleSpecs.Add(assemblyRule.assemblyName, existAssemblyRules);
}
existAssemblyRules.Add(assemblyRule);
}
}
private void LoadRawXml(string xmlFile, List<XmlElement> rawAssemblyElements)
{
Debug.Log($"ObfuscateRule::LoadXml {xmlFile}");
var doc = new XmlDocument();
doc.Load(xmlFile);
var root = doc.DocumentElement;
if (root.Name != "obfuz")
{
throw new Exception($"Invalid xml file {xmlFile}, root name should be 'obfuz'");
}
foreach (XmlNode node in root.ChildNodes)
{
if (!(node is XmlElement element))
{
continue;
}
switch (element.Name)
{
case "assembly":
{
rawAssemblyElements.Add(element);
break;
}
default:
{
throw new Exception($"Invalid xml file {xmlFile}, unknown node {element.Name}");
}
}
}
}
private ModifierType ComputeModifierType(TypeAttributes visibility)
{
if (visibility == TypeAttributes.NotPublic || visibility == TypeAttributes.NestedPrivate)
{
return ModifierType.Private;
}
if (visibility == TypeAttributes.Public || visibility == TypeAttributes.NestedPublic)
{
return ModifierType.Public;
}
return ModifierType.Protected;
}
private ModifierType ComputeModifierType(FieldAttributes access)
{
if (access == FieldAttributes.Private || access == FieldAttributes.PrivateScope)
{
return ModifierType.Private;
}
if (access == FieldAttributes.Public)
{
return ModifierType.Public;
}
return ModifierType.Protected;
}
//private ModifierType ComputeModifierType(MethodAttributes access)
//{
// if (access == MethodAttributes.Private || access == MethodAttributes.PrivateScope)
// {
// return ModifierType.Private;
// }
// if (access == MethodAttributes.Public)
// {
// return ModifierType.Public;
// }
// return ModifierType.Protected;
//}
private bool MatchModifier(ModifierType? modifierType, TypeDef typeDef)
{
return modifierType == null || (modifierType & ComputeModifierType(typeDef.Visibility)) != 0;
}
private bool MatchModifier(ModifierType? modifierType, FieldDef fieldDef)
{
return modifierType == null || (modifierType & ComputeModifierType(fieldDef.Access)) != 0;
}
private bool MatchModifier(ModifierType? modifierType, MethodDef methodDef)
{
return modifierType == null || (modifierType & ComputeModifierType((FieldAttributes)methodDef.Access)) != 0;
}
private bool MatchModifier(ModifierType? modifierType, PropertyDef propertyDef)
{
FieldAttributes access = default;
if (propertyDef.GetMethod != null)
{
access |= (FieldAttributes)propertyDef.GetMethod.Access;
}
if (propertyDef.SetMethod != null)
{
access |= (FieldAttributes)propertyDef.SetMethod.Access;
}
return modifierType == null || (modifierType & ComputeModifierType(access)) != 0;
}
private bool MatchModifier(ModifierType? modifierType, EventDef eventDef)
{
FieldAttributes access = default;
if (eventDef.AddMethod != null)
{
access |= (FieldAttributes)eventDef.AddMethod.Access;
}
if (eventDef.RemoveMethod != null)
{
access |= (FieldAttributes)eventDef.RemoveMethod.Access;
}
if (eventDef.InvokeMethod != null)
{
access |= (FieldAttributes)eventDef.InvokeMethod.Access;
}
return modifierType == null || (modifierType & ComputeModifierType(access)) != 0;
}
private class MethodComputeCache
{
public bool obfuscateName = true;
public bool obfuscateParam = true;
public bool obfuscateBody = true;
}
private class RuleResult
{
public bool? obfuscateName;
}
private readonly Dictionary<TypeDef, RuleResult> _typeSpecCache = new Dictionary<TypeDef, RuleResult>();
private readonly Dictionary<MethodDef, RuleResult> _methodSpecCache = new Dictionary<MethodDef, RuleResult>();
private readonly Dictionary<FieldDef, RuleResult> _fieldSpecCache = new Dictionary<FieldDef, RuleResult>();
private readonly Dictionary<PropertyDef, RuleResult> _propertySpecCache = new Dictionary<PropertyDef, RuleResult>();
private readonly Dictionary<EventDef, RuleResult> _eventSpecCache = new Dictionary<EventDef, RuleResult>();
private readonly HashSet<string> _obfuscationAssemblyNames;
private readonly List<ModuleDef> _assembliesToObfuscate;
public ConfigurableRenamePolicy(List<string> obfuscationAssemblyNames, List<ModuleDef> assembliesToObfuscate, List<string> xmlFiles)
{
_obfuscationAssemblyNames = new HashSet<string>(obfuscationAssemblyNames);
_assembliesToObfuscate = assembliesToObfuscate;
LoadXmls(xmlFiles);
BuildRuleResultCaches();
}
private bool MatchClassType(ClassType? classType, TypeDef typeDef)
{
if (classType == null)
{
return true;
}
if (typeDef.IsInterface && (classType & ClassType.Interface) != 0)
{
return true;
}
if (typeDef.IsEnum && (classType & ClassType.Enum) != 0)
{
return true;
}
if (typeDef.IsDelegate && (classType & ClassType.Delegate) != 0)
{
return true;
}
if (typeDef.IsValueType && !typeDef.IsEnum && (classType & ClassType.Struct) != 0)
{
return true;
}
if (!typeDef.IsValueType && !typeDef.IsInterface && !typeDef.IsDelegate && (classType & ClassType.Class) != 0)
{
return true;
}
return false;
}
private RuleResult GetOrCreateTypeRuleResult(TypeDef typeDef)
{
if (!_typeSpecCache.TryGetValue(typeDef, out var ruleResult))
{
ruleResult = new RuleResult();
_typeSpecCache.Add(typeDef, ruleResult);
}
return ruleResult;
}
private RuleResult GetOrCreateFieldRuleResult(FieldDef field)
{
if (!_fieldSpecCache.TryGetValue(field, out var ruleResult))
{
ruleResult = new RuleResult();
_fieldSpecCache.Add(field, ruleResult);
}
return ruleResult;
}
private RuleResult GetOrCreateMethodRuleResult(MethodDef method)
{
if (!_methodSpecCache.TryGetValue(method, out var ruleResult))
{
ruleResult = new RuleResult();
_methodSpecCache.Add(method, ruleResult);
}
return ruleResult;
}
private RuleResult GetOrCreatePropertyRuleResult(PropertyDef property)
{
if (!_propertySpecCache.TryGetValue(property, out var ruleResult))
{
ruleResult = new RuleResult();
_propertySpecCache.Add(property, ruleResult);
}
return ruleResult;
}
private RuleResult GetOrCreateEventRuleResult(EventDef eventDef)
{
if (!_eventSpecCache.TryGetValue(eventDef, out var ruleResult))
{
ruleResult = new RuleResult();
_eventSpecCache.Add(eventDef, ruleResult);
}
return ruleResult;
}
private void BuildTypeRuleResult(TypeRuleSpec typeSpec, TypeDef typeDef, RuleResult typeRuleResult)
{
string typeName = typeDef.FullName;
if (typeSpec.obfuscateName != null)
{
typeRuleResult.obfuscateName = typeSpec.obfuscateName;
}
foreach (var fieldDef in typeDef.Fields)
{
RuleResult fieldRuleResult = GetOrCreateFieldRuleResult(fieldDef);
if (typeSpec.applyToMembers != null && (typeSpec.applyToMembers & ObfuzScope.Field) != 0 && typeSpec.obfuscateName != null)
{
fieldRuleResult.obfuscateName = typeSpec.obfuscateName;
}
foreach (var fieldSpec in typeSpec.fields)
{
if (fieldSpec.nameMatcher.IsMatch(fieldDef.Name) && MatchModifier(fieldSpec.modifierType, fieldDef))
{
if (fieldSpec.obfuscateName != null)
{
fieldRuleResult.obfuscateName = fieldSpec.obfuscateName;
}
}
}
}
foreach (MethodDef methodDef in typeDef.Methods)
{
RuleResult methodRuleResult = GetOrCreateMethodRuleResult(methodDef);
if (typeSpec.applyToMembers != null && (typeSpec.applyToMembers & ObfuzScope.Method) != 0 && typeSpec.obfuscateName != null)
{
methodRuleResult.obfuscateName = typeSpec.obfuscateName;
}
}
foreach (var eventDef in typeDef.Events)
{
RuleResult eventRuleResult = GetOrCreateEventRuleResult(eventDef);
if (typeSpec.applyToMembers != null && (typeSpec.applyToMembers & ObfuzScope.EventName) != 0 && typeSpec.obfuscateName != null)
{
eventRuleResult.obfuscateName = typeSpec.obfuscateName;
}
foreach (var eventSpec in typeSpec.events)
{
if (!eventSpec.nameMatcher.IsMatch(eventDef.Name) || !MatchModifier(eventSpec.modifierType, eventDef))
{
continue;
}
if (typeSpec.obfuscateName != null && typeSpec.applyToMembers != null && (typeSpec.applyToMembers & ObfuzScope.EventAddRemoveFireName) != 0)
{
if (eventDef.AddMethod != null)
{
GetOrCreateMethodRuleResult(eventDef.AddMethod).obfuscateName = typeSpec.obfuscateName;
}
if (eventDef.RemoveMethod != null)
{
GetOrCreateMethodRuleResult(eventDef.RemoveMethod).obfuscateName = typeSpec.obfuscateName;
}
if (eventDef.InvokeMethod != null)
{
GetOrCreateMethodRuleResult(eventDef.InvokeMethod).obfuscateName = typeSpec.obfuscateName;
}
}
if (eventSpec.obfuscateName != null)
{
eventRuleResult.obfuscateName = eventSpec.obfuscateName;
if (eventSpec.applyToMembers != null && (eventSpec.applyToMembers & ObfuzScope.EventAddRemoveFireName) != 0)
{
if (eventDef.AddMethod != null)
{
GetOrCreateMethodRuleResult(eventDef.AddMethod).obfuscateName = eventSpec.obfuscateName;
}
if (eventDef.RemoveMethod != null)
{
GetOrCreateMethodRuleResult(eventDef.RemoveMethod).obfuscateName = eventSpec.obfuscateName;
}
if (eventDef.InvokeMethod != null)
{
GetOrCreateMethodRuleResult(eventDef.InvokeMethod).obfuscateName = eventSpec.obfuscateName;
}
}
}
}
}
foreach (var propertyDef in typeDef.Properties)
{
RuleResult propertyRuleResult = GetOrCreatePropertyRuleResult(propertyDef);
if (typeSpec.applyToMembers != null && (typeSpec.applyToMembers & ObfuzScope.PropertyName) != 0 && typeSpec.obfuscateName != null)
{
propertyRuleResult.obfuscateName = typeSpec.obfuscateName;
}
foreach (var propertySpec in typeSpec.properties)
{
if (!propertySpec.nameMatcher.IsMatch(propertyDef.Name) || !MatchModifier(propertySpec.modifierType, propertyDef))
{
continue;
}
if (typeSpec.obfuscateName != null && typeSpec.applyToMembers != null && (typeSpec.applyToMembers & ObfuzScope.PropertyGetterSetterName) != 0)
{
if (propertyDef.GetMethod != null)
{
GetOrCreateMethodRuleResult(propertyDef.GetMethod).obfuscateName = typeSpec.obfuscateName;
}
if (propertyDef.SetMethod != null)
{
GetOrCreateMethodRuleResult(propertyDef.SetMethod).obfuscateName = typeSpec.obfuscateName;
}
}
if (propertySpec.obfuscateName != null)
{
propertyRuleResult.obfuscateName = propertySpec.obfuscateName;
if (propertySpec.applyToMembers != null && (propertySpec.applyToMembers & ObfuzScope.PropertyGetterSetterName) != 0)
{
if (propertyDef.GetMethod != null)
{
GetOrCreateMethodRuleResult(propertyDef.GetMethod).obfuscateName = propertySpec.obfuscateName;
}
if (propertyDef.SetMethod != null)
{
GetOrCreateMethodRuleResult(propertyDef.SetMethod).obfuscateName = propertySpec.obfuscateName;
}
}
}
}
}
foreach (MethodDef methodDef in typeDef.Methods)
{
RuleResult methodRuleResult = GetOrCreateMethodRuleResult(methodDef);
foreach (MethodRuleSpec methodSpec in typeSpec.methods)
{
if (!methodSpec.nameMatcher.IsMatch(methodDef.Name) || !MatchModifier(methodSpec.modifierType, methodDef))
{
continue;
}
if (methodSpec.obfuscateName != null)
{
methodRuleResult.obfuscateName = methodSpec.obfuscateName;
}
}
}
if (typeSpec.applyToNestedTypes)
{
foreach (TypeDef nestedType in typeDef.NestedTypes)
{
var nestedRuleResult = GetOrCreateTypeRuleResult(nestedType);
BuildTypeRuleResult(typeSpec, nestedType, nestedRuleResult);
}
}
}
private bool MatchInheritTypes(List<string> inheritTypes, TypeDef typeDef)
{
if (inheritTypes == null || inheritTypes.Count == 0)
{
return true;
}
TypeDef currentType = typeDef;
while (currentType != null)
{
if (inheritTypes.Contains(currentType.FullName))
{
return true;
}
foreach (var interfaceType in currentType.Interfaces)
{
if (inheritTypes.Contains(interfaceType.Interface.FullName))
{
return true;
}
}
currentType = MetaUtil.GetBaseTypeDef(currentType);
}
return false;
}
private bool MatchCustomAttributes(List<string> customAttributes, TypeDef typeDef)
{
if (customAttributes == null || customAttributes.Count == 0)
{
return true;
}
foreach (string customAttributeName in customAttributes)
{
if (typeDef.CustomAttributes.Find(customAttributeName) != null)
{
return true;
}
}
return false;
}
private IEnumerable<TypeDef> GetMatchTypes(ModuleDef mod, List<TypeDef> types, TypeRuleSpec typeSpec)
{
if (typeSpec.nameMatcher.IsWildcardPattern)
{
foreach (var typeDef in types)
{
if (!typeSpec.nameMatcher.IsMatch(typeDef.FullName)
|| !MatchModifier(typeSpec.modifierType, typeDef)
|| !MatchClassType(typeSpec.classType, typeDef)
|| !MatchInheritTypes(typeSpec.inheritTypes, typeDef)
|| !MatchCustomAttributes(typeSpec.hasCustomAttributes, typeDef))
{
continue;
}
yield return typeDef;
}
}
else
{
TypeDef typeDef = mod.FindNormal(typeSpec.nameMatcher.NameOrPattern);
if (typeDef != null
&& MatchModifier(typeSpec.modifierType, typeDef)
&& MatchClassType(typeSpec.classType, typeDef)
&& MatchInheritTypes(typeSpec.inheritTypes, typeDef)
&& MatchCustomAttributes(typeSpec.hasCustomAttributes, typeDef))
{
yield return typeDef;
}
}
}
private void BuildRuleResultCaches()
{
foreach (AssemblyRuleSpec assSpec in _assemblyRuleSpecs.Values.SelectMany(arr => arr))
{
ModuleDef module = _assembliesToObfuscate.FirstOrDefault(m => m.Assembly.Name == assSpec.assemblyName);
if (module == null)
{
continue;
}
List<TypeDef> types = module.GetTypes().ToList();
foreach (TypeRuleSpec typeSpec in assSpec.types)
{
foreach (var typeDef in GetMatchTypes(module, types, typeSpec))
{
var ruleResult = GetOrCreateTypeRuleResult(typeDef);
if (typeSpec.obfuscateName != null)
{
ruleResult.obfuscateName = typeSpec.obfuscateName;
}
BuildTypeRuleResult(typeSpec, typeDef, ruleResult);
}
}
}
}
public override bool NeedRename(TypeDef typeDef)
{
return GetOrCreateTypeRuleResult(typeDef).obfuscateName != false;
}
public override bool NeedRename(MethodDef methodDef)
{
return GetOrCreateMethodRuleResult(methodDef).obfuscateName != false;
}
public override bool NeedRename(FieldDef fieldDef)
{
return GetOrCreateFieldRuleResult(fieldDef).obfuscateName != false;
}
public override bool NeedRename(PropertyDef propertyDef)
{
return GetOrCreatePropertyRuleResult(propertyDef).obfuscateName != false;
}
public override bool NeedRename(EventDef eventDef)
{
return GetOrCreateEventRuleResult(eventDef).obfuscateName != false;
}
}
}

View File

@ -1,120 +0,0 @@
using dnlib.DotNet;
using Obfuz.Editor;
using Obfuz.Utils;
using System.Collections.Generic;
namespace Obfuz.ObfusPasses.SymbolObfus.Policies
{
public class SystemRenamePolicy : ObfuscationPolicyBase
{
private readonly ObfuzIgnoreScopeComputeCache _obfuzIgnoreScopeComputeCache;
public SystemRenamePolicy(ObfuzIgnoreScopeComputeCache obfuzIgnoreScopeComputeCache)
{
_obfuzIgnoreScopeComputeCache = obfuzIgnoreScopeComputeCache;
}
private readonly HashSet<string> _fullIgnoreTypeFullNames = new HashSet<string>
{
ConstValues.ObfuzIgnoreAttributeFullName,
ConstValues.ObfuzScopeFullName,
ConstValues.EncryptFieldAttributeFullName,
ConstValues.EmbeddedAttributeFullName,
ConstValues.ZluaLuaInvokeAttributeFullName,
ConstValues.ZluaLuaCallbackAttributeFullName,
ConstValues.ZluaLuaMarshalAsAttributeFullName,
ConstValues.BurstCompileFullName,
};
private readonly HashSet<string> _fullIgnoreTypeNames = new HashSet<string>
{
ConstValues.MonoPInvokeCallbackAttributeName,
};
private bool IsFullIgnoreObfuscatedType(TypeDef typeDef)
{
return _fullIgnoreTypeFullNames.Contains(typeDef.FullName) || _fullIgnoreTypeNames.Contains(typeDef.Name) || MetaUtil.HasMicrosoftCodeAnalysisEmbeddedAttribute(typeDef);
}
public override bool NeedRename(TypeDef typeDef)
{
string name = typeDef.Name;
if (name == "<Module>")
{
return false;
}
if (IsFullIgnoreObfuscatedType(typeDef))
{
return false;
}
if (_obfuzIgnoreScopeComputeCache.HasSelfOrEnclosingOrInheritObfuzIgnoreScope(typeDef, ObfuzScope.TypeName))
{
return false;
}
return true;
}
public override bool NeedRename(MethodDef methodDef)
{
if (methodDef.DeclaringType.IsDelegate || IsFullIgnoreObfuscatedType(methodDef.DeclaringType))
{
return false;
}
if (methodDef.Name == ".ctor" || methodDef.Name == ".cctor")
{
return false;
}
if (_obfuzIgnoreScopeComputeCache.HasSelfOrInheritPropertyOrEventOrOrTypeDefIgnoreMethodName(methodDef))
{
return false;
}
return true;
}
public override bool NeedRename(FieldDef fieldDef)
{
if (fieldDef.DeclaringType.IsDelegate || IsFullIgnoreObfuscatedType(fieldDef.DeclaringType))
{
return false;
}
if (_obfuzIgnoreScopeComputeCache.HasSelfOrDeclaringOrEnclosingOrInheritObfuzIgnoreScope(fieldDef, fieldDef.DeclaringType, ObfuzScope.Field))
{
return false;
}
if (fieldDef.DeclaringType.IsEnum && !fieldDef.IsStatic)
{
return false;
}
return true;
}
public override bool NeedRename(PropertyDef propertyDef)
{
if (propertyDef.DeclaringType.IsDelegate || IsFullIgnoreObfuscatedType(propertyDef.DeclaringType))
{
return false;
}
if (_obfuzIgnoreScopeComputeCache.HasSelfOrDeclaringOrEnclosingOrInheritObfuzIgnoreScope(propertyDef, propertyDef.DeclaringType, ObfuzScope.PropertyName))
{
return false;
}
return true;
}
public override bool NeedRename(EventDef eventDef)
{
if (eventDef.DeclaringType.IsDelegate || IsFullIgnoreObfuscatedType(eventDef.DeclaringType))
{
return false;
}
if (_obfuzIgnoreScopeComputeCache.HasSelfOrDeclaringOrEnclosingOrInheritObfuzIgnoreScope(eventDef, eventDef.DeclaringType, ObfuzScope.EventName))
{
return false;
}
return true;
}
}
}

View File

@ -1,264 +0,0 @@
using dnlib.DotNet;
using Obfuz.Utils;
using System.Collections.Generic;
using System.Linq;
namespace Obfuz.ObfusPasses.SymbolObfus.Policies
{
public class UnityRenamePolicy : ObfuscationPolicyBase
{
private static HashSet<string> s_monoBehaviourEvents = new HashSet<string> {
// MonoBehaviour events
"Awake",
"FixedUpdate",
"LateUpdate",
"OnAnimatorIK",
"OnAnimatorMove",
"OnApplicationFocus",
"OnApplicationPause",
"OnApplicationQuit",
"OnAudioFilterRead",
"OnBecameVisible",
"OnBecameInvisible",
"OnCollisionEnter",
"OnCollisionEnter2D",
"OnCollisionExit",
"OnCollisionExit2D",
"OnCollisionStay",
"OnCollisionStay2D",
"OnConnectedToServer",
"OnControllerColliderHit",
"OnDrawGizmos",
"OnDrawGizmosSelected",
"OnDestroy",
"OnDisable",
"OnDisconnectedFromServer",
"OnEnable",
"OnFailedToConnect",
"OnFailedToConnectToMasterServer",
"OnGUI",
"OnJointBreak",
"OnJointBreak2D",
"OnMasterServerEvent",
"OnMouseDown",
"OnMouseDrag",
"OnMouseEnter",
"OnMouseExit",
"OnMouseOver",
"OnMouseUp",
"OnMouseUpAsButton",
"OnNetworkInstantiate",
"OnParticleSystemStopped",
"OnParticleTrigger",
"OnParticleUpdateJobScheduled",
"OnPlayerConnected",
"OnPlayerDisconnected",
"OnPostRender",
"OnPreCull",
"OnPreRender",
"OnRenderImage",
"OnRenderObject",
"OnSerializeNetworkView",
"OnServerInitialized",
"OnTransformChildrenChanged",
"OnTransformParentChanged",
"OnTriggerEnter",
"OnTriggerEnter2D",
"OnTriggerExit",
"OnTriggerExit2D",
"OnTriggerStay",
"OnTriggerStay2D",
"OnValidate",
"OnWillRenderObject",
"Reset",
"Start",
"Update",
// Animator/StateMachineBehaviour
"OnStateEnter",
"OnStateExit",
"OnStateMove",
"OnStateUpdate",
"OnStateIK",
"OnStateMachineEnter",
"OnStateMachineExit",
// ParticleSystem
"OnParticleTrigger",
"OnParticleCollision",
"OnParticleSystemStopped",
// UGUI/EventSystems
"OnPointerClick",
"OnPointerDown",
"OnPointerUp",
"OnPointerEnter",
"OnPointerExit",
"OnDrag",
"OnBeginDrag",
"OnEndDrag",
"OnDrop",
"OnScroll",
"OnSelect",
"OnDeselect",
"OnMove",
"OnSubmit",
"OnCancel",
};
private readonly CachedDictionary<TypeDef, bool> _computeDeclaringTypeDisableAllMemberRenamingCache;
private readonly CachedDictionary<TypeDef, bool> _isSerializableCache;
private readonly CachedDictionary<TypeDef, bool> _isInheritFromMonoBehaviourCache;
private readonly CachedDictionary<TypeDef, bool> _isScriptOrSerializableTypeCache;
public UnityRenamePolicy()
{
_computeDeclaringTypeDisableAllMemberRenamingCache = new CachedDictionary<TypeDef, bool>(ComputeDeclaringTypeDisableAllMemberRenaming);
_isSerializableCache = new CachedDictionary<TypeDef, bool>(MetaUtil.IsSerializableType);
_isInheritFromMonoBehaviourCache = new CachedDictionary<TypeDef, bool>(MetaUtil.IsInheritFromMonoBehaviour);
_isScriptOrSerializableTypeCache = new CachedDictionary<TypeDef, bool>(MetaUtil.IsScriptOrSerializableType);
}
private bool IsUnitySourceGeneratedAssemblyType(TypeDef typeDef)
{
if (typeDef.Name.StartsWith("UnitySourceGeneratedAssemblyMonoScriptTypes_"))
{
return true;
}
if (typeDef.FullName == "Unity.Entities.CodeGeneratedRegistry.AssemblyTypeRegistry")
{
return true;
}
if (typeDef.Name.StartsWith("__JobReflectionRegistrationOutput"))
{
return true;
}
if (MetaUtil.HasDOTSCompilerGeneratedAttribute(typeDef))
{
return true;
}
if (typeDef.DeclaringType != null)
{
return IsUnitySourceGeneratedAssemblyType(typeDef.DeclaringType);
}
return false;
}
private bool ComputeDeclaringTypeDisableAllMemberRenaming(TypeDef typeDef)
{
if (typeDef.IsEnum && MetaUtil.HasBlackboardEnumAttribute(typeDef))
{
return true;
}
if (IsUnitySourceGeneratedAssemblyType(typeDef))
{
return true;
}
if (MetaUtil.IsInheritFromDOTSTypes(typeDef))
{
return true;
}
return false;
}
public override bool NeedRename(TypeDef typeDef)
{
if (_isScriptOrSerializableTypeCache.GetValue(typeDef))
{
return false;
}
if (_computeDeclaringTypeDisableAllMemberRenamingCache.GetValue(typeDef))
{
return false;
}
if (MetaUtil.HasBurstCompileAttribute(typeDef))
{
return false;
}
if (typeDef.Methods.Any(m => MetaUtil.HasRuntimeInitializeOnLoadMethodAttribute(m)))
{
return false;
}
return true;
}
public override bool NeedRename(MethodDef methodDef)
{
TypeDef typeDef = methodDef.DeclaringType;
if (s_monoBehaviourEvents.Contains(methodDef.Name) && _isInheritFromMonoBehaviourCache.GetValue(typeDef))
{
return false;
}
if (_computeDeclaringTypeDisableAllMemberRenamingCache.GetValue(typeDef))
{
return false;
}
if (MetaUtil.HasRuntimeInitializeOnLoadMethodAttribute(methodDef))
{
return false;
}
if (MetaUtil.HasBurstCompileAttribute(methodDef) || MetaUtil.HasBurstCompileAttribute(methodDef.DeclaringType) || MetaUtil.HasDOTSCompilerGeneratedAttribute(methodDef))
{
return false;
}
return true;
}
public override bool NeedRename(FieldDef fieldDef)
{
TypeDef typeDef = fieldDef.DeclaringType;
if (_isScriptOrSerializableTypeCache.GetValue(typeDef))
{
if (typeDef.IsEnum)
{
return false;
}
if (fieldDef.IsPublic && !fieldDef.IsStatic)
{
return false;
}
if (!fieldDef.IsStatic && MetaUtil.IsSerializableField(fieldDef))
{
return false;
}
}
if (_computeDeclaringTypeDisableAllMemberRenamingCache.GetValue(typeDef))
{
return false;
}
return true;
}
public override bool NeedRename(PropertyDef propertyDef)
{
TypeDef typeDef = propertyDef.DeclaringType;
if (_isSerializableCache.GetValue(typeDef))
{
bool isGetterPublic = propertyDef.GetMethod != null && propertyDef.GetMethod.IsPublic && !propertyDef.GetMethod.IsStatic;
bool isSetterPublic = propertyDef.SetMethod != null && propertyDef.SetMethod.IsPublic && !propertyDef.SetMethod.IsStatic;
if (isGetterPublic || isSetterPublic)
{
return false;
}
}
return true;
}
}
}

View File

@ -1,42 +0,0 @@
using dnlib.DotNet;
using Obfuz.Settings;
using Obfuz.Utils;
using System.Collections.Generic;
using System.Threading;
namespace Obfuz.ObfusPasses.SymbolObfus
{
public class ReflectionCompatibilityDetectionPass : ObfuscationPassBase
{
private readonly SymbolObfuscationSettingsFacade _settings;
public override ObfuscationPassType Type => ObfuscationPassType.SymbolObfus;
public ReflectionCompatibilityDetectionPass(SymbolObfuscationSettingsFacade settings)
{
_settings = settings;
}
public override void Start()
{
}
public override void Stop()
{
}
public override void Process()
{
var ctx = ObfuscationPassContext.Current;
var assemblyCache = ctx.assemblyCache;
var toObfuscatedModules = ctx.modulesToObfuscate;
var obfuscatedAndNotObfuscatedModules = ctx.allObfuscationRelativeModules;
var toObfuscatedModuleSet = new HashSet<ModuleDef>(ctx.modulesToObfuscate);
var renamePolicy = SymbolRename.CreateDefaultRenamePolicy(_settings.ruleFiles, _settings.customRenamePolicyTypes);
var reflectionCompatibilityDetector = new ReflectionCompatibilityDetector(ctx.modulesToObfuscate, ctx.allObfuscationRelativeModules, renamePolicy);
reflectionCompatibilityDetector.Analyze();
}
}
}

View File

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

View File

@ -1,314 +0,0 @@
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Obfuz.ObfusPasses.SymbolObfus
{
public class ReflectionCompatibilityDetector
{
private readonly HashSet<ModuleDef> _assembliesToObfuscate;
private readonly List<ModuleDef> _obfuscatedAndNotObfuscatedModules;
private readonly IObfuscationPolicy _renamePolicy;
public ReflectionCompatibilityDetector(List<ModuleDef> assembliesToObfuscate, List<ModuleDef> obfuscatedAndNotObfuscatedModules, IObfuscationPolicy renamePolicy)
{
_assembliesToObfuscate = new HashSet<ModuleDef>(assembliesToObfuscate);
_obfuscatedAndNotObfuscatedModules = obfuscatedAndNotObfuscatedModules;
_renamePolicy = renamePolicy;
}
public void Analyze()
{
foreach (ModuleDef mod in _obfuscatedAndNotObfuscatedModules)
{
foreach (TypeDef type in mod.GetTypes())
{
foreach (MethodDef method in type.Methods)
{
AnalyzeMethod(method);
}
}
}
}
private MethodDef _curCallingMethod;
private IList<Instruction> _curInstructions;
private int _curInstIndex;
private void AnalyzeMethod(MethodDef method)
{
if (!method.HasBody)
{
return;
}
_curCallingMethod = method;
_curInstructions = method.Body.Instructions;
_curInstIndex = 0;
for (int n = _curInstructions.Count; _curInstIndex < n; _curInstIndex++)
{
var inst = _curInstructions[_curInstIndex];
switch (inst.OpCode.Code)
{
case Code.Call:
{
AnalyzeCall(inst.Operand as IMethod);
break;
}
case Code.Callvirt:
{
ITypeDefOrRef constrainedType = null;
if (_curInstIndex > 0)
{
var prevInst = _curInstructions[_curInstIndex - 1];
if (prevInst.OpCode.Code == Code.Constrained)
{
constrainedType = prevInst.Operand as ITypeDefOrRef;
}
}
AnalyzeCallvir(inst.Operand as IMethod, constrainedType);
break;
}
}
}
}
private ITypeDefOrRef FindLatestTypeOf(int backwardFindInstructionCount)
{
// find sequence ldtoken <type>;
for (int i = 2; i <= backwardFindInstructionCount; i++)
{
int index = _curInstIndex - i;
if (index < 0)
{
return null;
}
Instruction inst1 = _curInstructions[index];
Instruction inst2 = _curInstructions[index + 1];
if (inst1.OpCode.Code == Code.Ldtoken && inst2.OpCode.Code == Code.Call)
{
if (!(inst1.Operand is ITypeDefOrRef typeDefOrRef))
{
continue;
}
IMethod method = inst2.Operand as IMethod;
if (method.Name == "GetTypeFromHandle" && method.DeclaringType.FullName == "System.Type")
{
// Ldtoken <type>; Call System.Type.GetTypeFromHandle(System.RuntimeTypeHandle handle)
return typeDefOrRef;
}
}
}
return null;
}
private void AnalyzeCall(IMethod calledMethod)
{
TypeDef callType = calledMethod.DeclaringType.ResolveTypeDef();
if (callType == null)
{
return;
}
switch (callType.FullName)
{
case "System.Enum":
{
AnalyzeEnum(calledMethod, callType);
break;
}
case "System.Type":
{
AnalyzeGetType(calledMethod, callType);
break;
}
case "System.Reflection.Assembly":
{
if (calledMethod.Name == "GetType")
{
AnalyzeGetType(calledMethod, callType);
}
break;
}
}
}
private bool IsAnyEnumItemRenamed(TypeDef typeDef)
{
return _assembliesToObfuscate.Contains(typeDef.Module) && typeDef.Fields.Any(f => _renamePolicy.NeedRename(f));
}
private void AnalyzeCallvir(IMethod calledMethod, ITypeDefOrRef constrainedType)
{
TypeDef callType = calledMethod.DeclaringType.ResolveTypeDef();
if (callType == null)
{
return;
}
string calledMethodName = calledMethod.Name;
switch (callType.FullName)
{
case "System.Object":
{
if (calledMethodName == "ToString")
{
if (constrainedType != null)
{
TypeDef enumTypeDef = constrainedType.ResolveTypeDef();
if (enumTypeDef != null && enumTypeDef.IsEnum && IsAnyEnumItemRenamed(enumTypeDef))
{
Debug.LogError($"[ReflectionCompatibilityDetector] Reflection compatibility issue in {_curCallingMethod}: {enumTypeDef.FullName}.ToString() the enum members are renamed.");
}
}
}
break;
}
case "System.Type":
{
AnalyzeGetType(calledMethod, callType);
break;
}
}
}
private TypeSig GetMethodGenericParameter(IMethod method)
{
if (method is MethodSpec ms)
{
return ms.GenericInstMethodSig.GenericArguments.FirstOrDefault();
}
else
{
return null;
}
}
private void AnalyzeEnum(IMethod method, TypeDef typeDef)
{
const int extraSearchInstructionCount = 3;
TypeSig parseTypeSig = GetMethodGenericParameter(method);
TypeDef parseType = parseTypeSig?.ToTypeDefOrRef().ResolveTypeDef();
switch (method.Name)
{
case "Parse":
{
if (parseTypeSig != null)
{
// Enum.Parse<T>(string name) or Enum.Parse<T>(string name, bool caseInsensitive)
if (parseType != null)
{
if (IsAnyEnumItemRenamed(parseType))
{
Debug.LogError($"[ReflectionCompatibilityDetector] Reflection compatibility issue in {_curCallingMethod}: Enum.Parse<T> field of T:{parseType.FullName} is renamed.");
}
}
else
{
Debug.LogWarning($"[ReflectionCompatibilityDetector] Reflection compatibility issue in {_curCallingMethod}: Enum.Parse<T> field of T should not be renamed.");
}
}
else
{
// Enum.Parse(Type type, string name) or Enum.Parse(Type type, string name, bool ignoreCase)
TypeDef enumType = FindLatestTypeOf(method.GetParamCount() + extraSearchInstructionCount)?.ResolveTypeDef();
if (enumType != null && enumType.IsEnum && IsAnyEnumItemRenamed(enumType))
{
Debug.LogError($"[ReflectionCompatibilityDetector] Reflection compatibility issue in {_curCallingMethod}: Enum.Parse field of argument type:{enumType.FullName} is renamed.");
}
else
{
Debug.LogWarning($"[ReflectionCompatibilityDetector] Reflection compatibility issue in {_curCallingMethod}: Enum.Parse field of argument `type` should not be renamed.");
}
}
break;
}
case "TryParse":
{
if (parseTypeSig != null)
{
// Enum.TryParse<T>(string name, out T result) or Enum.TryParse<T>(string name, bool ignoreCase, out T result)
if (parseType != null)
{
if (IsAnyEnumItemRenamed(parseType))
{
Debug.LogError($"[ReflectionCompatibilityDetector] Reflection compatibility issue in {_curCallingMethod}: Enum.TryParse<T> field of T:{parseType.FullName} is renamed.");
}
}
else
{
Debug.LogWarning($"[ReflectionCompatibilityDetector] Reflection compatibility issue in {_curCallingMethod}: Enum.TryParse<T> field of T should not be renamed.");
}
}
else
{
TypeDef enumType = FindLatestTypeOf(method.GetParamCount() + extraSearchInstructionCount)?.ResolveTypeDef();
if (enumType != null && enumType.IsEnum && IsAnyEnumItemRenamed(enumType))
{
Debug.LogError($"[ReflectionCompatibilityDetector] Reflection compatibility issue in {_curCallingMethod}: Enum.TryParse field of argument type:{enumType.FullName} is renamed.");
}
else
{
Debug.LogWarning($"[ReflectionCompatibilityDetector] Reflection compatibility issue in {_curCallingMethod}: Enum.TryParse field of argument `type` should not be renamed.");
}
}
break;
}
case "GetName":
{
// Enum.GetName(Type type, object value)
TypeDef enumType = FindLatestTypeOf(method.GetParamCount() + extraSearchInstructionCount)?.ResolveTypeDef();
if (enumType != null && enumType.IsEnum && IsAnyEnumItemRenamed(enumType))
{
Debug.LogError($"[ReflectionCompatibilityDetector] Reflection compatibility issue in {_curCallingMethod}: Enum.GetName field of type:{enumType.FullName} is renamed.");
}
else
{
Debug.LogWarning($"[ReflectionCompatibilityDetector] Reflection compatibility issue in {_curCallingMethod}: Enum.GetName field of argument `type` should not be renamed.");
}
break;
}
case "GetNames":
{
// Enum.GetNames(Type type)
TypeDef enumType = FindLatestTypeOf(method.GetParamCount() + extraSearchInstructionCount)?.ResolveTypeDef();
if (enumType != null && enumType.IsEnum && IsAnyEnumItemRenamed(enumType))
{
Debug.LogError($"[ReflectionCompatibilityDetector] Reflection compatibility issue in {_curCallingMethod}: Enum.GetNames field of type:{enumType.FullName} is renamed.");
}
else
{
Debug.LogWarning($"[ReflectionCompatibilityDetector] Reflection compatibility issue in {_curCallingMethod}: Enum.GetNames field of argument `type` should not be renamed.");
}
break;
}
}
}
private void AnalyzeGetType(IMethod method, TypeDef declaringType)
{
switch (method.Name)
{
case "GetType":
{
Debug.LogWarning($"[ReflectionCompatibilityDetector] Reflection compatibility issue in {_curCallingMethod}: Type.GetType argument `typeName` should not be renamed.");
break;
}
case "GetField":
case "GetFields":
case "GetMethod":
case "GetMethods":
case "GetProperty":
case "GetProperties":
case "GetEvent":
case "GetEvents":
case "GetMembers":
{
Debug.LogWarning($"[ReflectionCompatibilityDetector] Reflection compatibility issue in {_curCallingMethod}: called method:{method} the members of type should not be renamed.");
break;
}
}
}
}
}

View File

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

View File

@ -1,299 +0,0 @@
using dnlib.DotNet;
using Obfuz.Utils;
using System.Collections.Generic;
namespace Obfuz.ObfusPasses.SymbolObfus
{
public class VirtualMethodGroup
{
public List<MethodDef> methods;
private HashSet<TypeDef> _nameScopes;
private HashSet<TypeDef> _rootNameScope;
public HashSet<TypeDef> GetNameConflictTypeScopes()
{
if (_nameScopes != null)
{
return _nameScopes;
}
_nameScopes = new HashSet<TypeDef>();
foreach (var method in methods)
{
TypeDef cur = method.DeclaringType;
while (cur != null)
{
_nameScopes.Add(cur);
cur = MetaUtil.GetBaseTypeDef(cur);
}
}
return _nameScopes;
}
public HashSet<TypeDef> GetRootBeInheritedTypes()
{
if (_rootNameScope != null)
{
return _rootNameScope;
}
_rootNameScope = new HashSet<TypeDef>();
var nameScopes = GetNameConflictTypeScopes();
foreach (var type in nameScopes)
{
TypeDef parentType = MetaUtil.GetBaseTypeDef(type);
if (parentType == null || !nameScopes.Contains(parentType))
{
_rootNameScope.Add(type);
}
}
return _rootNameScope;
}
public IEnumerable<TypeDef> GetNameDeclaringTypeScopes()
{
foreach (var method in methods)
{
yield return method.DeclaringType;
}
}
}
public class VirtualMethodGroupCalculator
{
private class TypeFlatMethods
{
public HashSet<MethodDef> flatMethods = new HashSet<MethodDef>();
private bool IsFinalTypeSig(TypeSig type)
{
switch (type.ElementType)
{
case ElementType.Void:
case ElementType.Boolean:
case ElementType.Char:
case ElementType.I1:
case ElementType.I2:
case ElementType.I4:
case ElementType.I8:
case ElementType.U1:
case ElementType.U2:
case ElementType.U4:
case ElementType.U8:
case ElementType.R4:
case ElementType.R8:
case ElementType.String:
case ElementType.Object:
case ElementType.Class:
case ElementType.ValueType:
return true;
default: return false;
}
}
private bool IsVarType(TypeSig t)
{
return t.ElementType == ElementType.MVar || t.ElementType == ElementType.Var;
}
private bool IsClassOrValueType(TypeSig t)
{
return t.ElementType == ElementType.Class || t.ElementType == ElementType.ValueType;
}
private bool IsLooseTypeSigMatch(TypeSig t1, TypeSig t2)
{
t1 = t1.RemovePinnedAndModifiers();
t2 = t2.RemovePinnedAndModifiers();
if (t1.ElementType != t2.ElementType)
{
return IsVarType(t1) || IsVarType(t2);
}
switch (t1.ElementType)
{
case ElementType.Void:
case ElementType.Boolean:
case ElementType.Char:
case ElementType.I1:
case ElementType.I2:
case ElementType.I4:
case ElementType.I8:
case ElementType.U1:
case ElementType.U2:
case ElementType.U4:
case ElementType.U8:
case ElementType.R4:
case ElementType.R8:
case ElementType.I:
case ElementType.U:
case ElementType.R:
case ElementType.String:
case ElementType.Object:
case ElementType.TypedByRef:
return true;
case ElementType.Class:
case ElementType.ValueType:
{
return t1.AssemblyQualifiedName == t2.AssemblyQualifiedName;
}
case ElementType.Ptr:
case ElementType.ByRef:
case ElementType.SZArray:
{
break;
}
case ElementType.Array:
{
var a1 = (ArraySig)t1;
var a2 = (ArraySig)t2;
if (a1.Rank != a2.Rank)
{
return false;
}
break;
}
case ElementType.Var:
case ElementType.MVar:
{
//var v1 = (GenericSig)t1;
//var v2 = (GenericSig)t2;
//return v1.Number == v2.Number;
return true;
}
default: return true;
}
if (t1.Next != null && t2.Next != null)
{
return IsLooseTypeSigMatch(t1.Next, t2.Next);
}
return true;
}
private bool IsLooseMatch(MethodDef method1, MethodDef method2)
{
if (method1.Name != method2.Name)
{
return false;
}
if (method1.GetParamCount() != method2.GetParamCount())
{
return false;
}
if (!IsLooseTypeSigMatch(method1.ReturnType, method2.ReturnType))
{
return false;
}
for (int i = 0, n = method1.GetParamCount(); i < n; i++)
{
if (!IsLooseTypeSigMatch(method1.GetParam(i), method2.GetParam(i)))
{
return false;
}
}
return true;
}
public bool TryFindMatchVirtualMethod(MethodDef method, out MethodDef matchMethodDef)
{
foreach (var parentOrInterfaceMethod in flatMethods)
{
if (IsLooseMatch(method, parentOrInterfaceMethod))
{
matchMethodDef = parentOrInterfaceMethod;
return true;
}
}
matchMethodDef = null;
return false;
}
}
private readonly Dictionary<MethodDef, VirtualMethodGroup> _methodGroups = new Dictionary<MethodDef, VirtualMethodGroup>();
private readonly Dictionary<TypeDef, TypeFlatMethods> _visitedTypes = new Dictionary<TypeDef, TypeFlatMethods>();
public VirtualMethodGroup GetMethodGroup(MethodDef methodDef)
{
if (_methodGroups.TryGetValue(methodDef, out var group))
{
return group;
}
return null;
}
public void CalculateType(TypeDef typeDef)
{
if (_visitedTypes.ContainsKey(typeDef))
{
return;
}
var typeMethods = new TypeFlatMethods();
var interfaceMethods = new List<MethodDef>();
if (typeDef.BaseType != null)
{
TypeDef baseTypeDef = MetaUtil.GetTypeDefOrGenericTypeBaseThrowException(typeDef.BaseType);
CalculateType(baseTypeDef);
typeMethods.flatMethods.AddRange(_visitedTypes[baseTypeDef].flatMethods);
foreach (var intfType in typeDef.Interfaces)
{
TypeDef intfTypeDef = MetaUtil.GetTypeDefOrGenericTypeBaseThrowException(intfType.Interface);
CalculateType(intfTypeDef);
//typeMethods.flatMethods.AddRange(_visitedTypes[intfTypeDef].flatMethods);
interfaceMethods.AddRange(_visitedTypes[intfTypeDef].flatMethods);
}
}
foreach (MethodDef method in interfaceMethods)
{
if (typeMethods.TryFindMatchVirtualMethod(method, out var matchMethodDef))
{
// merge group
var group = _methodGroups[matchMethodDef];
var matchGroup = _methodGroups[method];
if (group != matchGroup)
{
foreach (var m in matchGroup.methods)
{
group.methods.Add(m);
_methodGroups[m] = group;
}
}
}
typeMethods.flatMethods.Add(method);
}
foreach (MethodDef method in typeDef.Methods)
{
if (!method.IsVirtual)
{
continue;
}
if (typeMethods.TryFindMatchVirtualMethod(method, out var matchMethodDef))
{
var group = _methodGroups[matchMethodDef];
group.methods.Add(method);
_methodGroups.Add(method, group);
}
else
{
_methodGroups.Add(method, new VirtualMethodGroup() { methods = new List<MethodDef> { method } });
}
if (method.IsNewSlot)
{
typeMethods.flatMethods.Add(method);
}
}
_visitedTypes.Add(typeDef, typeMethods);
}
}
}

View File

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

View File

@ -1,242 +0,0 @@
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using Obfuz.Emit;
using Obfuz.Settings;
using Obfuz.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using UnityEngine;
using FieldAttributes = dnlib.DotNet.FieldAttributes;
using HashUtil = Obfuz.Utils.HashUtil;
using IRandom = Obfuz.Utils.IRandom;
using KeyGenerator = Obfuz.Utils.KeyGenerator;
using TypeAttributes = dnlib.DotNet.TypeAttributes;
namespace Obfuz.ObfusPasses.Watermark
{
public class WatermarkPass : ObfuscationPassBase
{
private readonly WatermarkSettingsFacade _watermarkSettings;
public WatermarkPass(WatermarkSettingsFacade watermarkSettingsFacade)
{
this._watermarkSettings = watermarkSettingsFacade;
}
public override ObfuscationPassType Type => ObfuscationPassType.WaterMark;
public override void Start()
{
}
public override void Stop()
{
}
public override void Process()
{
var ctx = ObfuscationPassContext.Current;
foreach (ModuleDef mod in ctx.modulesToObfuscate)
{
AddWaterMarkToAssembly(mod, _watermarkSettings.text);
}
}
private TypeDef GetDataHolderType(ModuleDef module, TypeDef declaringType, int size)
{
using (var scope = new DisableTypeDefFindCacheScope(module))
{
var dataHolderType = new TypeDefUser($"$Obfuz$WatermarkDataHolderSize{size}_{declaringType.NestedTypes.Count}", module.Import(typeof(System.ValueType)));
dataHolderType.Attributes = TypeAttributes.NestedPrivate | TypeAttributes.Sealed;
dataHolderType.Layout = TypeAttributes.ExplicitLayout;
dataHolderType.PackingSize = 1;
dataHolderType.ClassSize = (uint)size;
dataHolderType.DeclaringType = declaringType;
return dataHolderType;
}
}
class WatermarkInfo
{
public string text;
public byte[] signature;
public readonly List<FieldDef> signatureHoldFields = new List<FieldDef>();
}
private WatermarkInfo CreateWatermarkInfo(ModuleDef module, EncryptionScopeInfo encryptionScope, string waterMarkText)
{
string finalWatermarkText = $"{waterMarkText} [{module.Name}]";
byte[] watermarkBytes = KeyGenerator.GenerateKey(finalWatermarkText, _watermarkSettings.signatureLength);
var watermarkInfo = new WatermarkInfo()
{
text = finalWatermarkText,
signature = watermarkBytes,
};
TypeDef moduleType = module.FindNormal("<PrivateImplementationDetails>");
if (moduleType == null)
{
//throw new Exception($"Module '{module.Name}' does not contain a '<PrivateImplementationDetails>' type.");
moduleType = new TypeDefUser("<PrivateImplementationDetails>", module.Import(typeof(object)));
moduleType.Attributes = TypeAttributes.NotPublic | TypeAttributes.Sealed;
moduleType.CustomAttributes.Add(new CustomAttribute(module.Import(module.Import(typeof(CompilerGeneratedAttribute)).ResolveTypeDefThrow().FindDefaultConstructor())));
module.Types.Add(moduleType);
}
var random = encryptionScope.localRandomCreator(0);
for (int subIndex = 0; subIndex < watermarkBytes.Length;)
{
int subSegmentLength = Math.Min(random.NextInt(16, 32) & ~3, watermarkBytes.Length - subIndex);
int paddingLength = random.NextInt(8, 32) & ~3;
int totalLength = subSegmentLength + paddingLength;
TypeDef dataHolderType = GetDataHolderType(module, moduleType, totalLength);
byte[] subSegment = new byte[totalLength];
Buffer.BlockCopy(watermarkBytes, subIndex, subSegment, 0, subSegmentLength);
for (int i = subSegmentLength; i < totalLength; i++)
{
subSegment[i] = (byte)random.NextInt(0, 256);
}
subIndex += subSegmentLength;
var field = new FieldDefUser($"$Obfuz$WatermarkDataHolderField{moduleType.Fields.Count}",
new FieldSig(dataHolderType.ToTypeSig()),
FieldAttributes.Assembly | FieldAttributes.InitOnly | FieldAttributes.Static | FieldAttributes.HasFieldRVA);
field.DeclaringType = moduleType;
field.InitialValue = subSegment;
watermarkInfo.signatureHoldFields.Add(field);
}
var moduleTypeFields = moduleType.Fields.ToList();
RandomUtil.ShuffleList(moduleTypeFields, random);
moduleType.Fields.Clear();
foreach (var field in moduleTypeFields)
{
moduleType.Fields.Add(field);
}
return watermarkInfo;
}
private int GetRandomInsertPosition(List<Instruction> instructions, IRandom random)
{
var insertPositions = instructions
.Select((inst, index) => new { Instruction = inst, Index = index })
.Where(x => x.Instruction.OpCode.FlowControl == FlowControl.Next)
.Select(x => x.Index)
.ToList();
if (insertPositions.Count == 0)
{
return 0; // No valid position to insert
}
return insertPositions[random.NextInt(insertPositions.Count)] + 1;
}
private void AddFieldAccessToSignatureHolder(ModuleDef module, EncryptionScopeInfo encryptionScope, WatermarkInfo watermarkInfo)
{
BurstCompileComputeCache burstCompileComputeCache = ObfuscationPassContext.Current.burstCompileComputeCache;
var insertTargetMethods = module.Types
.Where(t => !MetaUtil.HasBurstCompileAttribute(t))
.SelectMany(t => t.Methods)
.Where(m => m.HasBody && m.Body.Instructions.Count > 10 && !MetaUtil.HasBurstCompileAttribute(m)
&& !burstCompileComputeCache.IsBurstCompileMethodOrReferencedByBurstCompileMethod(m))
.ToList();
if (insertTargetMethods.Count == 0)
{
Debug.LogWarning($"No suitable methods found in module '{module.Name}' to insert access to watermark signature.");
return;
}
var random = encryptionScope.localRandomCreator(HashUtil.ComputeHash($"AddFieldAccessToSignatureHolder:{module.Name}"));
DefaultMetadataImporter importer = ObfuscationPassContext.Current.moduleEntityManager.GetEntity<DefaultMetadataImporter>(module);
foreach (var fieldDef in watermarkInfo.signatureHoldFields)
{
// Randomly select a method to insert the access
var targetMethod = insertTargetMethods[random.NextInt(insertTargetMethods.Count)];
var insts = (List<Instruction>)targetMethod.Body.Instructions;
int insertIndex = GetRandomInsertPosition(insts, random);
Instruction nop = Instruction.Create(OpCodes.Nop);
insts.InsertRange(insertIndex, new[]
{
Instruction.CreateLdcI4(random.NextInt(1, 10000000)),
Instruction.Create(OpCodes.Brtrue, nop),
Instruction.CreateLdcI4(random.NextInt(fieldDef.InitialValue.Length)),
Instruction.Create(OpCodes.Newarr, module.CorLibTypes.Byte),
Instruction.Create(OpCodes.Ldtoken, fieldDef),
Instruction.Create(OpCodes.Call, importer.InitializedArray),
nop,
});
//Debug.Log($"Inserted watermark access for field '{fieldDef.Name}' in method '{targetMethod.FullName}' at index {insertIndex}.");
}
}
private readonly OpCode[] binOpCodes = new[]
{
OpCodes.Add, OpCodes.Sub, OpCodes.Mul, OpCodes.Div, OpCodes.Rem,
OpCodes.And, OpCodes.Or, OpCodes.Xor
};
private OpCode GetRandomBinOpCode(IRandom random)
{
return binOpCodes[random.NextInt(binOpCodes.Length)];
}
private void AddWaterMarkILSequences(ModuleDef module, EncryptionScopeInfo encryptionScope, WatermarkInfo watermarkInfo)
{
var insertTargetMethods = module.Types
.SelectMany(t => t.Methods)
.Where(m => m.HasBody && m.Body.Instructions.Count > 10)
.ToList();
if (insertTargetMethods.Count == 0)
{
Debug.LogWarning($"No suitable methods found in module '{module.Name}' to insert watermark IL sequences.");
return;
}
var random = encryptionScope.localRandomCreator(HashUtil.ComputeHash($"AddWaterMarkILSequences:{module.Name}"));
int[] signature = KeyGenerator.ConvertToIntKey(watermarkInfo.signature);
for (int intIndex = 0; intIndex < signature.Length;)
{
int ldcCount = Math.Min(random.NextInt(2, 4), signature.Length - intIndex);
// Randomly select a method to insert the IL sequence
var targetMethod = insertTargetMethods[random.NextInt(insertTargetMethods.Count)];
var insts = (List<Instruction>)targetMethod.Body.Instructions;
int insertIndex = GetRandomInsertPosition(insts, random);
var insertInstructions = new List<Instruction>()
{
Instruction.CreateLdcI4(random.NextInt(1, 10000000)),
Instruction.Create(OpCodes.Brtrue, insts[insertIndex]),
};
for (int i = 0; i < ldcCount; i++)
{
insertInstructions.Add(Instruction.CreateLdcI4(signature[intIndex + i]));
if (i > 0)
{
insertInstructions.Add(Instruction.Create(GetRandomBinOpCode(random)));
}
}
insertInstructions.Add(Instruction.Create(OpCodes.Pop));
insts.InsertRange(insertIndex, insertInstructions);
intIndex += ldcCount;
//Debug.Log($"Inserted watermark IL sequence for in method '{targetMethod.FullName}' at index {insertIndex}.");
}
}
private void AddWaterMarkToAssembly(ModuleDef module, string waterMarkText)
{
var ctx = ObfuscationPassContext.Current;
EncryptionScopeInfo encryptionScope = ctx.moduleEntityManager.EncryptionScopeProvider.GetScope(module);
WatermarkInfo watermarkInfo = CreateWatermarkInfo(module, encryptionScope, waterMarkText);
AddFieldAccessToSignatureHolder(module, encryptionScope, watermarkInfo);
AddWaterMarkILSequences(module, encryptionScope, watermarkInfo);
}
}
}

View File

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

View File

@ -1,110 +0,0 @@
using dnlib.DotNet;
using Obfuz.Editor;
using Obfuz.Utils;
using System.Linq;
using UnityEngine;
namespace Obfuz
{
public class ObfuscationMethodWhitelist
{
private readonly ObfuzIgnoreScopeComputeCache _obfuzComputeCache;
private readonly BurstCompileComputeCache _burstCompileComputeCache;
public ObfuscationMethodWhitelist(ObfuzIgnoreScopeComputeCache obfuzComputeCache, BurstCompileComputeCache burstCompileComputeCache)
{
_obfuzComputeCache = obfuzComputeCache;
_burstCompileComputeCache = burstCompileComputeCache;
}
public bool IsInWhiteList(ModuleDef module)
{
string modName = module.Assembly.Name;
if (modName == ConstValues.ObfuzRuntimeAssemblyName)
{
return true;
}
//if (MetaUtil.HasObfuzIgnoreScope(module))
//{
// return true;
//}
return false;
}
private bool DoesMethodContainsRuntimeInitializeOnLoadMethodAttributeAndLoadTypeGreaterEqualAfterAssembliesLoaded(MethodDef method)
{
CustomAttribute ca = method.CustomAttributes.Find(ConstValues.RuntimeInitializedOnLoadMethodAttributeFullName);
if (ca != null && ca.ConstructorArguments.Count > 0)
{
RuntimeInitializeLoadType loadType = (RuntimeInitializeLoadType)ca.ConstructorArguments[0].Value;
if (loadType >= RuntimeInitializeLoadType.AfterAssembliesLoaded)
{
return true;
}
}
return false;
}
public bool IsInWhiteList(MethodDef method)
{
TypeDef typeDef = method.DeclaringType;
//if (IsInWhiteList(typeDef))
//{
// return true;
//}
if (method.Name.StartsWith(ConstValues.ObfuzInternalSymbolNamePrefix))
{
return true;
}
if (_obfuzComputeCache.HasSelfOrDeclaringOrEnclosingOrInheritObfuzIgnoreScope(method, typeDef, ObfuzScope.MethodBody))
{
return true;
}
CustomAttribute ca = method.CustomAttributes.Find(ConstValues.RuntimeInitializedOnLoadMethodAttributeFullName);
if (DoesMethodContainsRuntimeInitializeOnLoadMethodAttributeAndLoadTypeGreaterEqualAfterAssembliesLoaded(method))
{
return true;
}
if (MetaUtil.HasBurstCompileAttribute(method) || _burstCompileComputeCache.IsBurstCompileMethodOrReferencedByBurstCompileMethod(method))
{
return true;
}
// don't obfuscate cctor when it has RuntimeInitializeOnLoadMethodAttribute with load type AfterAssembliesLoaded
if (method.IsStatic && method.Name == ".cctor" && typeDef.Methods.Any(m => DoesMethodContainsRuntimeInitializeOnLoadMethodAttributeAndLoadTypeGreaterEqualAfterAssembliesLoaded(m)))
{
return true;
}
return false;
}
public bool IsInWhiteList(TypeDef type)
{
if (type.Name.StartsWith(ConstValues.ObfuzInternalSymbolNamePrefix))
{
return true;
}
if (IsInWhiteList(type.Module))
{
return true;
}
if (MetaUtil.HasBurstCompileAttribute(type))
{
return true;
}
if (_obfuzComputeCache.HasSelfOrDeclaringOrEnclosingOrInheritObfuzIgnoreScope(type, type.DeclaringType, ObfuzScope.MethodBody))
{
return true;
}
//if (type.DeclaringType != null && IsInWhiteList(type.DeclaringType))
//{
// return true;
//}
if (type.FullName == ConstValues.GeneratedEncryptionVirtualMachineFullName)
{
return true;
}
return false;
}
}
}

View File

@ -1,234 +0,0 @@
using dnlib.DotNet.Writer;
using Obfuz.EncryptionVM;
using Obfuz.ObfusPasses;
using Obfuz.ObfusPasses.CallObfus;
using Obfuz.ObfusPasses.ConstEncrypt;
using Obfuz.ObfusPasses.ControlFlowObfus;
using Obfuz.ObfusPasses.EvalStackObfus;
using Obfuz.ObfusPasses.ExprObfus;
using Obfuz.ObfusPasses.FieldEncrypt;
using Obfuz.ObfusPasses.RemoveConstField;
using Obfuz.ObfusPasses.SymbolObfus;
using Obfuz.ObfusPasses.Watermark;
using Obfuz.Settings;
using Obfuz.Utils;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace Obfuz
{
public class CoreSettingsFacade
{
public BuildTarget buildTarget;
public RuntimeType targetRuntime;
public byte[] defaultStaticSecretKey;
public byte[] defaultDynamicSecretKey;
public List<string> assembliesUsingDynamicSecretKeys;
public int randomSeed;
public string encryptionVmGenerationSecretKey;
public int encryptionVmOpCodeCount;
public string encryptionVmCodeFile;
public List<string> assembliesToObfuscate;
public List<string> nonObfuscatedButReferencingObfuscatedAssemblies;
public List<string> assemblySearchPaths;
public string obfuscatedAssemblyOutputPath;
public string obfuscatedAssemblyTempOutputPath;
public ObfuscationPassType enabledObfuscationPasses;
public List<string> obfuscationPassRuleConfigFiles;
public List<IObfuscationPass> obfuscationPasses;
}
public class ObfuscatorBuilder
{
private CoreSettingsFacade _coreSettingsFacade;
public CoreSettingsFacade CoreSettingsFacade => _coreSettingsFacade;
public void InsertTopPriorityAssemblySearchPaths(List<string> assemblySearchPaths)
{
_coreSettingsFacade.assemblySearchPaths.InsertRange(0, assemblySearchPaths);
}
public ObfuscatorBuilder AddPass(IObfuscationPass pass)
{
_coreSettingsFacade.obfuscationPasses.Add(pass);
return this;
}
public Obfuscator Build()
{
return new Obfuscator(this);
}
public static List<string> BuildUnityAssemblySearchPaths(bool searchPathIncludeUnityEditorDll = false)
{
string applicationContentsPath = EditorApplication.applicationContentsPath;
var searchPaths = new List<string>
{
#if UNITY_2021_1_OR_NEWER
#if UNITY_STANDALONE_WIN || (UNITY_EDITOR_WIN && UNITY_SERVER) || UNITY_WSA || UNITY_LUMIN
"MonoBleedingEdge/lib/mono/unityaot-win32",
"MonoBleedingEdge/lib/mono/unityaot-win32/Facades",
#elif UNITY_STANDALONE_OSX || (UNITY_EDITOR_OSX && UNITY_SERVER) || UNITY_IOS || UNITY_TVOS
"MonoBleedingEdge/lib/mono/unityaot-macos",
"MonoBleedingEdge/lib/mono/unityaot-macos/Facades",
#else
"MonoBleedingEdge/lib/mono/unityaot-linux",
"MonoBleedingEdge/lib/mono/unityaot-linux/Facades",
#endif
#else
"MonoBleedingEdge/lib/mono/unityaot",
"MonoBleedingEdge/lib/mono/unityaot/Facades",
#endif
#if UNITY_STANDALONE_WIN || (UNITY_EDITOR_WIN && UNITY_SERVER)
"PlaybackEngines/windowsstandalonesupport/Variations/il2cpp/Managed",
#elif UNITY_STANDALONE_OSX || (UNITY_EDITOR_OSX && UNITY_SERVER)
"PlaybackEngines/MacStandaloneSupport/Variations/il2cpp/Managed",
#elif UNITY_STANDALONE_LINUX || (UNITY_EDITOR_LINUX && UNITY_SERVER)
"PlaybackEngines/LinuxStandaloneSupport/Variations/il2cpp/Managed",
#elif UNITY_ANDROID
"PlaybackEngines/AndroidPlayer/Variations/il2cpp/Managed",
#elif UNITY_IOS
"PlaybackEngines/iOSSupport/Variations/il2cpp/Managed",
#elif UNITY_MINIGAME || UNITY_WEIXINMINIGAME
#if TUANJIE_1_1_OR_NEWER
"PlaybackEngines/WeixinMiniGameSupport/Variations/il2cpp/nondevelopment/Data/Managed",
#else
"PlaybackEngines/WeixinMiniGameSupport/Variations/nondevelopment/Data/Managed",
#endif
#elif UNITY_OPENHARMONY
"PlaybackEngines/OpenHarmonyPlayer/Variations/il2cpp/Managed",
#elif UNITY_WEBGL
"PlaybackEngines/WebGLSupport/Variations/nondevelopment/Data/Managed",
#elif UNITY_TVOS
"PlaybackEngines/AppleTVSupport/Variations/il2cpp/Managed",
#elif UNITY_WSA
"PlaybackEngines/WSASupport/Variations/il2cpp/Managed",
#elif UNITY_LUMIN
"PlaybackEngines/LuminSupport/Variations/il2cpp/Managed",
#else
#error "Unsupported platform, please report to us"
#endif
};
if (searchPathIncludeUnityEditorDll)
{
searchPaths.Add("Managed/UnityEngine");
}
var resultPaths = new List<string>();
foreach (var path in searchPaths)
{
string candidatePath1 = Path.Combine(applicationContentsPath, path);
if (Directory.Exists(candidatePath1))
{
resultPaths.Add(candidatePath1);
}
if (path.StartsWith("PlaybackEngines"))
{
string candidatePath2 = Path.Combine(Path.GetDirectoryName(Path.GetDirectoryName(applicationContentsPath)), path);
if (Directory.Exists(candidatePath2))
{
resultPaths.Add(candidatePath2);
}
}
}
return resultPaths;
}
public static ObfuscatorBuilder FromObfuzSettings(ObfuzSettings settings, BuildTarget target, bool searchPathIncludeUnityEditorInstallLocation, bool searchPathIncludeUnityEditorDll = false)
{
List<string> searchPaths = searchPathIncludeUnityEditorInstallLocation ?
BuildUnityAssemblySearchPaths(searchPathIncludeUnityEditorDll).Concat(settings.assemblySettings.additionalAssemblySearchPaths).ToList()
: settings.assemblySettings.additionalAssemblySearchPaths.ToList();
foreach (var path in searchPaths)
{
bool exists = Directory.Exists(path);
UnityEngine.Debug.Log($"search path:{path} exists:{exists}");
}
RuntimeType targetRuntime = settings.compatibilitySettings.targetRuntime != RuntimeType.ActivatedScriptingBackend ?
settings.compatibilitySettings.targetRuntime :
(PlatformUtil.IsMonoBackend() ? RuntimeType.Mono : RuntimeType.IL2CPP);
if (searchPathIncludeUnityEditorDll && targetRuntime != RuntimeType.Mono)
{
Debug.LogError($"obfuscate dll for editor, but ObfuzSettings.CompatibilitySettings.targetRuntime isn't RuntimeType.Mono. Use RuntimeType.Mono for targetRuntime automatically.");
targetRuntime = RuntimeType.Mono;
}
var builder = new ObfuscatorBuilder
{
_coreSettingsFacade = new CoreSettingsFacade()
{
buildTarget = target,
targetRuntime = targetRuntime,
defaultStaticSecretKey = KeyGenerator.GenerateKey(settings.secretSettings.defaultStaticSecretKey, VirtualMachine.SecretKeyLength),
defaultDynamicSecretKey = KeyGenerator.GenerateKey(settings.secretSettings.defaultDynamicSecretKey, VirtualMachine.SecretKeyLength),
assembliesUsingDynamicSecretKeys = settings.secretSettings.assembliesUsingDynamicSecretKeys.ToList(),
randomSeed = settings.secretSettings.randomSeed,
encryptionVmGenerationSecretKey = settings.encryptionVMSettings.codeGenerationSecretKey,
encryptionVmOpCodeCount = settings.encryptionVMSettings.encryptionOpCodeCount,
encryptionVmCodeFile = settings.encryptionVMSettings.codeOutputPath,
assembliesToObfuscate = settings.assemblySettings.GetAssembliesToObfuscate(),
nonObfuscatedButReferencingObfuscatedAssemblies = settings.assemblySettings.nonObfuscatedButReferencingObfuscatedAssemblies.ToList(),
assemblySearchPaths = searchPaths,
obfuscatedAssemblyOutputPath = settings.GetObfuscatedAssemblyOutputPath(target),
obfuscatedAssemblyTempOutputPath = settings.GetObfuscatedAssemblyTempOutputPath(target),
enabledObfuscationPasses = settings.obfuscationPassSettings.enabledPasses,
obfuscationPassRuleConfigFiles = settings.obfuscationPassSettings.ruleFiles?.ToList() ?? new List<string>(),
obfuscationPasses = new List<IObfuscationPass>(),
},
};
ObfuscationPassType obfuscationPasses = settings.obfuscationPassSettings.enabledPasses;
if (obfuscationPasses.HasFlag(ObfuscationPassType.SymbolObfus) && settings.symbolObfusSettings.detectReflectionCompatibility)
{
builder.AddPass(new ReflectionCompatibilityDetectionPass(settings.symbolObfusSettings.ToFacade()));
}
if (obfuscationPasses.HasFlag(ObfuscationPassType.ConstEncrypt))
{
builder.AddPass(new ConstEncryptPass(settings.constEncryptSettings.ToFacade()));
}
if (obfuscationPasses.HasFlag(ObfuscationPassType.RemoveConstField))
{
builder.AddPass(new RemoveConstFieldPass(settings.removeConstFieldSettings.ToFacade()));
}
if (obfuscationPasses.HasFlag(ObfuscationPassType.ExprObfus))
{
builder.AddPass(new ExprObfusPass(settings.exprObfusSettings.ToFacade()));
}
//if (obfuscationPasses.HasFlag(ObfuscationPassType.EvalStackObfus))
//{
// builder.AddPass(new EvalStackObfusPass(settings.evalStackObfusSettings.ToFacade()));
//}
if (obfuscationPasses.HasFlag(ObfuscationPassType.FieldEncrypt))
{
builder.AddPass(new FieldEncryptPass(settings.fieldEncryptSettings.ToFacade()));
}
if (obfuscationPasses.HasFlag(ObfuscationPassType.CallObfus))
{
builder.AddPass(new CallObfusPass(settings.callObfusSettings.ToFacade()));
}
if (obfuscationPasses.HasFlag(ObfuscationPassType.ControlFlowObfus))
{
builder.AddPass(new ControlFlowObfusPass(settings.controlFlowObfusSettings.ToFacade()));
}
if (obfuscationPasses.HasFlag(ObfuscationPassType.WaterMark))
{
builder.AddPass(new WatermarkPass(settings.watermarkSettings.ToFacade()));
}
if (obfuscationPasses.HasFlag(ObfuscationPassType.SymbolObfus))
{
builder.AddPass(new SymbolObfusPass(settings.symbolObfusSettings.ToFacade()));
}
return builder;
}
}
}

View File

@ -1,41 +0,0 @@
using Obfuz.Editor;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Obfuz.Settings
{
[Serializable]
public class AssemblySettings
{
[Tooltip("name of assemblies to obfuscate, please don't add 'Obfuz.Runtime'")]
public string[] assembliesToObfuscate;
[Tooltip("name of assemblies not obfuscated but reference assemblies to obfuscated ")]
public string[] nonObfuscatedButReferencingObfuscatedAssemblies;
[Tooltip("additional assembly search paths")]
public string[] additionalAssemblySearchPaths;
[Tooltip("obfuscate Obfuz.Runtime")]
public bool obfuscateObfuzRuntime = true;
public List<string> GetAssembliesToObfuscate()
{
var asses = new List<string>(assembliesToObfuscate ?? Array.Empty<string>());
if (obfuscateObfuzRuntime && !asses.Contains(ConstValues.ObfuzRuntimeAssemblyName))
{
asses.Add(ConstValues.ObfuzRuntimeAssemblyName);
}
return asses;
}
public List<string> GetObfuscationRelativeAssemblyNames()
{
var asses = GetAssembliesToObfuscate();
asses.AddRange(nonObfuscatedButReferencingObfuscatedAssemblies ?? Array.Empty<string>());
return asses;
}
}
}

View File

@ -1,18 +0,0 @@
using System;
using UnityEngine;
namespace Obfuz.Settings
{
[Serializable]
public class BuildPipelineSettings
{
[Tooltip("enable Obfuz")]
public bool enable = true;
[Tooltip("callback order of LinkXmlProcessor")]
public int linkXmlProcessCallbackOrder = 10000;
[Tooltip("callback order of ObfuscationProcess")]
public int obfuscationProcessCallbackOrder = 10000;
}
}

View File

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

View File

@ -1,53 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Obfuz.Settings
{
public enum ProxyMode
{
Dispatch,
Delegate,
}
public class CallObfuscationSettingsFacade
{
public ProxyMode proxyMode;
public int obfuscationLevel;
public int maxProxyMethodCountPerDispatchMethod;
public bool obfuscateCallToMethodInMscorlib;
public List<string> ruleFiles;
}
[Serializable]
public class CallObfuscationSettings
{
public ProxyMode proxyMode = ProxyMode.Dispatch;
[Tooltip("The obfuscation level for the obfuscation. Higher levels provide more security but may impact performance.")]
[Range(1, 4)]
public int obfuscationLevel = 1;
[Tooltip("The maximum number of proxy methods that can be generated per dispatch method. This helps to limit the complexity of the generated code and improve performance.")]
public int maxProxyMethodCountPerDispatchMethod = 100;
[Tooltip("Whether to obfuscate calls to methods in mscorlib. Enable this option will impact performance.")]
public bool obfuscateCallToMethodInMscorlib;
[Tooltip("rule config xml files")]
public string[] ruleFiles;
public CallObfuscationSettingsFacade ToFacade()
{
return new CallObfuscationSettingsFacade
{
proxyMode = proxyMode,
obfuscationLevel = obfuscationLevel,
maxProxyMethodCountPerDispatchMethod = maxProxyMethodCountPerDispatchMethod,
obfuscateCallToMethodInMscorlib = obfuscateCallToMethodInMscorlib,
ruleFiles = ruleFiles?.ToList() ?? new List<string>(),
};
}
}
}

View File

@ -1,17 +0,0 @@
using System;
namespace Obfuz.Settings
{
public enum RuntimeType
{
ActivatedScriptingBackend,
IL2CPP,
Mono,
}
[Serializable]
public class CompatibilitySettings
{
public RuntimeType targetRuntime;
}
}

Some files were not shown because too many files have changed in this diff Show More