Compare commits
246 Commits
1.0.0-alpha
...
main
Author | SHA1 | Date |
---|---|---|
|
403764e7af | |
|
e12a0e26dc | |
|
daff29ea94 | |
|
eeff4a75ca | |
|
b0699ecf5c | |
|
5557b27724 | |
|
59b1166ff3 | |
|
4ad3ed76dc | |
|
2576236960 | |
|
c3c53b2797 | |
|
0889f730fd | |
|
87cd3caf44 | |
|
8dd6352028 | |
|
739fcb24c5 | |
|
246a49f8ba | |
|
1ec6e2f426 | |
|
b68571de7e | |
|
50fe1e1179 | |
|
d52a9e7016 | |
|
f5c2fe94ea | |
|
54bcae5178 | |
|
cfb544426b | |
|
1e027e6299 | |
|
4db68f707b | |
|
c596b58d3e | |
|
ddb144eac8 | |
|
1a240c47ac | |
|
2e48164ae9 | |
|
9b6e6375f6 | |
|
38ad0de746 | |
|
6ec1a74d57 | |
|
d6d9cde741 | |
|
87f086e310 | |
|
69b91575db | |
|
0985b3d06e | |
|
d4133f1e8a | |
|
3bcf204f69 | |
|
905351789e | |
|
3bcb093467 | |
|
49194ca1af | |
|
6a4f84a9b0 | |
|
083ddd3035 | |
|
2887231df7 | |
|
c3238c54a9 | |
|
f908b648c1 | |
|
29debc44bf | |
|
9cbb105405 | |
|
e3d9d7a08e | |
|
4b0c5d7521 | |
|
9b9eb6d12d | |
|
52d9ee1349 | |
|
bf3f6e4534 | |
|
655c2fe07f | |
|
02ed0608e4 | |
|
59db0dfaab | |
|
2b8e51b12d | |
|
df181ed5c1 | |
|
1f29b5530e | |
|
af8477f4b3 | |
|
9d46b5438a | |
|
a833cf26e1 | |
|
7a7ef72728 | |
|
ac9c96b4b9 | |
|
95b789deb2 | |
|
f3bde846ea | |
|
905da05afc | |
|
62deffa10d | |
|
72d0b292c5 | |
|
2572841e59 | |
|
38ebe11d7d | |
|
73915db7ca | |
|
832a955167 | |
|
5cdc4c9f92 | |
|
0508421850 | |
|
0ad96daa32 | |
|
cfe9dcdd08 | |
|
1afc36339d | |
|
1f9aac59ee | |
|
338d2acf05 | |
|
d8fb8bc630 | |
|
67990f841a | |
|
cbf9ab7d68 | |
|
f8571ada9e | |
|
b1731a8c38 | |
|
8314ed4327 | |
|
f247719bc1 | |
|
9c445213b5 | |
|
111d3a7dc1 | |
|
4bc6cf923f | |
|
8288042e94 | |
|
b84d158fac | |
|
0fe0a91793 | |
|
d60d0e02dd | |
|
52fcf17161 | |
|
7ff5c97140 | |
|
df53a0bd1b | |
|
174140c5da | |
|
3f00d5ca91 | |
|
28b841562c | |
|
6226c3a867 | |
|
a61f31e289 | |
|
ea5a8e62ce | |
|
83598d6805 | |
|
114707544a | |
|
a109511f9e | |
|
3867a98d48 | |
|
025f900f4e | |
|
9505f2b90f | |
|
10d450c4e3 | |
|
ac6ca08d87 | |
|
260f8b8cc5 | |
|
40f6c90494 | |
|
f2409de99a | |
|
5124f993c7 | |
|
2ecf363d0b | |
|
75a4e2cdad | |
|
fea2e65075 | |
|
b7d2f69321 | |
|
7e2162e66d | |
|
9db3f0bd05 | |
|
f1c423ed02 | |
|
432eb83c41 | |
|
161ab5a29e | |
|
8bd2aab9da | |
|
58ad0fca67 | |
|
b38becf84a | |
|
1508cdc31d | |
|
b021a8be40 | |
|
ebf34b22af | |
|
e023f0aa7d | |
|
1604efbd19 | |
|
998af4ed38 | |
|
39c9925cbc | |
|
1f74c8d65d | |
|
0c0a6afee4 | |
|
fa4fb9da09 | |
|
88c8cbab08 | |
|
da044b72bc | |
|
51020dfc93 | |
|
a231de1f62 | |
|
76cb8fbcbb | |
|
10e6c0d914 | |
|
cad7fff2d1 | |
|
b9061c567c | |
|
f0c09ad741 | |
|
dcd38e288b | |
|
374a297e45 | |
|
b113364214 | |
|
84ed5b127a | |
|
2312291040 | |
|
c3ed85fb3f | |
|
c173efe689 | |
|
5ce7b9b5f4 | |
|
febb8c9fd8 | |
|
e818c6ad4d | |
|
a6863b5089 | |
|
28ac98352d | |
|
b85f3f54a0 | |
|
620d695880 | |
|
ceb92fba40 | |
|
cbd4f1ded9 | |
|
468ea6a343 | |
|
94b9b7ee2f | |
|
14a6ddb661 | |
|
77c6635eda | |
|
8f0a5bc0f2 | |
|
1b3c1c4958 | |
|
22fca877f6 | |
|
994e63966f | |
|
f134b88c13 | |
|
cd99bfe4f3 | |
|
62f4063078 | |
|
c1600f0f4d | |
|
4ca7a53a1e | |
|
fcbf77bb40 | |
|
b51893d154 | |
|
78699d7959 | |
|
ad258e9c84 | |
|
386048b485 | |
|
3066fbf3c7 | |
|
cd99a13562 | |
|
9d77cfa269 | |
|
702f20c6b0 | |
|
c84d4bae5b | |
|
6e989ccd36 | |
|
e0da3da2bc | |
|
882047eb6c | |
|
b2ba676ec1 | |
|
1cd1b912ec | |
|
b2d7637438 | |
|
48f1dfe64a | |
|
647619943f | |
|
f1a225cd81 | |
|
d64e57b370 | |
|
5f4083066b | |
|
5de469c4a6 | |
|
28e276eda5 | |
|
03b0172240 | |
|
41230aca29 | |
|
fb9ffae1e8 | |
|
b6500147c2 | |
|
3425abceb5 | |
|
f5b45a0543 | |
|
4d8737f01c | |
|
d06caf5e38 | |
|
32d1aac9ba | |
|
cb27fadb08 | |
|
05c3fd24bf | |
|
3fe3a6b302 | |
|
e19dbe1dc8 | |
|
c1beb962f5 | |
|
0efc98fb4d | |
|
bf38f43824 | |
|
09fdd3052d | |
|
1e8832ca7e | |
|
69a4cd686f | |
|
4398ee0875 | |
|
b18a8f70e3 | |
|
8cdd69fd45 | |
|
f265022d0c | |
|
2f7e2be97a | |
|
3d04c15d98 | |
|
425db24ee2 | |
|
1f29de26cf | |
|
b6cc07b54b | |
|
bd370e545a | |
|
c260cc2379 | |
|
d258738262 | |
|
10eef16d78 | |
|
2bc310f15e | |
|
f332617acc | |
|
0a9968f7a1 | |
|
48779110f6 | |
|
0ef162b901 | |
|
2453acc1d3 | |
|
8f8422864b | |
|
acb35e375e | |
|
4fd71a30c3 | |
|
da47e1283d | |
|
5766d2f2f4 | |
|
8f66a0ac5b | |
|
544f8157fc | |
|
bed98bd6be | |
|
aa2ea50ed3 | |
|
faeafc3cf8 | |
|
e13adb7efd |
|
@ -1,22 +0,0 @@
|
||||||
## 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
|
|
|
@ -1,15 +0,0 @@
|
||||||
<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>
|
|
|
@ -1,24 +0,0 @@
|
||||||
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
|
|
|
@ -1,57 +0,0 @@
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
{
|
|
||||||
"profiles": {
|
|
||||||
"DeobfuscateStackTrace": {
|
|
||||||
"commandName": "Project",
|
|
||||||
"commandLineArgs": "-m ../../../mapping.xml -i ../../../obfuscated.log -o ../../../deobfuscated.log"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,128 +0,0 @@
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
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
|
@ -1,17 +0,0 @@
|
||||||
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()
|
|
|
@ -2,11 +2,7 @@
|
||||||
using Obfuz.Utils;
|
using Obfuz.Utils;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using UnityEditor.VersionControl;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace Obfuz.Conf
|
namespace Obfuz.Conf
|
||||||
|
@ -17,7 +13,7 @@ namespace Obfuz.Conf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public interface IMethodRule<R> where R: IRule<R>
|
public interface IMethodRule<R> where R : IRule<R>
|
||||||
{
|
{
|
||||||
string Name { get; set; }
|
string Name { get; set; }
|
||||||
NameMatcher NameMatcher { get; set; }
|
NameMatcher NameMatcher { get; set; }
|
||||||
|
@ -33,7 +29,7 @@ namespace Obfuz.Conf
|
||||||
public R Rule { get; set; }
|
public R Rule { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ITypeRule<T, R> where T: IMethodRule<R> where R : IRule<R>
|
public interface ITypeRule<T, R> where T : IMethodRule<R> where R : IRule<R>
|
||||||
{
|
{
|
||||||
string Name { get; set; }
|
string Name { get; set; }
|
||||||
|
|
|
@ -2,12 +2,7 @@
|
||||||
using Obfuz.Utils;
|
using Obfuz.Utils;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using UnityEditor.VersionControl;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace Obfuz.Conf
|
namespace Obfuz.Conf
|
||||||
{
|
{
|
|
@ -3,9 +3,6 @@ using Obfuz.ObfusPasses;
|
||||||
using Obfuz.Utils;
|
using Obfuz.Utils;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
|
@ -189,7 +186,7 @@ namespace Obfuz
|
||||||
ObfuscationPassType passType = ObfuscationPassType.None;
|
ObfuscationPassType passType = ObfuscationPassType.None;
|
||||||
foreach (var passName in obfuscationPassTypesStr.Split('|'))
|
foreach (var passName in obfuscationPassTypesStr.Split('|'))
|
||||||
{
|
{
|
||||||
if (Enum.TryParse< ObfuscationPassType>(passName, out var pass))
|
if (Enum.TryParse<ObfuscationPassType>(passName, out var pass))
|
||||||
{
|
{
|
||||||
passType |= pass;
|
passType |= pass;
|
||||||
}
|
}
|
||||||
|
@ -389,7 +386,7 @@ namespace Obfuz
|
||||||
{
|
{
|
||||||
if (ass.nameMatcher.IsMatch(assName))
|
if (ass.nameMatcher.IsMatch(assName))
|
||||||
{
|
{
|
||||||
result = (ass, _defaultPassRule);
|
result = (ass, ass.rule);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,22 +6,12 @@ using Obfuz.Utils;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Net.NetworkInformation;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.Assertions;
|
using UnityEngine.Assertions;
|
||||||
|
|
||||||
namespace Obfuz.Data
|
namespace Obfuz.Data
|
||||||
{
|
{
|
||||||
public class ModuleConstFieldAllocator : IGroupByModuleEntity
|
public class ConstFieldAllocator : GroupByModuleEntityBase
|
||||||
{
|
{
|
||||||
private ModuleDef _module;
|
|
||||||
private readonly EncryptionScopeProvider _encryptionScopeProvider;
|
|
||||||
private readonly RvaDataAllocator _rvaDataAllocator;
|
|
||||||
private readonly GroupByModuleEntityManager _moduleEntityManager;
|
|
||||||
private EncryptionScopeInfo _encryptionScope;
|
|
||||||
private RandomCreator _randomCreator;
|
private RandomCreator _randomCreator;
|
||||||
private IEncryptor _encryptor;
|
private IEncryptor _encryptor;
|
||||||
|
|
||||||
|
@ -62,19 +52,14 @@ namespace Obfuz.Data
|
||||||
private bool _done;
|
private bool _done;
|
||||||
|
|
||||||
|
|
||||||
public ModuleConstFieldAllocator(EncryptionScopeProvider encryptionScopeProvider, RvaDataAllocator rvaDataAllocator, GroupByModuleEntityManager moduleEntityManager)
|
public ConstFieldAllocator()
|
||||||
{
|
{
|
||||||
_encryptionScopeProvider = encryptionScopeProvider;
|
|
||||||
_rvaDataAllocator = rvaDataAllocator;
|
|
||||||
_moduleEntityManager = moduleEntityManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Init(ModuleDef mod)
|
public override void Init()
|
||||||
{
|
{
|
||||||
_module = mod;
|
_randomCreator = EncryptionScope.localRandomCreator;
|
||||||
_encryptionScope = _encryptionScopeProvider.GetScope(mod);
|
_encryptor = EncryptionScope.encryptor;
|
||||||
_randomCreator = _encryptionScope.localRandomCreator;
|
|
||||||
_encryptor = _encryptionScope.encryptor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const int maxFieldCount = 1000;
|
const int maxFieldCount = 1000;
|
||||||
|
@ -82,34 +67,37 @@ namespace Obfuz.Data
|
||||||
|
|
||||||
private TypeSig GetTypeSigOfValue(object value)
|
private TypeSig GetTypeSigOfValue(object value)
|
||||||
{
|
{
|
||||||
|
ModuleDef mod = Module;
|
||||||
if (value is int)
|
if (value is int)
|
||||||
return _module.CorLibTypes.Int32;
|
return mod.CorLibTypes.Int32;
|
||||||
if (value is long)
|
if (value is long)
|
||||||
return _module.CorLibTypes.Int64;
|
return mod.CorLibTypes.Int64;
|
||||||
if (value is float)
|
if (value is float)
|
||||||
return _module.CorLibTypes.Single;
|
return mod.CorLibTypes.Single;
|
||||||
if (value is double)
|
if (value is double)
|
||||||
return _module.CorLibTypes.Double;
|
return mod.CorLibTypes.Double;
|
||||||
if (value is string)
|
if (value is string)
|
||||||
return _module.CorLibTypes.String;
|
return mod.CorLibTypes.String;
|
||||||
if (value is byte[])
|
if (value is byte[])
|
||||||
return new SZArraySig(_module.CorLibTypes.Byte);
|
return new SZArraySig(mod.CorLibTypes.Byte);
|
||||||
throw new NotSupportedException($"Unsupported type: {value.GetType()}");
|
throw new NotSupportedException($"Unsupported type: {value.GetType()}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private ConstFieldInfo CreateConstFieldInfo(object value)
|
private ConstFieldInfo CreateConstFieldInfo(object value)
|
||||||
{
|
{
|
||||||
|
ModuleDef mod = Module;
|
||||||
if (_holderTypeDef == null || _holderTypeDef.Fields.Count >= maxFieldCount)
|
if (_holderTypeDef == null || _holderTypeDef.Fields.Count >= maxFieldCount)
|
||||||
{
|
{
|
||||||
_module.EnableTypeDefFindCache = false;
|
using (var scope = new DisableTypeDefFindCacheScope(mod))
|
||||||
ITypeDefOrRef objectTypeRef = _module.Import(typeof(object));
|
{
|
||||||
|
ITypeDefOrRef objectTypeRef = mod.Import(typeof(object));
|
||||||
_holderTypeDef = new TypeDefUser($"{ConstValues.ObfuzInternalSymbolNamePrefix}ConstFieldHolder${_holderTypeDefs.Count}", objectTypeRef);
|
_holderTypeDef = new TypeDefUser($"{ConstValues.ObfuzInternalSymbolNamePrefix}ConstFieldHolder${_holderTypeDefs.Count}", objectTypeRef);
|
||||||
_module.Types.Add(_holderTypeDef);
|
mod.Types.Add(_holderTypeDef);
|
||||||
_holderTypeDefs.Add(_holderTypeDef);
|
_holderTypeDefs.Add(_holderTypeDef);
|
||||||
_module.EnableTypeDefFindCache = true;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var field = new FieldDefUser($"{ConstValues.ObfuzInternalSymbolNamePrefix}RVA_Value{_holderTypeDef.Fields.Count}", new FieldSig(GetTypeSigOfValue(value)), FieldAttributes.Static | FieldAttributes.Public | FieldAttributes.InitOnly);
|
var field = new FieldDefUser($"{ConstValues.ObfuzInternalSymbolNamePrefix}RVA_Value{_holderTypeDef.Fields.Count}", new FieldSig(GetTypeSigOfValue(value)), FieldAttributes.Static | FieldAttributes.Public);
|
||||||
field.DeclaringType = _holderTypeDef;
|
field.DeclaringType = _holderTypeDef;
|
||||||
return new ConstFieldInfo
|
return new ConstFieldInfo
|
||||||
{
|
{
|
||||||
|
@ -163,41 +151,35 @@ namespace Obfuz.Data
|
||||||
return AllocateAny(value);
|
return AllocateAny(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DefaultMetadataImporter GetModuleMetadataImporter()
|
|
||||||
{
|
|
||||||
return _moduleEntityManager.GetDefaultModuleMetadataImporter(_module, _encryptionScopeProvider);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CreateCCtorOfRvaTypeDef(TypeDef type)
|
private void CreateCCtorOfRvaTypeDef(TypeDef type)
|
||||||
{
|
{
|
||||||
|
ModuleDef mod = Module;
|
||||||
var cctor = new MethodDefUser(".cctor",
|
var cctor = new MethodDefUser(".cctor",
|
||||||
MethodSig.CreateStatic(_module.CorLibTypes.Void),
|
MethodSig.CreateStatic(mod.CorLibTypes.Void),
|
||||||
MethodImplAttributes.IL | MethodImplAttributes.Managed,
|
MethodImplAttributes.IL | MethodImplAttributes.Managed,
|
||||||
MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.Private);
|
MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.Private);
|
||||||
cctor.DeclaringType = type;
|
cctor.DeclaringType = type;
|
||||||
//_rvaTypeDef.Methods.Add(cctor);
|
|
||||||
var body = new CilBody();
|
var body = new CilBody();
|
||||||
cctor.Body = body;
|
cctor.Body = body;
|
||||||
var ins = body.Instructions;
|
var ins = body.Instructions;
|
||||||
|
|
||||||
//IMethod method = _module.Import(typeof(System.Runtime.CompilerServices.RuntimeHelpers).GetMethod("InitializeArray", new[] { typeof(Array), typeof(RuntimeFieldHandle) }));
|
|
||||||
//Assert.IsNotNull(method);
|
|
||||||
|
|
||||||
|
DefaultMetadataImporter importer = this.GetDefaultModuleMetadataImporter();
|
||||||
DefaultMetadataImporter importer = GetModuleMetadataImporter();
|
RvaDataAllocator rvaDataAllocator = GetEntity<RvaDataAllocator>();
|
||||||
// TODO. obfuscate init codes
|
// TODO. obfuscate init codes
|
||||||
foreach (var field in type.Fields)
|
foreach (var field in type.Fields)
|
||||||
{
|
{
|
||||||
ConstFieldInfo constInfo = _field2Fields[field];
|
ConstFieldInfo constInfo = _field2Fields[field];
|
||||||
IRandom localRandom = _randomCreator(HashUtil.ComputePrimitiveOrStringOrBytesHashCode(constInfo.value));
|
IRandom localRandom = _randomCreator(HashUtil.ComputePrimitiveOrStringOrBytesHashCode(constInfo.value));
|
||||||
int ops = EncryptionUtil.GenerateEncryptionOpCodes(localRandom, _encryptor, 4);
|
int ops = EncryptionUtil.GenerateEncryptionOpCodes(localRandom, _encryptor, EncryptionScopeInfo.MaxEncryptionLevel, false);
|
||||||
int salt = localRandom.NextInt();
|
int salt = localRandom.NextInt();
|
||||||
switch (constInfo.value)
|
switch (constInfo.value)
|
||||||
{
|
{
|
||||||
case int i:
|
case int i:
|
||||||
{
|
{
|
||||||
int encryptedValue = _encryptor.Encrypt(i, ops, salt);
|
int encryptedValue = _encryptor.Encrypt(i, ops, salt);
|
||||||
RvaData rvaData = _rvaDataAllocator.Allocate(_module, encryptedValue);
|
RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue);
|
||||||
ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
|
ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
|
||||||
ins.Add(Instruction.CreateLdcI4(rvaData.offset));
|
ins.Add(Instruction.CreateLdcI4(rvaData.offset));
|
||||||
ins.Add(Instruction.CreateLdcI4(ops));
|
ins.Add(Instruction.CreateLdcI4(ops));
|
||||||
|
@ -208,7 +190,7 @@ namespace Obfuz.Data
|
||||||
case long l:
|
case long l:
|
||||||
{
|
{
|
||||||
long encryptedValue = _encryptor.Encrypt(l, ops, salt);
|
long encryptedValue = _encryptor.Encrypt(l, ops, salt);
|
||||||
RvaData rvaData = _rvaDataAllocator.Allocate(_module, encryptedValue);
|
RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue);
|
||||||
ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
|
ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
|
||||||
ins.Add(Instruction.CreateLdcI4(rvaData.offset));
|
ins.Add(Instruction.CreateLdcI4(rvaData.offset));
|
||||||
ins.Add(Instruction.CreateLdcI4(ops));
|
ins.Add(Instruction.CreateLdcI4(ops));
|
||||||
|
@ -219,7 +201,7 @@ namespace Obfuz.Data
|
||||||
case float f:
|
case float f:
|
||||||
{
|
{
|
||||||
float encryptedValue = _encryptor.Encrypt(f, ops, salt);
|
float encryptedValue = _encryptor.Encrypt(f, ops, salt);
|
||||||
RvaData rvaData = _rvaDataAllocator.Allocate(_module, encryptedValue);
|
RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue);
|
||||||
ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
|
ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
|
||||||
ins.Add(Instruction.CreateLdcI4(rvaData.offset));
|
ins.Add(Instruction.CreateLdcI4(rvaData.offset));
|
||||||
ins.Add(Instruction.CreateLdcI4(ops));
|
ins.Add(Instruction.CreateLdcI4(ops));
|
||||||
|
@ -230,7 +212,7 @@ namespace Obfuz.Data
|
||||||
case double d:
|
case double d:
|
||||||
{
|
{
|
||||||
double encryptedValue = _encryptor.Encrypt(d, ops, salt);
|
double encryptedValue = _encryptor.Encrypt(d, ops, salt);
|
||||||
RvaData rvaData = _rvaDataAllocator.Allocate(_module, encryptedValue);
|
RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue);
|
||||||
ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
|
ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
|
||||||
ins.Add(Instruction.CreateLdcI4(rvaData.offset));
|
ins.Add(Instruction.CreateLdcI4(rvaData.offset));
|
||||||
ins.Add(Instruction.CreateLdcI4(ops));
|
ins.Add(Instruction.CreateLdcI4(ops));
|
||||||
|
@ -241,7 +223,7 @@ namespace Obfuz.Data
|
||||||
case string s:
|
case string s:
|
||||||
{
|
{
|
||||||
byte[] encryptedValue = _encryptor.Encrypt(s, ops, salt);
|
byte[] encryptedValue = _encryptor.Encrypt(s, ops, salt);
|
||||||
RvaData rvaData = _rvaDataAllocator.Allocate(_module, encryptedValue);
|
RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue);
|
||||||
ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
|
ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
|
||||||
ins.Add(Instruction.CreateLdcI4(rvaData.offset));
|
ins.Add(Instruction.CreateLdcI4(rvaData.offset));
|
||||||
Assert.AreEqual(encryptedValue.Length, rvaData.size);
|
Assert.AreEqual(encryptedValue.Length, rvaData.size);
|
||||||
|
@ -255,7 +237,7 @@ namespace Obfuz.Data
|
||||||
{
|
{
|
||||||
byte[] encryptedValue = _encryptor.Encrypt(bs, 0, bs.Length, ops, salt);
|
byte[] encryptedValue = _encryptor.Encrypt(bs, 0, bs.Length, ops, salt);
|
||||||
Assert.AreEqual(encryptedValue.Length, bs.Length);
|
Assert.AreEqual(encryptedValue.Length, bs.Length);
|
||||||
RvaData rvaData = _rvaDataAllocator.Allocate(_module, encryptedValue);
|
RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue);
|
||||||
ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
|
ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
|
||||||
ins.Add(Instruction.CreateLdcI4(rvaData.offset));
|
ins.Add(Instruction.CreateLdcI4(rvaData.offset));
|
||||||
ins.Add(Instruction.CreateLdcI4(bs.Length));
|
ins.Add(Instruction.CreateLdcI4(bs.Length));
|
||||||
|
@ -271,7 +253,7 @@ namespace Obfuz.Data
|
||||||
ins.Add(Instruction.Create(OpCodes.Ret));
|
ins.Add(Instruction.Create(OpCodes.Ret));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Done()
|
public override void Done()
|
||||||
{
|
{
|
||||||
if (_done)
|
if (_done)
|
||||||
{
|
{
|
||||||
|
@ -284,61 +266,4 @@ namespace Obfuz.Data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ConstFieldAllocator
|
|
||||||
{
|
|
||||||
private readonly EncryptionScopeProvider _encryptionScopeProvider;
|
|
||||||
private readonly RvaDataAllocator _rvaDataAllocator;
|
|
||||||
private readonly GroupByModuleEntityManager _moduleEntityManager;
|
|
||||||
|
|
||||||
public ConstFieldAllocator(EncryptionScopeProvider encryptionScopeProvider, RvaDataAllocator rvaDataAllocator, GroupByModuleEntityManager moduleEntityManager)
|
|
||||||
{
|
|
||||||
_encryptionScopeProvider = encryptionScopeProvider;
|
|
||||||
_rvaDataAllocator = rvaDataAllocator;
|
|
||||||
_moduleEntityManager = moduleEntityManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ModuleConstFieldAllocator GetModuleAllocator(ModuleDef mod)
|
|
||||||
{
|
|
||||||
return _moduleEntityManager.GetEntity<ModuleConstFieldAllocator>(mod, () => new ModuleConstFieldAllocator(_encryptionScopeProvider, _rvaDataAllocator, _moduleEntityManager));
|
|
||||||
}
|
|
||||||
|
|
||||||
public FieldDef Allocate(ModuleDef mod, int value)
|
|
||||||
{
|
|
||||||
return GetModuleAllocator(mod).Allocate(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public FieldDef Allocate(ModuleDef mod, long value)
|
|
||||||
{
|
|
||||||
return GetModuleAllocator(mod).Allocate(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public FieldDef Allocate(ModuleDef mod, float value)
|
|
||||||
{
|
|
||||||
return GetModuleAllocator(mod).Allocate(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public FieldDef Allocate(ModuleDef mod, double value)
|
|
||||||
{
|
|
||||||
return GetModuleAllocator(mod).Allocate(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public FieldDef Allocate(ModuleDef mod, byte[] value)
|
|
||||||
{
|
|
||||||
return GetModuleAllocator(mod).Allocate(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public FieldDef Allocate(ModuleDef mod, string value)
|
|
||||||
{
|
|
||||||
return GetModuleAllocator(mod).Allocate(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Done()
|
|
||||||
{
|
|
||||||
foreach (var moduleAllocator in _moduleEntityManager.GetEntities<ModuleConstFieldAllocator>())
|
|
||||||
{
|
|
||||||
moduleAllocator.Done();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -0,0 +1,323 @@
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,9 +3,6 @@ using dnlib.DotNet.Emit;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.Remoting.Messaging;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Obfuz.Emit
|
namespace Obfuz.Emit
|
||||||
{
|
{
|
||||||
|
@ -41,13 +38,20 @@ namespace Obfuz.Emit
|
||||||
|
|
||||||
public IList<BasicBlock> Blocks => _blocks;
|
public IList<BasicBlock> Blocks => _blocks;
|
||||||
|
|
||||||
public BasicBlockCollection(MethodDef method)
|
public BasicBlockCollection(MethodDef method, bool computeInLoop)
|
||||||
{
|
{
|
||||||
_method = method;
|
_method = method;
|
||||||
HashSet<Instruction> splitPoints = BuildSplitPoint(method);
|
HashSet<Instruction> splitPoints = BuildSplitPoint(method);
|
||||||
BuildBasicBlocks(method, splitPoints);
|
BuildBasicBlocks(method, splitPoints);
|
||||||
BuildInOutGraph(method);
|
BuildInOutGraph(method);
|
||||||
|
if (computeInLoop)
|
||||||
|
{
|
||||||
|
ComputeBlocksInLoop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ComputeBlocksInLoop()
|
||||||
|
{
|
||||||
var loopBlocks = FindLoopBlocks(_blocks);
|
var loopBlocks = FindLoopBlocks(_blocks);
|
||||||
foreach (var block in loopBlocks)
|
foreach (var block in loopBlocks)
|
||||||
{
|
{
|
||||||
|
@ -100,6 +104,7 @@ namespace Obfuz.Emit
|
||||||
{
|
{
|
||||||
splitPoints.Add(nextInst);
|
splitPoints.Add(nextInst);
|
||||||
}
|
}
|
||||||
|
splitPoints.Add((Instruction)curInst.Operand);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FlowControl.Cond_Branch:
|
case FlowControl.Cond_Branch:
|
||||||
|
@ -207,11 +212,21 @@ namespace Obfuz.Emit
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case FlowControl.Call:
|
||||||
|
case FlowControl.Next:
|
||||||
|
{
|
||||||
|
if (nextBlock != null)
|
||||||
|
{
|
||||||
|
curBlock.AddTargetBasicBlock(nextBlock);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case FlowControl.Return:
|
case FlowControl.Return:
|
||||||
case FlowControl.Throw:
|
case FlowControl.Throw:
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
default: throw new NotSupportedException($"Unsupported flow control: {lastInst.OpCode.FlowControl} in method {method.FullName}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,423 @@
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
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>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 639006a739675484884778c298eebdc4
|
guid: 6e9557733f180764692756653eb60f88
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,5 @@
|
||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 639006a739675484884778c298eebdc4
|
guid: f25425a3077f6db41873dee4223d0abc
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
|
@ -0,0 +1,89 @@
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 406c63e9d464ca544ac337bc8fcce30e
|
guid: 955da34fbde179641a94108ec53405ce
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
|
@ -1,8 +1,4 @@
|
||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Obfuz.EncryptionVM.Instructions
|
namespace Obfuz.EncryptionVM.Instructions
|
||||||
{
|
{
|
|
@ -1,8 +1,4 @@
|
||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Obfuz.EncryptionVM.Instructions
|
namespace Obfuz.EncryptionVM.Instructions
|
||||||
{
|
{
|
|
@ -1,8 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Obfuz.EncryptionVM.Instructions
|
namespace Obfuz.EncryptionVM.Instructions
|
||||||
{
|
{
|
|
@ -1,5 +1,4 @@
|
||||||
using NUnit.Framework;
|
using Obfuz.Utils;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Obfuz.EncryptionVM.Instructions
|
namespace Obfuz.EncryptionVM.Instructions
|
||||||
|
@ -14,31 +13,14 @@ namespace Obfuz.EncryptionVM.Instructions
|
||||||
{
|
{
|
||||||
_multiValue = addValue;
|
_multiValue = addValue;
|
||||||
_opKeyIndex = opKeyIndex;
|
_opKeyIndex = opKeyIndex;
|
||||||
_revertMultiValue = (int)ModInverseOdd((uint)addValue);
|
_revertMultiValue = MathUtil.ModInverse32(addValue);
|
||||||
Verify();
|
Verify();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Verify()
|
private void Verify()
|
||||||
{
|
{
|
||||||
int a = 1122334;
|
int a = 1122334;
|
||||||
Assert.AreEqual(a, a * _multiValue * _revertMultiValue);
|
UnityEngine.Assertions.Assert.AreEqual(a, a * _multiValue * _revertMultiValue);
|
||||||
}
|
|
||||||
|
|
||||||
public static uint ModInverseOdd(uint a)
|
|
||||||
{
|
|
||||||
if (a % 2 == 0)
|
|
||||||
throw new ArgumentException("Input must be an odd number.", nameof(a));
|
|
||||||
|
|
||||||
uint x = 1; // 初始解:x₀ = 1 (mod 2)
|
|
||||||
for (int i = 0; i < 5; i++) // 迭代5次(2^1 → 2^32)
|
|
||||||
{
|
|
||||||
int shift = 2 << i; // 当前模数为 2^(2^(i+1))
|
|
||||||
ulong mod = 1UL << shift; // 使用 ulong 避免溢出
|
|
||||||
ulong ax = (ulong)a * x; // 计算 a*x(64位避免截断)
|
|
||||||
ulong term = (2 - ax) % mod;
|
|
||||||
x = (uint)((x * term) % mod); // 更新 x,结果截断为 uint
|
|
||||||
}
|
|
||||||
return x; // 最终解为 x₅ mod 2^32
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int Encrypt(int value, int[] secretKey, int salt)
|
public override int Encrypt(int value, int[] secretKey, int salt)
|
|
@ -1,8 +1,5 @@
|
||||||
using System;
|
using Obfuz.Utils;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Obfuz.EncryptionVM.Instructions
|
namespace Obfuz.EncryptionVM.Instructions
|
||||||
{
|
{
|
||||||
|
@ -21,7 +18,7 @@ namespace Obfuz.EncryptionVM.Instructions
|
||||||
public MultipleRotateXorInstruction(int multipleValue, int index1, int rotateBitNum, int xorValue)
|
public MultipleRotateXorInstruction(int multipleValue, int index1, int rotateBitNum, int xorValue)
|
||||||
{
|
{
|
||||||
_multipleValue = multipleValue;
|
_multipleValue = multipleValue;
|
||||||
_revertMultipleValue = (int)MultipleInstruction.ModInverseOdd((uint)multipleValue);
|
_revertMultipleValue = MathUtil.ModInverse32(multipleValue);
|
||||||
_index1 = index1;
|
_index1 = index1;
|
||||||
_rotateBitNum = rotateBitNum;
|
_rotateBitNum = rotateBitNum;
|
||||||
_xorValue = xorValue;
|
_xorValue = xorValue;
|
|
@ -1,8 +1,5 @@
|
||||||
using System;
|
using Obfuz.Utils;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Obfuz.EncryptionVM.Instructions
|
namespace Obfuz.EncryptionVM.Instructions
|
||||||
{
|
{
|
||||||
|
@ -21,7 +18,7 @@ namespace Obfuz.EncryptionVM.Instructions
|
||||||
public MultipleXorRotateInstruction(int multipleValue, int index1, int xorValue, int rotateBitNum)
|
public MultipleXorRotateInstruction(int multipleValue, int index1, int xorValue, int rotateBitNum)
|
||||||
{
|
{
|
||||||
_multipleValue = multipleValue;
|
_multipleValue = multipleValue;
|
||||||
_revertMultipleValue = (int)MultipleInstruction.ModInverseOdd((uint)multipleValue);
|
_revertMultipleValue = MathUtil.ModInverse32(multipleValue);
|
||||||
_index1 = index1;
|
_index1 = index1;
|
||||||
_rotateBitNum = rotateBitNum;
|
_rotateBitNum = rotateBitNum;
|
||||||
_xorValue = xorValue;
|
_xorValue = xorValue;
|
|
@ -1,8 +1,4 @@
|
||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Obfuz.EncryptionVM.Instructions
|
namespace Obfuz.EncryptionVM.Instructions
|
||||||
{
|
{
|
|
@ -1,8 +1,5 @@
|
||||||
using System;
|
using Obfuz.Utils;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Obfuz.EncryptionVM.Instructions
|
namespace Obfuz.EncryptionVM.Instructions
|
||||||
{
|
{
|
||||||
|
@ -21,7 +18,7 @@ namespace Obfuz.EncryptionVM.Instructions
|
||||||
public XorMultipleRotateInstruction(int xorValue, int multipleValue, int index1, int rotateBitNum)
|
public XorMultipleRotateInstruction(int xorValue, int multipleValue, int index1, int rotateBitNum)
|
||||||
{
|
{
|
||||||
_multipleValue = multipleValue;
|
_multipleValue = multipleValue;
|
||||||
_revertMultipleValue = (int)MultipleInstruction.ModInverseOdd((uint)multipleValue);
|
_revertMultipleValue = MathUtil.ModInverse32(multipleValue);
|
||||||
_index1 = index1;
|
_index1 = index1;
|
||||||
_rotateBitNum = rotateBitNum;
|
_rotateBitNum = rotateBitNum;
|
||||||
_xorValue = xorValue;
|
_xorValue = xorValue;
|
|
@ -1,11 +1,8 @@
|
||||||
using Obfuz.Utils;
|
using Obfuz.Utils;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace Obfuz.EncryptionVM
|
namespace Obfuz.EncryptionVM
|
||||||
|
@ -55,7 +52,6 @@ namespace Obfuz.EncryptionVM
|
||||||
|
|
||||||
File.WriteAllText(outputFile, code, Encoding.UTF8);
|
File.WriteAllText(outputFile, code, Encoding.UTF8);
|
||||||
Debug.Log($"Generate EncryptionVM code to {outputFile}");
|
Debug.Log($"Generate EncryptionVM code to {outputFile}");
|
||||||
UnityEditor.AssetDatabase.Refresh();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GenerateCode()
|
private string GenerateCode()
|
|
@ -1,10 +1,7 @@
|
||||||
using NUnit.Framework;
|
using Obfuz.EncryptionVM.Instructions;
|
||||||
using Obfuz.EncryptionVM.Instructions;
|
|
||||||
using Obfuz.Utils;
|
using Obfuz.Utils;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using UnityEngine.Assertions;
|
|
||||||
using UnityEngine.UIElements;
|
|
||||||
|
|
||||||
namespace Obfuz.EncryptionVM
|
namespace Obfuz.EncryptionVM
|
||||||
{
|
{
|
|
@ -1,12 +1,6 @@
|
||||||
using Obfuz.Utils;
|
using Obfuz.Utils;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq.Expressions;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Text;
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.Assertions;
|
using UnityEngine.Assertions;
|
||||||
using UnityEngine.UIElements;
|
|
||||||
|
|
||||||
namespace Obfuz.EncryptionVM
|
namespace Obfuz.EncryptionVM
|
||||||
{
|
{
|
||||||
|
@ -47,7 +41,7 @@ namespace Obfuz.EncryptionVM
|
||||||
byte[] strBytes = Encrypt("abcdef", ops, salt);
|
byte[] strBytes = Encrypt("abcdef", ops, salt);
|
||||||
Assert.AreEqual("abcdef", DecryptString(strBytes, 0, strBytes.Length, ops, salt));
|
Assert.AreEqual("abcdef", DecryptString(strBytes, 0, strBytes.Length, ops, salt));
|
||||||
var arr = new byte[100];
|
var arr = new byte[100];
|
||||||
for (int i = 0; i < arr.Length ; i++)
|
for (int i = 0; i < arr.Length; i++)
|
||||||
{
|
{
|
||||||
arr[i] = (byte)i;
|
arr[i] = (byte)i;
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 5be12685e3d38a24ab47ccfde4f424a1
|
guid: f47f2abd9eb7ba8469ba5cb1bb085d33
|
||||||
folderAsset: yes
|
folderAsset: yes
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
|
@ -0,0 +1,117 @@
|
||||||
|
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}}}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 406c63e9d464ca544ac337bc8fcce30e
|
guid: 327cb4a465ff23944a5fea30bf3beeeb
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
|
@ -0,0 +1,88 @@
|
||||||
|
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.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ff64fd1e6f7b8874db5a5228fab159f9
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -0,0 +1,21 @@
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 74a17802b5aab2e40a3c89e0ddbcec0d
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -0,0 +1,106 @@
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: bae18fd49482f00439d37f28a6a78d9b
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -0,0 +1,157 @@
|
||||||
|
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}}}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5071c4b9c7f5aef409f3e7fdb45ecd8d
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -1,9 +1,4 @@
|
||||||
using Obfuz.ObfusPasses;
|
using Obfuz.ObfusPasses;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Obfuz
|
namespace Obfuz
|
||||||
{
|
{
|
|
@ -1,54 +1,20 @@
|
||||||
using dnlib.DotNet.Emit;
|
using dnlib.DotNet;
|
||||||
using dnlib.DotNet;
|
using dnlib.DotNet.Emit;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using Obfuz.Emit;
|
using Obfuz.Emit;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Obfuz.ObfusPasses
|
namespace Obfuz.ObfusPasses
|
||||||
{
|
{
|
||||||
public abstract class BasicBlockObfuscationPassBase : ObfuscationPassBase
|
public abstract class BasicBlockObfuscationPassBase : ObfuscationMethodPassBase
|
||||||
{
|
{
|
||||||
protected abstract bool NeedObfuscateMethod(MethodDef method);
|
protected virtual bool ComputeBlockInLoop => true;
|
||||||
|
|
||||||
public override void Process()
|
|
||||||
{
|
|
||||||
var ctx = ObfuscationPassContext.Current;
|
|
||||||
ObfuscationMethodWhitelist whiteList = ctx.whiteList;
|
|
||||||
ConfigurablePassPolicy passPolicy = ctx.passPolicy;
|
|
||||||
foreach (ModuleDef mod in ctx.modulesToObfuscate)
|
|
||||||
{
|
|
||||||
if (whiteList.IsInWhiteList(mod) || !Support(passPolicy.GetAssemblyObfuscationPasses(mod)))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// ToArray to avoid modify list exception
|
|
||||||
foreach (TypeDef type in mod.GetTypes().ToArray())
|
|
||||||
{
|
|
||||||
if (whiteList.IsInWhiteList(type) || !Support(passPolicy.GetTypeObfuscationPasses(type)))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// ToArray to avoid modify list exception
|
|
||||||
foreach (MethodDef method in type.Methods.ToArray())
|
|
||||||
{
|
|
||||||
if (!method.HasBody || ctx.whiteList.IsInWhiteList(method) || !Support(passPolicy.GetMethodObfuscationPasses(method)) || !NeedObfuscateMethod(method))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// TODO if isGeneratedBy Obfuscator, continue
|
|
||||||
ObfuscateData(method);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected abstract bool TryObfuscateInstruction(MethodDef callingMethod, Instruction inst, BasicBlock block, int instructionIndex,
|
protected abstract bool TryObfuscateInstruction(MethodDef callingMethod, Instruction inst, BasicBlock block, int instructionIndex,
|
||||||
IList<Instruction> globalInstructions, List<Instruction> outputInstructions, List<Instruction> totalFinalInstructions);
|
IList<Instruction> globalInstructions, List<Instruction> outputInstructions, List<Instruction> totalFinalInstructions);
|
||||||
|
|
||||||
private void ObfuscateData(MethodDef method)
|
protected override void ObfuscateData(MethodDef method)
|
||||||
{
|
{
|
||||||
BasicBlockCollection bbc = new BasicBlockCollection(method);
|
BasicBlockCollection bbc = new BasicBlockCollection(method, ComputeBlockInLoop);
|
||||||
|
|
||||||
IList<Instruction> instructions = method.Body.Instructions;
|
IList<Instruction> instructions = method.Body.Instructions;
|
||||||
|
|
|
@ -0,0 +1,166 @@
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,13 +1,10 @@
|
||||||
using dnlib.DotNet;
|
using dnlib.DotNet;
|
||||||
using Obfuz.Conf;
|
using Obfuz.Conf;
|
||||||
|
using Obfuz.Settings;
|
||||||
using Obfuz.Utils;
|
using Obfuz.Utils;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace Obfuz.ObfusPasses.CallObfus
|
namespace Obfuz.ObfusPasses.CallObfus
|
||||||
{
|
{
|
||||||
|
@ -38,29 +35,12 @@ namespace Obfuz.ObfusPasses.CallObfus
|
||||||
|
|
||||||
class ObfuscationRule : IRule<ObfuscationRule>
|
class ObfuscationRule : IRule<ObfuscationRule>
|
||||||
{
|
{
|
||||||
public bool? disableObfuscation;
|
public ObfuscationLevel? obfuscationLevel;
|
||||||
public bool? obfuscateCallInLoop;
|
|
||||||
public bool? cacheCallIndexInLoop;
|
|
||||||
public bool? cacheCallIndexNotLoop;
|
|
||||||
|
|
||||||
public void InheritParent(ObfuscationRule parentRule)
|
public void InheritParent(ObfuscationRule parentRule)
|
||||||
{
|
{
|
||||||
if (disableObfuscation == null)
|
if (obfuscationLevel == null)
|
||||||
{
|
obfuscationLevel = parentRule.obfuscationLevel;
|
||||||
disableObfuscation = parentRule.disableObfuscation;
|
|
||||||
}
|
|
||||||
if (obfuscateCallInLoop == null)
|
|
||||||
{
|
|
||||||
obfuscateCallInLoop = parentRule.obfuscateCallInLoop;
|
|
||||||
}
|
|
||||||
if (cacheCallIndexInLoop == null)
|
|
||||||
{
|
|
||||||
cacheCallIndexInLoop = parentRule.cacheCallIndexInLoop;
|
|
||||||
}
|
|
||||||
if (cacheCallIndexNotLoop == null)
|
|
||||||
{
|
|
||||||
cacheCallIndexNotLoop = parentRule.cacheCallIndexNotLoop;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,10 +59,7 @@ namespace Obfuz.ObfusPasses.CallObfus
|
||||||
|
|
||||||
private static readonly ObfuscationRule s_default = new ObfuscationRule()
|
private static readonly ObfuscationRule s_default = new ObfuscationRule()
|
||||||
{
|
{
|
||||||
disableObfuscation = false,
|
obfuscationLevel = ObfuscationLevel.Basic,
|
||||||
obfuscateCallInLoop = true,
|
|
||||||
cacheCallIndexInLoop = true,
|
|
||||||
cacheCallIndexNotLoop = false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private readonly XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule> _configParser;
|
private readonly XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule> _configParser;
|
||||||
|
@ -90,11 +67,12 @@ namespace Obfuz.ObfusPasses.CallObfus
|
||||||
private ObfuscationRule _global;
|
private ObfuscationRule _global;
|
||||||
private readonly List<WhiteListAssembly> _whiteListAssemblies = new List<WhiteListAssembly>();
|
private readonly List<WhiteListAssembly> _whiteListAssemblies = new List<WhiteListAssembly>();
|
||||||
|
|
||||||
private readonly Dictionary<IMethod, bool> _whiteListMethodCache = new Dictionary<IMethod, bool>(MethodEqualityComparer.CompareDeclaringTypes);
|
private readonly CachedDictionary<IMethod, bool> _whiteListMethodCache;
|
||||||
private readonly Dictionary<MethodDef, ObfuscationRule> _methodRuleCache = new Dictionary<MethodDef, ObfuscationRule>();
|
private readonly Dictionary<MethodDef, ObfuscationRule> _methodRuleCache = new Dictionary<MethodDef, ObfuscationRule>();
|
||||||
|
|
||||||
public ConfigurableObfuscationPolicy(List<string> toObfuscatedAssemblyNames, List<string> xmlConfigFiles)
|
public ConfigurableObfuscationPolicy(List<string> toObfuscatedAssemblyNames, List<string> xmlConfigFiles)
|
||||||
{
|
{
|
||||||
|
_whiteListMethodCache = new CachedDictionary<IMethod, bool>(MethodEqualityComparer.CompareDeclaringTypes, this.ComputeIsInWhiteList);
|
||||||
_configParser = new XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule>(toObfuscatedAssemblyNames,
|
_configParser = new XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule>(toObfuscatedAssemblyNames,
|
||||||
ParseObfuscationRule, ParseGlobalElement);
|
ParseObfuscationRule, ParseGlobalElement);
|
||||||
LoadConfigs(xmlConfigFiles);
|
LoadConfigs(xmlConfigFiles);
|
||||||
|
@ -150,21 +128,9 @@ namespace Obfuz.ObfusPasses.CallObfus
|
||||||
private ObfuscationRule ParseObfuscationRule(string configFile, XmlElement ele)
|
private ObfuscationRule ParseObfuscationRule(string configFile, XmlElement ele)
|
||||||
{
|
{
|
||||||
var rule = new ObfuscationRule();
|
var rule = new ObfuscationRule();
|
||||||
if (ele.HasAttribute("disableObfuscation"))
|
if (ele.HasAttribute("obfuscationLevel"))
|
||||||
{
|
{
|
||||||
rule.disableObfuscation = ConfigUtil.ParseBool(ele.GetAttribute("disableObfuscation"));
|
rule.obfuscationLevel = ConfigUtil.ParseObfuscationLevel(ele.GetAttribute("obfuscationLevel"));
|
||||||
}
|
|
||||||
if (ele.HasAttribute("obfuscateCallInLoop"))
|
|
||||||
{
|
|
||||||
rule.obfuscateCallInLoop = ConfigUtil.ParseBool(ele.GetAttribute("obfuscateCallInLoop"));
|
|
||||||
}
|
|
||||||
if (ele.HasAttribute("cacheCallIndexInLoop"))
|
|
||||||
{
|
|
||||||
rule.cacheCallIndexInLoop = ConfigUtil.ParseBool(ele.GetAttribute("cacheCallIndexInLoop"));
|
|
||||||
}
|
|
||||||
if (ele.HasAttribute("cacheCallIndexNotLoop"))
|
|
||||||
{
|
|
||||||
rule.cacheCallIndexNotLoop = ConfigUtil.ParseBool(ele.GetAttribute("cacheCallIndexNotLoop"));
|
|
||||||
}
|
}
|
||||||
return rule;
|
return rule;
|
||||||
}
|
}
|
||||||
|
@ -256,7 +222,7 @@ namespace Obfuz.ObfusPasses.CallObfus
|
||||||
{
|
{
|
||||||
if (!_methodRuleCache.TryGetValue(method, out var rule))
|
if (!_methodRuleCache.TryGetValue(method, out var rule))
|
||||||
{
|
{
|
||||||
rule = _configParser.GetMethodRule(method, s_default);
|
rule = _configParser.GetMethodRule(method, _global);
|
||||||
_methodRuleCache[method] = rule;
|
_methodRuleCache[method] = rule;
|
||||||
}
|
}
|
||||||
return rule;
|
return rule;
|
||||||
|
@ -265,44 +231,7 @@ namespace Obfuz.ObfusPasses.CallObfus
|
||||||
public override bool NeedObfuscateCallInMethod(MethodDef method)
|
public override bool NeedObfuscateCallInMethod(MethodDef method)
|
||||||
{
|
{
|
||||||
ObfuscationRule rule = GetMethodObfuscationRule(method);
|
ObfuscationRule rule = GetMethodObfuscationRule(method);
|
||||||
return rule.disableObfuscation != true;
|
return rule.obfuscationLevel != null && rule.obfuscationLevel.Value >= ObfuscationLevel.Basic;
|
||||||
}
|
|
||||||
|
|
||||||
public override ObfuscationCachePolicy GetMethodObfuscationCachePolicy(MethodDef method)
|
|
||||||
{
|
|
||||||
ObfuscationRule rule = GetMethodObfuscationRule(method);
|
|
||||||
return new ObfuscationCachePolicy()
|
|
||||||
{
|
|
||||||
cacheInLoop = rule.cacheCallIndexInLoop.Value,
|
|
||||||
cacheNotInLoop = rule.cacheCallIndexNotLoop.Value,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private bool IsSpecialNotObfuscatedMethod(TypeDef typeDef, IMethod method)
|
|
||||||
{
|
|
||||||
if (typeDef.IsDelegate || typeDef.IsEnum)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
string methodName = method.Name;
|
|
||||||
|
|
||||||
// doesn't proxy call if the method is a constructor
|
|
||||||
if (methodName == ".ctor")
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeDef.Name == "EncryptionService`1")
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// special handle
|
|
||||||
// don't proxy call for List<T>.Enumerator GetEnumerator()
|
|
||||||
if (methodName == "GetEnumerator")
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ComputeIsInWhiteList(IMethod calledMethod)
|
private bool ComputeIsInWhiteList(IMethod calledMethod)
|
||||||
|
@ -330,11 +259,6 @@ namespace Obfuz.ObfusPasses.CallObfus
|
||||||
|
|
||||||
TypeDef typeDef = declaringType.ResolveTypeDef();
|
TypeDef typeDef = declaringType.ResolveTypeDef();
|
||||||
|
|
||||||
if (IsSpecialNotObfuscatedMethod(typeDef, calledMethod))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
string assName = typeDef.Module.Assembly.Name;
|
string assName = typeDef.Module.Assembly.Name;
|
||||||
string typeFullName = typeDef.FullName;
|
string typeFullName = typeDef.FullName;
|
||||||
string methodName = calledMethod.Name;
|
string methodName = calledMethod.Name;
|
||||||
|
@ -364,44 +288,9 @@ namespace Obfuz.ObfusPasses.CallObfus
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsInWhiteList(IMethod method)
|
public override bool NeedObfuscateCalledMethod(MethodDef callerMethod, IMethod calledMethod, bool callVir)
|
||||||
{
|
{
|
||||||
if (!_whiteListMethodCache.TryGetValue(method, out var isWhiteList))
|
if (_whiteListMethodCache.GetValue(calledMethod))
|
||||||
{
|
|
||||||
isWhiteList = ComputeIsInWhiteList(method);
|
|
||||||
_whiteListMethodCache.Add(method, isWhiteList);
|
|
||||||
}
|
|
||||||
return isWhiteList;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsTypeSelfAndParentPublic(TypeDef type)
|
|
||||||
{
|
|
||||||
if (type.DeclaringType != null && !IsTypeSelfAndParentPublic(type.DeclaringType))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return type.IsPublic;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool NeedObfuscateCalledMethod(MethodDef callerMethod, IMethod calledMethod, bool callVir, bool currentInLoop)
|
|
||||||
{
|
|
||||||
if (IsInWhiteList(calledMethod))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// mono has more strict access control, calls non-public method will raise exception.
|
|
||||||
if (PlatformUtil.IsMonoBackend())
|
|
||||||
{
|
|
||||||
MethodDef calledMethodDef = calledMethod.ResolveMethodDef();
|
|
||||||
if (calledMethodDef != null && (!calledMethodDef.IsPublic || !IsTypeSelfAndParentPublic(calledMethodDef.DeclaringType)))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ObfuscationRule rule = GetMethodObfuscationRule(callerMethod);
|
|
||||||
if (currentInLoop && rule.obfuscateCallInLoop == false)
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
|
@ -0,0 +1,265 @@
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 02761bacbed8a8b489ae3e7f49f0f84a
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -0,0 +1,81 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1102cd9f03de27c4b9fde3d6a87277c7
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -2,17 +2,17 @@
|
||||||
using dnlib.DotNet.Emit;
|
using dnlib.DotNet.Emit;
|
||||||
using Obfuz.Editor;
|
using Obfuz.Editor;
|
||||||
using Obfuz.Emit;
|
using Obfuz.Emit;
|
||||||
|
using Obfuz.Settings;
|
||||||
using Obfuz.Utils;
|
using Obfuz.Utils;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using MethodImplAttributes = dnlib.DotNet.MethodImplAttributes;
|
using MethodImplAttributes = dnlib.DotNet.MethodImplAttributes;
|
||||||
using TypeAttributes = dnlib.DotNet.TypeAttributes;
|
using TypeAttributes = dnlib.DotNet.TypeAttributes;
|
||||||
|
|
||||||
namespace Obfuz.ObfusPasses.CallObfus
|
namespace Obfuz.ObfusPasses.CallObfus
|
||||||
{
|
{
|
||||||
|
|
||||||
public struct ProxyCallMethodData
|
public struct ProxyCallMethodData
|
||||||
{
|
{
|
||||||
public readonly MethodDef proxyMethod;
|
public readonly MethodDef proxyMethod;
|
||||||
|
@ -31,38 +31,11 @@ namespace Obfuz.ObfusPasses.CallObfus
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ModuleCallProxyAllocator : IGroupByModuleEntity
|
class ModuleDispatchProxyAllocator : GroupByModuleEntityBase
|
||||||
{
|
{
|
||||||
private ModuleDef _module;
|
|
||||||
private readonly EncryptionScopeProvider _encryptionScopeProvider;
|
|
||||||
private readonly int _encryptionLevel;
|
|
||||||
|
|
||||||
private EncryptionScopeInfo _encryptionScope;
|
|
||||||
private bool _done;
|
private bool _done;
|
||||||
|
private CallObfuscationSettingsFacade _settings;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MethodProxyInfo
|
class MethodProxyInfo
|
||||||
{
|
{
|
||||||
|
@ -76,11 +49,9 @@ namespace Obfuz.ObfusPasses.CallObfus
|
||||||
|
|
||||||
private readonly Dictionary<MethodKey, MethodProxyInfo> _methodProxys = new Dictionary<MethodKey, MethodProxyInfo>();
|
private readonly Dictionary<MethodKey, MethodProxyInfo> _methodProxys = new Dictionary<MethodKey, MethodProxyInfo>();
|
||||||
|
|
||||||
|
|
||||||
const int maxProxyMethodPerDispatchMethod = 1000;
|
|
||||||
|
|
||||||
class CallInfo
|
class CallInfo
|
||||||
{
|
{
|
||||||
|
public string id;
|
||||||
public IMethod method;
|
public IMethod method;
|
||||||
public bool callVir;
|
public bool callVir;
|
||||||
}
|
}
|
||||||
|
@ -96,35 +67,60 @@ namespace Obfuz.ObfusPasses.CallObfus
|
||||||
|
|
||||||
private TypeDef _proxyTypeDef;
|
private TypeDef _proxyTypeDef;
|
||||||
|
|
||||||
public ModuleCallProxyAllocator(EncryptionScopeProvider encryptionScopeProvider, int encryptionLevel)
|
public ModuleDispatchProxyAllocator()
|
||||||
{
|
{
|
||||||
_encryptionScopeProvider = encryptionScopeProvider;
|
|
||||||
_encryptionLevel = encryptionLevel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Init(ModuleDef mod)
|
public override void Init()
|
||||||
{
|
{
|
||||||
_module = mod;
|
_settings = CallObfusPass.CurrentSettings;
|
||||||
_encryptionScope = _encryptionScopeProvider.GetScope(mod);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private TypeDef CreateProxyTypeDef()
|
private TypeDef CreateProxyTypeDef()
|
||||||
{
|
{
|
||||||
var typeDef = new TypeDefUser($"{ConstValues.ObfuzInternalSymbolNamePrefix}ProxyCall", _module.CorLibTypes.Object.ToTypeDefOrRef());
|
ModuleDef mod = Module;
|
||||||
|
using (var scope = new DisableTypeDefFindCacheScope(mod))
|
||||||
|
{
|
||||||
|
var typeDef = new TypeDefUser($"{ConstValues.ObfuzInternalSymbolNamePrefix}ProxyCall", mod.CorLibTypes.Object.ToTypeDefOrRef());
|
||||||
typeDef.Attributes = TypeAttributes.NotPublic | TypeAttributes.Sealed;
|
typeDef.Attributes = TypeAttributes.NotPublic | TypeAttributes.Sealed;
|
||||||
_module.EnableTypeDefFindCache = false;
|
mod.Types.Add(typeDef);
|
||||||
_module.Types.Add(typeDef);
|
|
||||||
_module.EnableTypeDefFindCache = true;
|
|
||||||
return typeDef;
|
return typeDef;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private MethodDef CreateDispatchMethodInfo(MethodSig methodSig)
|
private readonly HashSet<string> _uniqueMethodNames = new HashSet<string>();
|
||||||
|
|
||||||
|
|
||||||
|
private string ToUniqueMethodName(string originalName)
|
||||||
|
{
|
||||||
|
if (_uniqueMethodNames.Add(originalName))
|
||||||
|
{
|
||||||
|
return originalName;
|
||||||
|
}
|
||||||
|
for (int index = 1; ; index++)
|
||||||
|
{
|
||||||
|
string uniqueName = $"{originalName}${index}";
|
||||||
|
if (_uniqueMethodNames.Add(uniqueName))
|
||||||
|
{
|
||||||
|
return uniqueName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string CreateDispatchMethodName(MethodSig methodSig, int index)
|
||||||
|
{
|
||||||
|
// use a stable name for the dispatch method, so that we can reuse it across different modules
|
||||||
|
// this is important for cross-module calls
|
||||||
|
return ToUniqueMethodName($"{ConstValues.ObfuzInternalSymbolNamePrefix}Dispatch_{HashUtil.ComputeHash(methodSig.Params) & 0xFFFF}_{HashUtil.ComputeHash(methodSig.RetType) & 0xFFFFFF}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private MethodDef CreateDispatchMethodInfo(MethodSig methodSig, int index)
|
||||||
{
|
{
|
||||||
if (_proxyTypeDef == null)
|
if (_proxyTypeDef == null)
|
||||||
{
|
{
|
||||||
_proxyTypeDef = CreateProxyTypeDef();
|
_proxyTypeDef = CreateProxyTypeDef();
|
||||||
}
|
}
|
||||||
MethodDef methodDef = new MethodDefUser($"{ConstValues.ObfuzInternalSymbolNamePrefix}ProxyCall$Dispatch${_proxyTypeDef.Methods.Count}", methodSig,
|
MethodDef methodDef = new MethodDefUser(CreateDispatchMethodName(methodSig, index), methodSig,
|
||||||
MethodImplAttributes.IL | MethodImplAttributes.Managed,
|
MethodImplAttributes.IL | MethodImplAttributes.Managed,
|
||||||
MethodAttributes.Static | MethodAttributes.Public);
|
MethodAttributes.Static | MethodAttributes.Public);
|
||||||
methodDef.DeclaringType = _proxyTypeDef;
|
methodDef.DeclaringType = _proxyTypeDef;
|
||||||
|
@ -133,24 +129,25 @@ namespace Obfuz.ObfusPasses.CallObfus
|
||||||
|
|
||||||
private MethodSig CreateDispatchMethodSig(IMethod method)
|
private MethodSig CreateDispatchMethodSig(IMethod method)
|
||||||
{
|
{
|
||||||
MethodSig methodSig = MetaUtil.ToSharedMethodSig(_module.CorLibTypes, MetaUtil.GetInflatedMethodSig(method));
|
ModuleDef mod = Module;
|
||||||
|
MethodSig methodSig = MetaUtil.ToSharedMethodSig(mod.CorLibTypes, MetaUtil.GetInflatedMethodSig(method, null));
|
||||||
//MethodSig methodSig = MetaUtil.GetInflatedMethodSig(method).Clone();
|
//MethodSig methodSig = MetaUtil.GetInflatedMethodSig(method).Clone();
|
||||||
//methodSig.Params
|
//methodSig.Params
|
||||||
switch (MetaUtil.GetThisArgType(method))
|
switch (MetaUtil.GetThisArgType(method))
|
||||||
{
|
{
|
||||||
case ThisArgType.Class:
|
case ThisArgType.Class:
|
||||||
{
|
{
|
||||||
methodSig.Params.Insert(0, _module.CorLibTypes.Object);
|
methodSig.Params.Insert(0, mod.CorLibTypes.Object);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ThisArgType.ValueType:
|
case ThisArgType.ValueType:
|
||||||
{
|
{
|
||||||
methodSig.Params.Insert(0, _module.CorLibTypes.IntPtr);
|
methodSig.Params.Insert(0, mod.CorLibTypes.IntPtr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// extra param for index
|
// extra param for index
|
||||||
methodSig.Params.Add(_module.CorLibTypes.Int32);
|
methodSig.Params.Add(mod.CorLibTypes.Int32);
|
||||||
return MethodSig.CreateStatic(methodSig.RetType, methodSig.Params.ToArray());
|
return MethodSig.CreateStatic(methodSig.RetType, methodSig.Params.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,7 +158,7 @@ namespace Obfuz.ObfusPasses.CallObfus
|
||||||
|
|
||||||
private int GenerateEncryptOps(IRandom random)
|
private int GenerateEncryptOps(IRandom random)
|
||||||
{
|
{
|
||||||
return EncryptionUtil.GenerateEncryptionOpCodes(random, _encryptionScope.encryptor, _encryptionLevel);
|
return EncryptionUtil.GenerateEncryptionOpCodes(random, EncryptionScope.encryptor, _settings.obfuscationLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DispatchMethodInfo GetDispatchMethod(IMethod method)
|
private DispatchMethodInfo GetDispatchMethod(IMethod method)
|
||||||
|
@ -172,11 +169,11 @@ namespace Obfuz.ObfusPasses.CallObfus
|
||||||
dispatchMethods = new List<DispatchMethodInfo>();
|
dispatchMethods = new List<DispatchMethodInfo>();
|
||||||
_dispatchMethods.Add(methodSig, dispatchMethods);
|
_dispatchMethods.Add(methodSig, dispatchMethods);
|
||||||
}
|
}
|
||||||
if (dispatchMethods.Count == 0 || dispatchMethods.Last().methods.Count >= maxProxyMethodPerDispatchMethod)
|
if (dispatchMethods.Count == 0 || dispatchMethods.Last().methods.Count >= _settings.maxProxyMethodCountPerDispatchMethod)
|
||||||
{
|
{
|
||||||
var newDispatchMethodInfo = new DispatchMethodInfo
|
var newDispatchMethodInfo = new DispatchMethodInfo
|
||||||
{
|
{
|
||||||
methodDef = CreateDispatchMethodInfo(methodSig),
|
methodDef = CreateDispatchMethodInfo(methodSig, dispatchMethods.Count),
|
||||||
};
|
};
|
||||||
dispatchMethods.Add(newDispatchMethodInfo);
|
dispatchMethods.Add(newDispatchMethodInfo);
|
||||||
}
|
}
|
||||||
|
@ -186,7 +183,7 @@ namespace Obfuz.ObfusPasses.CallObfus
|
||||||
private IRandom CreateRandomForMethod(IMethod method, bool callVir)
|
private IRandom CreateRandomForMethod(IMethod method, bool callVir)
|
||||||
{
|
{
|
||||||
int seed = MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method);
|
int seed = MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method);
|
||||||
return _encryptionScope.localRandomCreator(seed);
|
return EncryptionScope.localRandomCreator(seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProxyCallMethodData Allocate(IMethod method, bool callVir)
|
public ProxyCallMethodData Allocate(IMethod method, bool callVir)
|
||||||
|
@ -204,7 +201,7 @@ namespace Obfuz.ObfusPasses.CallObfus
|
||||||
IRandom localRandom = CreateRandomForMethod(method, callVir);
|
IRandom localRandom = CreateRandomForMethod(method, callVir);
|
||||||
int encryptOps = GenerateEncryptOps(localRandom);
|
int encryptOps = GenerateEncryptOps(localRandom);
|
||||||
int salt = GenerateSalt(localRandom);
|
int salt = GenerateSalt(localRandom);
|
||||||
int encryptedIndex = _encryptionScope.encryptor.Encrypt(index, encryptOps, salt);
|
int encryptedIndex = EncryptionScope.encryptor.Encrypt(index, encryptOps, salt);
|
||||||
proxyInfo = new MethodProxyInfo()
|
proxyInfo = new MethodProxyInfo()
|
||||||
{
|
{
|
||||||
proxyMethod = methodDispatcher.methodDef,
|
proxyMethod = methodDispatcher.methodDef,
|
||||||
|
@ -213,19 +210,32 @@ namespace Obfuz.ObfusPasses.CallObfus
|
||||||
salt = salt,
|
salt = salt,
|
||||||
encryptedIndex = encryptedIndex,
|
encryptedIndex = encryptedIndex,
|
||||||
};
|
};
|
||||||
methodDispatcher.methods.Add(new CallInfo { method = method, callVir = callVir});
|
methodDispatcher.methods.Add(new CallInfo { id = $"{method}{(callVir ? "" : "v")}", method = method, callVir = callVir });
|
||||||
_methodProxys.Add(key, proxyInfo);
|
_methodProxys.Add(key, proxyInfo);
|
||||||
}
|
}
|
||||||
return new ProxyCallMethodData(proxyInfo.proxyMethod, proxyInfo.encryptedOps, proxyInfo.salt, proxyInfo.encryptedIndex, proxyInfo.index);
|
return new ProxyCallMethodData(proxyInfo.proxyMethod, proxyInfo.encryptedOps, proxyInfo.salt, proxyInfo.encryptedIndex, proxyInfo.index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Done()
|
public override void Done()
|
||||||
{
|
{
|
||||||
if (_done)
|
if (_done)
|
||||||
{
|
{
|
||||||
throw new Exception("Already done");
|
throw new Exception("Already done");
|
||||||
}
|
}
|
||||||
_done = true;
|
_done = true;
|
||||||
|
if (_proxyTypeDef == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for stable order, we sort methods by name
|
||||||
|
var methodWithNamePairList = _proxyTypeDef.Methods.Select(m => (m, m.ToString())).ToList();
|
||||||
|
methodWithNamePairList.Sort((a, b) => a.Item2.CompareTo(b.Item2));
|
||||||
|
_proxyTypeDef.Methods.Clear();
|
||||||
|
foreach (var methodPair in methodWithNamePairList)
|
||||||
|
{
|
||||||
|
methodPair.Item1.DeclaringType = _proxyTypeDef;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (DispatchMethodInfo dispatchMethod in _dispatchMethods.Values.SelectMany(ms => ms))
|
foreach (DispatchMethodInfo dispatchMethod in _dispatchMethods.Values.SelectMany(ms => ms))
|
||||||
{
|
{
|
||||||
|
@ -246,6 +256,9 @@ namespace Obfuz.ObfusPasses.CallObfus
|
||||||
var switchInst = Instruction.Create(OpCodes.Switch, switchCases);
|
var switchInst = Instruction.Create(OpCodes.Switch, switchCases);
|
||||||
ins.Add(switchInst);
|
ins.Add(switchInst);
|
||||||
var ret = Instruction.Create(OpCodes.Ret);
|
var ret = Instruction.Create(OpCodes.Ret);
|
||||||
|
|
||||||
|
// sort methods by signature to ensure stable order
|
||||||
|
//dispatchMethod.methods.Sort((a, b) => a.id.CompareTo(b.id));
|
||||||
foreach (CallInfo ci in dispatchMethod.methods)
|
foreach (CallInfo ci in dispatchMethod.methods)
|
||||||
{
|
{
|
||||||
var callTargetMethod = Instruction.Create(ci.callVir ? OpCodes.Callvirt : OpCodes.Call, ci.method);
|
var callTargetMethod = Instruction.Create(ci.callVir ? OpCodes.Callvirt : OpCodes.Call, ci.method);
|
||||||
|
@ -257,37 +270,4 @@ namespace Obfuz.ObfusPasses.CallObfus
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CallProxyAllocator
|
|
||||||
{
|
|
||||||
private readonly EncryptionScopeProvider _encryptionScopeProvider;
|
|
||||||
private GroupByModuleEntityManager _moduleEntityManager;
|
|
||||||
private readonly int _encryptionLevel;
|
|
||||||
|
|
||||||
public CallProxyAllocator(EncryptionScopeProvider encryptionScopeProvider, GroupByModuleEntityManager moduleEntityManager, int encryptionLevel)
|
|
||||||
{
|
|
||||||
_encryptionScopeProvider = encryptionScopeProvider;
|
|
||||||
_moduleEntityManager = moduleEntityManager;
|
|
||||||
_encryptionLevel = encryptionLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ModuleCallProxyAllocator GetModuleAllocator(ModuleDef mod)
|
|
||||||
{
|
|
||||||
return _moduleEntityManager.GetEntity<ModuleCallProxyAllocator>(mod, () => new ModuleCallProxyAllocator(_encryptionScopeProvider, _encryptionLevel));
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProxyCallMethodData Allocate(ModuleDef mod, IMethod method, bool callVir)
|
|
||||||
{
|
|
||||||
ModuleCallProxyAllocator allocator = GetModuleAllocator(mod);
|
|
||||||
return allocator.Allocate(method, callVir);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Done()
|
|
||||||
{
|
|
||||||
foreach (var allocator in _moduleEntityManager.GetEntities<ModuleCallProxyAllocator>())
|
|
||||||
{
|
|
||||||
allocator.Done();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue