add Obfuz Unity Project
parent
eb0542ed0f
commit
50fb2274f1
|
|
@ -3,398 +3,14 @@
|
||||||
##
|
##
|
||||||
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
|
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
|
||||||
|
|
||||||
# User-specific files
|
**/Library/
|
||||||
*.rsuser
|
**/Logs/
|
||||||
*.suo
|
**/Temp/
|
||||||
*.user
|
|
||||||
*.userosscache
|
|
||||||
*.sln.docstates
|
|
||||||
|
|
||||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
**/.vs/
|
||||||
*.userprefs
|
**/bin/
|
||||||
|
**/obj/
|
||||||
|
|
||||||
# Mono auto generated files
|
|
||||||
mono_crash.*
|
|
||||||
|
|
||||||
# Build results
|
*.vsconfig
|
||||||
[Dd]ebug/
|
**/UserSettings/
|
||||||
[Dd]ebugPublic/
|
|
||||||
[Rr]elease/
|
|
||||||
[Rr]eleases/
|
|
||||||
x64/
|
|
||||||
x86/
|
|
||||||
[Ww][Ii][Nn]32/
|
|
||||||
[Aa][Rr][Mm]/
|
|
||||||
[Aa][Rr][Mm]64/
|
|
||||||
bld/
|
|
||||||
[Bb]in/
|
|
||||||
[Oo]bj/
|
|
||||||
[Ll]og/
|
|
||||||
[Ll]ogs/
|
|
||||||
|
|
||||||
# Visual Studio 2015/2017 cache/options directory
|
|
||||||
.vs/
|
|
||||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
|
||||||
#wwwroot/
|
|
||||||
|
|
||||||
# Visual Studio 2017 auto generated files
|
|
||||||
Generated\ Files/
|
|
||||||
|
|
||||||
# MSTest test Results
|
|
||||||
[Tt]est[Rr]esult*/
|
|
||||||
[Bb]uild[Ll]og.*
|
|
||||||
|
|
||||||
# NUnit
|
|
||||||
*.VisualState.xml
|
|
||||||
TestResult.xml
|
|
||||||
nunit-*.xml
|
|
||||||
|
|
||||||
# Build Results of an ATL Project
|
|
||||||
[Dd]ebugPS/
|
|
||||||
[Rr]eleasePS/
|
|
||||||
dlldata.c
|
|
||||||
|
|
||||||
# Benchmark Results
|
|
||||||
BenchmarkDotNet.Artifacts/
|
|
||||||
|
|
||||||
# .NET Core
|
|
||||||
project.lock.json
|
|
||||||
project.fragment.lock.json
|
|
||||||
artifacts/
|
|
||||||
|
|
||||||
# ASP.NET Scaffolding
|
|
||||||
ScaffoldingReadMe.txt
|
|
||||||
|
|
||||||
# StyleCop
|
|
||||||
StyleCopReport.xml
|
|
||||||
|
|
||||||
# Files built by Visual Studio
|
|
||||||
*_i.c
|
|
||||||
*_p.c
|
|
||||||
*_h.h
|
|
||||||
*.ilk
|
|
||||||
*.meta
|
|
||||||
*.obj
|
|
||||||
*.iobj
|
|
||||||
*.pch
|
|
||||||
*.pdb
|
|
||||||
*.ipdb
|
|
||||||
*.pgc
|
|
||||||
*.pgd
|
|
||||||
*.rsp
|
|
||||||
# but not Directory.Build.rsp, as it configures directory-level build defaults
|
|
||||||
!Directory.Build.rsp
|
|
||||||
*.sbr
|
|
||||||
*.tlb
|
|
||||||
*.tli
|
|
||||||
*.tlh
|
|
||||||
*.tmp
|
|
||||||
*.tmp_proj
|
|
||||||
*_wpftmp.csproj
|
|
||||||
*.log
|
|
||||||
*.tlog
|
|
||||||
*.vspscc
|
|
||||||
*.vssscc
|
|
||||||
.builds
|
|
||||||
*.pidb
|
|
||||||
*.svclog
|
|
||||||
*.scc
|
|
||||||
|
|
||||||
# Chutzpah Test files
|
|
||||||
_Chutzpah*
|
|
||||||
|
|
||||||
# Visual C++ cache files
|
|
||||||
ipch/
|
|
||||||
*.aps
|
|
||||||
*.ncb
|
|
||||||
*.opendb
|
|
||||||
*.opensdf
|
|
||||||
*.sdf
|
|
||||||
*.cachefile
|
|
||||||
*.VC.db
|
|
||||||
*.VC.VC.opendb
|
|
||||||
|
|
||||||
# Visual Studio profiler
|
|
||||||
*.psess
|
|
||||||
*.vsp
|
|
||||||
*.vspx
|
|
||||||
*.sap
|
|
||||||
|
|
||||||
# Visual Studio Trace Files
|
|
||||||
*.e2e
|
|
||||||
|
|
||||||
# TFS 2012 Local Workspace
|
|
||||||
$tf/
|
|
||||||
|
|
||||||
# Guidance Automation Toolkit
|
|
||||||
*.gpState
|
|
||||||
|
|
||||||
# ReSharper is a .NET coding add-in
|
|
||||||
_ReSharper*/
|
|
||||||
*.[Rr]e[Ss]harper
|
|
||||||
*.DotSettings.user
|
|
||||||
|
|
||||||
# TeamCity is a build add-in
|
|
||||||
_TeamCity*
|
|
||||||
|
|
||||||
# DotCover is a Code Coverage Tool
|
|
||||||
*.dotCover
|
|
||||||
|
|
||||||
# AxoCover is a Code Coverage Tool
|
|
||||||
.axoCover/*
|
|
||||||
!.axoCover/settings.json
|
|
||||||
|
|
||||||
# Coverlet is a free, cross platform Code Coverage Tool
|
|
||||||
coverage*.json
|
|
||||||
coverage*.xml
|
|
||||||
coverage*.info
|
|
||||||
|
|
||||||
# Visual Studio code coverage results
|
|
||||||
*.coverage
|
|
||||||
*.coveragexml
|
|
||||||
|
|
||||||
# NCrunch
|
|
||||||
_NCrunch_*
|
|
||||||
.*crunch*.local.xml
|
|
||||||
nCrunchTemp_*
|
|
||||||
|
|
||||||
# MightyMoose
|
|
||||||
*.mm.*
|
|
||||||
AutoTest.Net/
|
|
||||||
|
|
||||||
# Web workbench (sass)
|
|
||||||
.sass-cache/
|
|
||||||
|
|
||||||
# Installshield output folder
|
|
||||||
[Ee]xpress/
|
|
||||||
|
|
||||||
# DocProject is a documentation generator add-in
|
|
||||||
DocProject/buildhelp/
|
|
||||||
DocProject/Help/*.HxT
|
|
||||||
DocProject/Help/*.HxC
|
|
||||||
DocProject/Help/*.hhc
|
|
||||||
DocProject/Help/*.hhk
|
|
||||||
DocProject/Help/*.hhp
|
|
||||||
DocProject/Help/Html2
|
|
||||||
DocProject/Help/html
|
|
||||||
|
|
||||||
# Click-Once directory
|
|
||||||
publish/
|
|
||||||
|
|
||||||
# Publish Web Output
|
|
||||||
*.[Pp]ublish.xml
|
|
||||||
*.azurePubxml
|
|
||||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
|
||||||
# but database connection strings (with potential passwords) will be unencrypted
|
|
||||||
*.pubxml
|
|
||||||
*.publishproj
|
|
||||||
|
|
||||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
|
||||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
|
||||||
# in these scripts will be unencrypted
|
|
||||||
PublishScripts/
|
|
||||||
|
|
||||||
# NuGet Packages
|
|
||||||
*.nupkg
|
|
||||||
# NuGet Symbol Packages
|
|
||||||
*.snupkg
|
|
||||||
# The packages folder can be ignored because of Package Restore
|
|
||||||
**/[Pp]ackages/*
|
|
||||||
# except build/, which is used as an MSBuild target.
|
|
||||||
!**/[Pp]ackages/build/
|
|
||||||
# Uncomment if necessary however generally it will be regenerated when needed
|
|
||||||
#!**/[Pp]ackages/repositories.config
|
|
||||||
# NuGet v3's project.json files produces more ignorable files
|
|
||||||
*.nuget.props
|
|
||||||
*.nuget.targets
|
|
||||||
|
|
||||||
# Microsoft Azure Build Output
|
|
||||||
csx/
|
|
||||||
*.build.csdef
|
|
||||||
|
|
||||||
# Microsoft Azure Emulator
|
|
||||||
ecf/
|
|
||||||
rcf/
|
|
||||||
|
|
||||||
# Windows Store app package directories and files
|
|
||||||
AppPackages/
|
|
||||||
BundleArtifacts/
|
|
||||||
Package.StoreAssociation.xml
|
|
||||||
_pkginfo.txt
|
|
||||||
*.appx
|
|
||||||
*.appxbundle
|
|
||||||
*.appxupload
|
|
||||||
|
|
||||||
# Visual Studio cache files
|
|
||||||
# files ending in .cache can be ignored
|
|
||||||
*.[Cc]ache
|
|
||||||
# but keep track of directories ending in .cache
|
|
||||||
!?*.[Cc]ache/
|
|
||||||
|
|
||||||
# Others
|
|
||||||
ClientBin/
|
|
||||||
~$*
|
|
||||||
*~
|
|
||||||
*.dbmdl
|
|
||||||
*.dbproj.schemaview
|
|
||||||
*.jfm
|
|
||||||
*.pfx
|
|
||||||
*.publishsettings
|
|
||||||
orleans.codegen.cs
|
|
||||||
|
|
||||||
# Including strong name files can present a security risk
|
|
||||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
|
||||||
#*.snk
|
|
||||||
|
|
||||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
|
||||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
|
||||||
#bower_components/
|
|
||||||
|
|
||||||
# RIA/Silverlight projects
|
|
||||||
Generated_Code/
|
|
||||||
|
|
||||||
# Backup & report files from converting an old project file
|
|
||||||
# to a newer Visual Studio version. Backup files are not needed,
|
|
||||||
# because we have git ;-)
|
|
||||||
_UpgradeReport_Files/
|
|
||||||
Backup*/
|
|
||||||
UpgradeLog*.XML
|
|
||||||
UpgradeLog*.htm
|
|
||||||
ServiceFabricBackup/
|
|
||||||
*.rptproj.bak
|
|
||||||
|
|
||||||
# SQL Server files
|
|
||||||
*.mdf
|
|
||||||
*.ldf
|
|
||||||
*.ndf
|
|
||||||
|
|
||||||
# Business Intelligence projects
|
|
||||||
*.rdl.data
|
|
||||||
*.bim.layout
|
|
||||||
*.bim_*.settings
|
|
||||||
*.rptproj.rsuser
|
|
||||||
*- [Bb]ackup.rdl
|
|
||||||
*- [Bb]ackup ([0-9]).rdl
|
|
||||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
|
||||||
|
|
||||||
# Microsoft Fakes
|
|
||||||
FakesAssemblies/
|
|
||||||
|
|
||||||
# GhostDoc plugin setting file
|
|
||||||
*.GhostDoc.xml
|
|
||||||
|
|
||||||
# Node.js Tools for Visual Studio
|
|
||||||
.ntvs_analysis.dat
|
|
||||||
node_modules/
|
|
||||||
|
|
||||||
# Visual Studio 6 build log
|
|
||||||
*.plg
|
|
||||||
|
|
||||||
# Visual Studio 6 workspace options file
|
|
||||||
*.opt
|
|
||||||
|
|
||||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
|
||||||
*.vbw
|
|
||||||
|
|
||||||
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
|
|
||||||
*.vbp
|
|
||||||
|
|
||||||
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
|
|
||||||
*.dsw
|
|
||||||
*.dsp
|
|
||||||
|
|
||||||
# Visual Studio 6 technical files
|
|
||||||
*.ncb
|
|
||||||
*.aps
|
|
||||||
|
|
||||||
# Visual Studio LightSwitch build output
|
|
||||||
**/*.HTMLClient/GeneratedArtifacts
|
|
||||||
**/*.DesktopClient/GeneratedArtifacts
|
|
||||||
**/*.DesktopClient/ModelManifest.xml
|
|
||||||
**/*.Server/GeneratedArtifacts
|
|
||||||
**/*.Server/ModelManifest.xml
|
|
||||||
_Pvt_Extensions
|
|
||||||
|
|
||||||
# Paket dependency manager
|
|
||||||
.paket/paket.exe
|
|
||||||
paket-files/
|
|
||||||
|
|
||||||
# FAKE - F# Make
|
|
||||||
.fake/
|
|
||||||
|
|
||||||
# CodeRush personal settings
|
|
||||||
.cr/personal
|
|
||||||
|
|
||||||
# Python Tools for Visual Studio (PTVS)
|
|
||||||
__pycache__/
|
|
||||||
*.pyc
|
|
||||||
|
|
||||||
# Cake - Uncomment if you are using it
|
|
||||||
# tools/**
|
|
||||||
# !tools/packages.config
|
|
||||||
|
|
||||||
# Tabs Studio
|
|
||||||
*.tss
|
|
||||||
|
|
||||||
# Telerik's JustMock configuration file
|
|
||||||
*.jmconfig
|
|
||||||
|
|
||||||
# BizTalk build output
|
|
||||||
*.btp.cs
|
|
||||||
*.btm.cs
|
|
||||||
*.odx.cs
|
|
||||||
*.xsd.cs
|
|
||||||
|
|
||||||
# OpenCover UI analysis results
|
|
||||||
OpenCover/
|
|
||||||
|
|
||||||
# Azure Stream Analytics local run output
|
|
||||||
ASALocalRun/
|
|
||||||
|
|
||||||
# MSBuild Binary and Structured Log
|
|
||||||
*.binlog
|
|
||||||
|
|
||||||
# NVidia Nsight GPU debugger configuration file
|
|
||||||
*.nvuser
|
|
||||||
|
|
||||||
# MFractors (Xamarin productivity tool) working folder
|
|
||||||
.mfractor/
|
|
||||||
|
|
||||||
# Local History for Visual Studio
|
|
||||||
.localhistory/
|
|
||||||
|
|
||||||
# Visual Studio History (VSHistory) files
|
|
||||||
.vshistory/
|
|
||||||
|
|
||||||
# BeatPulse healthcheck temp database
|
|
||||||
healthchecksdb
|
|
||||||
|
|
||||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
|
||||||
MigrationBackup/
|
|
||||||
|
|
||||||
# Ionide (cross platform F# VS Code tools) working folder
|
|
||||||
.ionide/
|
|
||||||
|
|
||||||
# Fody - auto-generated XML schema
|
|
||||||
FodyWeavers.xsd
|
|
||||||
|
|
||||||
# VS Code files for those working on multiple tools
|
|
||||||
.vscode/*
|
|
||||||
!.vscode/settings.json
|
|
||||||
!.vscode/tasks.json
|
|
||||||
!.vscode/launch.json
|
|
||||||
!.vscode/extensions.json
|
|
||||||
*.code-workspace
|
|
||||||
|
|
||||||
# Local History for Visual Studio Code
|
|
||||||
.history/
|
|
||||||
|
|
||||||
# Windows Installer files from build outputs
|
|
||||||
*.cab
|
|
||||||
*.msi
|
|
||||||
*.msix
|
|
||||||
*.msm
|
|
||||||
*.msp
|
|
||||||
|
|
||||||
# JetBrains Rider
|
|
||||||
*.sln.iml
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
test stack trace
|
||||||
|
UnityEngine.DebugLogHandler:Internal_Log(LogType, LogOption, String, Object)
|
||||||
|
UnityEngine.DebugLogHandler:LogFormat(LogType, Object, String, Object[])
|
||||||
|
UnityEngine.Logger:Log(LogType, Object)
|
||||||
|
UnityEngine.Debug:Log(Object)
|
||||||
|
Obfus2.TestStackTrace:Stack3()
|
||||||
|
Obfus2.NestedClass`1:Stack2(TestStackTrace, Int32[], List`1, Banana)
|
||||||
|
Obfus2.TestStackTrace:Stack1(Int64, UInt64, Single, Double, String, Object)
|
||||||
|
Obfus2.TestStackTrace:Stack0(Byte, SByte, Int16, UInt16, Int32, UInt32)
|
||||||
|
Tests.TC_StackTrace:PrintStackTrace()
|
||||||
|
System.Reflection.RuntimeMethodInfo:InternalInvoke(Object, Object[], Exception&)
|
||||||
|
System.Reflection.RuntimeMethodInfo:Invoke(Object, BindingFlags, Binder, Object[], CultureInfo)
|
||||||
|
System.Reflection.MethodBase:Invoke(Object, Object[])
|
||||||
|
SharpUnit.TestCase:Run(TestResult)
|
||||||
|
SharpUnit.TestSuite:Run(TestResult)
|
||||||
|
TestRunner:Run()
|
||||||
|
Bootstrap:Start()
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
test stack trace
|
||||||
|
UnityEngine.DebugLogHandler:Internal_Log(LogType, LogOption, String, Object)
|
||||||
|
UnityEngine.DebugLogHandler:LogFormat(LogType, Object, String, Object[])
|
||||||
|
UnityEngine.Logger:Log(LogType, Object)
|
||||||
|
UnityEngine.Debug:Log(Object)
|
||||||
|
F.g:A()
|
||||||
|
F.G:a(g, Int32[], List`1, Banana)
|
||||||
|
F.g:a(Int64, UInt64, Single, Double, String, Object)
|
||||||
|
F.g:b(Byte, SByte, Int16, UInt16, Int32, UInt32)
|
||||||
|
Tests.TC_StackTrace:PrintStackTrace()
|
||||||
|
System.Reflection.RuntimeMethodInfo:InternalInvoke(Object, Object[], Exception&)
|
||||||
|
System.Reflection.RuntimeMethodInfo:Invoke(Object, BindingFlags, Binder, Object[], CultureInfo)
|
||||||
|
System.Reflection.MethodBase:Invoke(Object, Object[])
|
||||||
|
SharpUnit.TestCase:Run(TestResult)
|
||||||
|
SharpUnit.TestSuite:Run(TestResult)
|
||||||
|
TestRunner:Run()
|
||||||
|
Bootstrap:Start()
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,881 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<!-- Generated file, do not modify, your changes will be overwritten (use AssetPostprocessor.OnGeneratedCSProject) -->
|
||||||
|
<PropertyGroup>
|
||||||
|
<LangVersion>9.0</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProductVersion>10.0.20506</ProductVersion>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
<RootNamespace></RootNamespace>
|
||||||
|
<ProjectGuid>{1FE2F0BF-BDED-ACA3-1B41-08AC3002B1B6}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<AssemblyName>Obfuz.Runtime</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<BaseDirectory>.</BaseDirectory>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<NoWarn>0169;USG0001</NoWarn>
|
||||||
|
<DefineConstants>UNITY_2022_3_11;UNITY_2022_3;UNITY_2022;UNITY_5_3_OR_NEWER;UNITY_5_4_OR_NEWER;UNITY_5_5_OR_NEWER;UNITY_5_6_OR_NEWER;UNITY_2017_1_OR_NEWER;UNITY_2017_2_OR_NEWER;UNITY_2017_3_OR_NEWER;UNITY_2017_4_OR_NEWER;UNITY_2018_1_OR_NEWER;UNITY_2018_2_OR_NEWER;UNITY_2018_3_OR_NEWER;UNITY_2018_4_OR_NEWER;UNITY_2019_1_OR_NEWER;UNITY_2019_2_OR_NEWER;UNITY_2019_3_OR_NEWER;UNITY_2019_4_OR_NEWER;UNITY_2020_1_OR_NEWER;UNITY_2020_2_OR_NEWER;UNITY_2020_3_OR_NEWER;UNITY_2021_1_OR_NEWER;UNITY_2021_2_OR_NEWER;UNITY_2021_3_OR_NEWER;UNITY_2022_1_OR_NEWER;UNITY_2022_2_OR_NEWER;UNITY_2022_3_OR_NEWER;PLATFORM_ARCH_64;UNITY_64;UNITY_INCLUDE_TESTS;ENABLE_AR;ENABLE_AUDIO;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_EVENT_QUEUE;ENABLE_MICROPHONE;ENABLE_MULTIPLE_DISPLAYS;ENABLE_PHYSICS;ENABLE_TEXTURE_STREAMING;ENABLE_VIRTUALTEXTURING;ENABLE_LZMA;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_UNITYWEBREQUEST;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_EDITOR_GAME_SERVICES;ENABLE_UNITY_GAME_SERVICES_ANALYTICS_SUPPORT;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_HUB_LICENSE;ENABLE_WEBSOCKET_CLIENT;ENABLE_GENERATE_NATIVE_PLUGINS_FOR_ASSEMBLIES_API;ENABLE_DIRECTOR_AUDIO;ENABLE_DIRECTOR_TEXTURE;ENABLE_MANAGED_JOBS;ENABLE_MANAGED_TRANSFORM_JOBS;ENABLE_MANAGED_ANIMATION_JOBS;ENABLE_MANAGED_AUDIO_JOBS;ENABLE_MANAGED_UNITYTLS;INCLUDE_DYNAMIC_GI;ENABLE_SCRIPTING_GC_WBARRIERS;PLATFORM_SUPPORTS_MONO;RENDER_SOFTWARE_CURSOR;ENABLE_VIDEO;ENABLE_ACCELERATOR_CLIENT_DEBUGGING;ENABLE_NAVIGATION_PACKAGE_DEBUG_VISUALIZATION;ENABLE_NAVIGATION_HEIGHTMESH_RUNTIME_SUPPORT;ENABLE_NAVIGATION_UI_REQUIRES_PACKAGE;PLATFORM_STANDALONE;TEXTCORE_1_0_OR_NEWER;PLATFORM_STANDALONE_WIN;UNITY_STANDALONE_WIN;UNITY_STANDALONE;ENABLE_RUNTIME_GI;ENABLE_MOVIES;ENABLE_NETWORK;ENABLE_NVIDIA;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_OUT_OF_PROCESS_CRASH_HANDLER;ENABLE_CLUSTER_SYNC;ENABLE_CLUSTERINPUT;PLATFORM_UPDATES_TIME_OUTSIDE_OF_PLAYER_LOOP;GFXDEVICE_WAITFOREVENT_MESSAGEPUMP;PLATFORM_INITIALIZES_MEMORY_MANAGER_EXPLICITLY;ENABLE_MONO;NET_4_6;NET_UNITY_4_8;ENABLE_PROFILER;DEBUG;TRACE;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_WIN;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_BURST_AOT;UNITY_TEAM_LICENSE;ENABLE_CUSTOM_RENDER_TEXTURE;ENABLE_DIRECTOR;ENABLE_LOCALIZATION;ENABLE_SPRITES;ENABLE_TERRAIN;ENABLE_TILEMAP;ENABLE_TIMELINE;ENABLE_LEGACY_INPUT_MANAGER;TEXTCORE_FONT_ENGINE_1_5_OR_NEWER;CSHARP_7_OR_LATER;CSHARP_7_3_OR_NEWER</DefineConstants>
|
||||||
|
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>Temp\bin\Debug\</OutputPath>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>Temp\bin\Release\</OutputPath>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<NoConfig>true</NoConfig>
|
||||||
|
<NoStdLib>true</NoStdLib>
|
||||||
|
<AddAdditionalExplicitAssemblyReferences>false</AddAdditionalExplicitAssemblyReferences>
|
||||||
|
<ImplicitlyExpandNETStandardFacades>false</ImplicitlyExpandNETStandardFacades>
|
||||||
|
<ImplicitlyExpandDesignTimeFacades>false</ImplicitlyExpandDesignTimeFacades>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<ProjectTypeGuids>{E097FAD1-6243-4DAD-9C02-E9B9EFC3FFC1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||||
|
<UnityProjectGenerator>Package</UnityProjectGenerator>
|
||||||
|
<UnityProjectGeneratorVersion>2.0.23</UnityProjectGeneratorVersion>
|
||||||
|
<UnityProjectGeneratorStyle>Legacy</UnityProjectGeneratorStyle>
|
||||||
|
<UnityProjectType>Game:1</UnityProjectType>
|
||||||
|
<UnityBuildTarget>StandaloneWindows64:19</UnityBuildTarget>
|
||||||
|
<UnityVersion>2022.3.11f1</UnityVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Analyzer Include="d:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\Extensions\Microsoft\Visual Studio Tools for Unity\Analyzers\Microsoft.Unity.Analyzers.dll" />
|
||||||
|
<Analyzer Include="D:\UnityHubs\2022.3.11f1\Editor\Data\Tools\Unity.SourceGenerators\Unity.SourceGenerators.dll" />
|
||||||
|
<Analyzer Include="D:\UnityHubs\2022.3.11f1\Editor\Data\Tools\Unity.SourceGenerators\Unity.Properties.SourceGenerator.dll" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Packages\com.code-philosophy.obfuz\Runtime\ObfuzIgnoreAttribute.cs" />
|
||||||
|
<Compile Include="Packages\com.code-philosophy.obfuz\Runtime\EncryptionService.cs" />
|
||||||
|
<Compile Include="Packages\com.code-philosophy.obfuz\Runtime\IEncryptor.cs" />
|
||||||
|
<Compile Include="Packages\com.code-philosophy.obfuz\Runtime\NullEncryptor.cs" />
|
||||||
|
<Compile Include="Packages\com.code-philosophy.obfuz\Runtime\ConstUtility.cs" />
|
||||||
|
<Compile Include="Packages\com.code-philosophy.obfuz\Runtime\EncryptorBase.cs" />
|
||||||
|
<Compile Include="Packages\com.code-philosophy.obfuz\Runtime\EncryptionScope.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="Packages\com.code-philosophy.obfuz\Runtime\Obfuz.Runtime.asmdef" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="UnityEngine">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.ARModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.ARModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.AccessibilityModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.AccessibilityModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.AssetBundleModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.AssetBundleModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.AudioModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.AudioModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.ClusterInputModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.ClusterInputModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.ClusterRendererModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.ClusterRendererModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.ContentLoadModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.ContentLoadModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.CoreModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.CrashReportingModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.CrashReportingModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.DSPGraphModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.DSPGraphModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.GIModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.GIModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.GameCenterModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.GameCenterModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.GridModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.GridModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.HotReloadModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.HotReloadModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.IMGUIModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.IMGUIModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.ImageConversionModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.ImageConversionModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.InputModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.InputModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.InputLegacyModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.InputLegacyModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.JSONSerializeModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.JSONSerializeModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.LocalizationModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.LocalizationModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.PerformanceReportingModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.PerformanceReportingModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.ProfilerModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.ProfilerModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.PropertiesModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.PropertiesModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.SharedInternalsModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.SharedInternalsModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.SpriteMaskModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.SpriteMaskModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.SpriteShapeModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.SpriteShapeModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.StreamingModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.StreamingModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.SubstanceModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.SubstanceModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.TLSModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.TLSModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.TextCoreFontEngineModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.TextCoreFontEngineModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.TextCoreTextEngineModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.TextCoreTextEngineModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.TextRenderingModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.TextRenderingModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.UnityAnalyticsCommonModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityAnalyticsCommonModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.UnityConnectModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityConnectModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.UnityCurlModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityCurlModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.UnityTestProtocolModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityTestProtocolModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.UnityWebRequestModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.UnityWebRequestAssetBundleModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestAssetBundleModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.UnityWebRequestAudioModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestAudioModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.UnityWebRequestWWWModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestWWWModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.VFXModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.VFXModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.VirtualTexturingModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEngine.VirtualTexturingModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEditor">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEditor.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEditor.CoreModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEditor.CoreModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEditor.DeviceSimulatorModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEditor.DeviceSimulatorModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEditor.DiagnosticsModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEditor.DiagnosticsModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEditor.EditorToolbarModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEditor.EditorToolbarModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEditor.GraphViewModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEditor.GraphViewModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEditor.PresetsUIModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEditor.PresetsUIModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEditor.QuickSearchModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEditor.QuickSearchModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEditor.SceneTemplateModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEditor.SceneTemplateModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEditor.SceneViewModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEditor.SceneViewModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEditor.TextCoreFontEngineModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEditor.TextCoreFontEngineModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEditor.TextCoreTextEngineModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEditor.TextCoreTextEngineModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEditor.UIBuilderModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEditor.UIBuilderModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEditor.UIElementsModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEditor.UIElementsModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEditor.UIElementsSamplesModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEditor.UIElementsSamplesModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEditor.UnityConnectModule">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEngine\UnityEditor.UnityConnectModule.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEditor.Graphs">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\Managed\UnityEditor.Graphs.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEditor.WebGL.Extensions">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\PlaybackEngines\WebGLSupport\UnityEditor.WebGL.Extensions.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEditor.Android.Extensions">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\PlaybackEngines\AndroidPlayer\UnityEditor.Android.Extensions.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEditor.iOS.Extensions">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\PlaybackEngines\iOSSupport\UnityEditor.iOS.Extensions.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEditor.AppleTV.Extensions">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\PlaybackEngines\AppleTVSupport\UnityEditor.AppleTV.Extensions.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEditor.WindowsStandalone.Extensions">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\PlaybackEngines\WindowsStandaloneSupport\UnityEditor.WindowsStandalone.Extensions.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEditor.LinuxStandalone.Extensions">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\PlaybackEngines\LinuxStandaloneSupport\UnityEditor.LinuxStandalone.Extensions.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="dnlib">
|
||||||
|
<HintPath>Packages\com.code-philosophy.obfuz\Plugins\dnlib.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEditor.iOS.Extensions.Xcode">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\PlaybackEngines\AppleTVSupport\UnityEditor.iOS.Extensions.Xcode.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEditor.iOS.Extensions.Xcode">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\PlaybackEngines\iOSSupport\UnityEditor.iOS.Extensions.Xcode.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEditor.iOS.Extensions.Common">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\PlaybackEngines\iOSSupport\UnityEditor.iOS.Extensions.Common.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Unity.Android.Types">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\PlaybackEngines\AndroidPlayer\Unity.Android.Types.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Unity.Android.Gradle">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\PlaybackEngines\AndroidPlayer\Unity.Android.Gradle.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Unity.Android.GradleProject">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\PlaybackEngines\AndroidPlayer\Unity.Android.GradleProject.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="mscorlib">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\mscorlib.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Core">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Core.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Runtime.Serialization">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Runtime.Serialization.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Xml">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Xml.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Xml.Linq">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Xml.Linq.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Numerics">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Numerics.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Numerics.Vectors">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Numerics.Vectors.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Net.Http">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Net.Http.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.IO.Compression">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.IO.Compression.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.CSharp">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Microsoft.CSharp.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Data">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Data.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Data.DataSetExtensions">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Data.DataSetExtensions.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Drawing">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Drawing.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.IO.Compression.FileSystem">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.IO.Compression.FileSystem.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.ComponentModel.Composition">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.ComponentModel.Composition.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Transactions">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Transactions.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.Win32.Primitives">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\Microsoft.Win32.Primitives.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="netstandard">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\netstandard.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.AppContext">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.AppContext.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Buffers">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Buffers.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Collections.Concurrent">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Collections.Concurrent.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Collections">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Collections.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Collections.NonGeneric">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Collections.NonGeneric.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Collections.Specialized">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Collections.Specialized.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.ComponentModel.Annotations">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ComponentModel.Annotations.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.ComponentModel">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ComponentModel.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.ComponentModel.EventBasedAsync">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ComponentModel.EventBasedAsync.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.ComponentModel.Primitives">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ComponentModel.Primitives.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.ComponentModel.TypeConverter">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ComponentModel.TypeConverter.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Console">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Console.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Data.Common">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Data.Common.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Diagnostics.Contracts">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.Contracts.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Diagnostics.Debug">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.Debug.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Diagnostics.FileVersionInfo">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.FileVersionInfo.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Diagnostics.Process">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.Process.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Diagnostics.StackTrace">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.StackTrace.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Diagnostics.TextWriterTraceListener">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.TextWriterTraceListener.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Diagnostics.Tools">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.Tools.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Diagnostics.TraceSource">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.TraceSource.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Drawing.Primitives">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Drawing.Primitives.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Dynamic.Runtime">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Dynamic.Runtime.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Globalization.Calendars">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Globalization.Calendars.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Globalization">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Globalization.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Globalization.Extensions">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Globalization.Extensions.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.IO.Compression.ZipFile">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.Compression.ZipFile.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.IO">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.IO.FileSystem">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.FileSystem.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.IO.FileSystem.DriveInfo">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.FileSystem.DriveInfo.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.IO.FileSystem.Primitives">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.FileSystem.Primitives.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.IO.FileSystem.Watcher">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.FileSystem.Watcher.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.IO.IsolatedStorage">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.IsolatedStorage.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.IO.MemoryMappedFiles">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.MemoryMappedFiles.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.IO.Pipes">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.Pipes.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.IO.UnmanagedMemoryStream">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.UnmanagedMemoryStream.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Linq">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Linq.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Linq.Expressions">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Linq.Expressions.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Linq.Parallel">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Linq.Parallel.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Linq.Queryable">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Linq.Queryable.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Memory">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Memory.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Net.Http.Rtc">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Http.Rtc.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Net.NameResolution">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.NameResolution.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Net.NetworkInformation">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.NetworkInformation.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Net.Ping">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Ping.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Net.Primitives">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Primitives.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Net.Requests">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Requests.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Net.Security">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Security.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Net.Sockets">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Sockets.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Net.WebHeaderCollection">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.WebHeaderCollection.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Net.WebSockets.Client">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.WebSockets.Client.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Net.WebSockets">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.WebSockets.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.ObjectModel">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ObjectModel.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Reflection.DispatchProxy">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.DispatchProxy.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Reflection">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Reflection.Emit">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.Emit.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Reflection.Emit.ILGeneration">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.Emit.ILGeneration.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Reflection.Emit.Lightweight">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.Emit.Lightweight.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Reflection.Extensions">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.Extensions.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Reflection.Primitives">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.Primitives.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Resources.Reader">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Resources.Reader.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Resources.ResourceManager">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Resources.ResourceManager.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Resources.Writer">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Resources.Writer.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Runtime.CompilerServices.VisualC">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.CompilerServices.VisualC.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Runtime">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Runtime.Extensions">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Extensions.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Runtime.Handles">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Handles.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Runtime.InteropServices">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.InteropServices.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Runtime.InteropServices.RuntimeInformation">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.InteropServices.RuntimeInformation.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Runtime.InteropServices.WindowsRuntime">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.InteropServices.WindowsRuntime.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Runtime.Numerics">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Numerics.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Runtime.Serialization.Formatters">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Serialization.Formatters.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Runtime.Serialization.Json">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Serialization.Json.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Runtime.Serialization.Primitives">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Serialization.Primitives.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Runtime.Serialization.Xml">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Serialization.Xml.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Security.Claims">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Claims.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Security.Cryptography.Algorithms">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Cryptography.Algorithms.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Security.Cryptography.Csp">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Cryptography.Csp.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Security.Cryptography.Encoding">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Cryptography.Encoding.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Security.Cryptography.Primitives">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Cryptography.Primitives.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Security.Cryptography.X509Certificates">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Cryptography.X509Certificates.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Security.Principal">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Principal.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Security.SecureString">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.SecureString.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.ServiceModel.Duplex">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ServiceModel.Duplex.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.ServiceModel.Http">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ServiceModel.Http.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.ServiceModel.NetTcp">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ServiceModel.NetTcp.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.ServiceModel.Primitives">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ServiceModel.Primitives.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.ServiceModel.Security">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ServiceModel.Security.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Text.Encoding">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Text.Encoding.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Text.Encoding.Extensions">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Text.Encoding.Extensions.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Text.RegularExpressions">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Text.RegularExpressions.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Threading">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Threading.Overlapped">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Overlapped.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Threading.Tasks">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Tasks.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Threading.Tasks.Extensions">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Tasks.Extensions.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Threading.Tasks.Parallel">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Tasks.Parallel.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Threading.Thread">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Thread.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Threading.ThreadPool">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.ThreadPool.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Threading.Timer">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Timer.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.ValueTuple">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ValueTuple.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Xml.ReaderWriter">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.ReaderWriter.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Xml.XDocument">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.XDocument.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Xml.XmlDocument">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.XmlDocument.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Xml.XmlSerializer">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.XmlSerializer.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Xml.XPath">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.XPath.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Xml.XPath.XDocument">
|
||||||
|
<HintPath>D:\UnityHubs\2022.3.11f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.XPath.XDocument.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<Target Name="GenerateTargetFrameworkMonikerAttribute" />
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio 15
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Obfuz.Editor", "Obfuz.Editor.csproj", "{61F9FC55-17B9-1093-9FB3-FCD0720BA981}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Obfuz.Runtime", "Obfuz.Runtime.csproj", "{1FE2F0BF-BDED-ACA3-1B41-08AC3002B1B6}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{61F9FC55-17B9-1093-9FB3-FCD0720BA981}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{61F9FC55-17B9-1093-9FB3-FCD0720BA981}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{61F9FC55-17B9-1093-9FB3-FCD0720BA981}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{61F9FC55-17B9-1093-9FB3-FCD0720BA981}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{1FE2F0BF-BDED-ACA3-1B41-08AC3002B1B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{1FE2F0BF-BDED-ACA3-1B41-08AC3002B1B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{1FE2F0BF-BDED-ACA3-1B41-08AC3002B1B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{1FE2F0BF-BDED-ACA3-1B41-08AC3002B1B6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
|
|
@ -0,0 +1,400 @@
|
||||||
|
## 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
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.rsuser
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Mono auto generated files
|
||||||
|
mono_crash.*
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
[Ww][Ii][Nn]32/
|
||||||
|
[Aa][Rr][Mm]/
|
||||||
|
[Aa][Rr][Mm]64/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Ll]og/
|
||||||
|
[Ll]ogs/
|
||||||
|
|
||||||
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# Visual Studio 2017 auto generated files
|
||||||
|
Generated\ Files/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUnit
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
nunit-*.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# Benchmark Results
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
# .NET Core
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
# ASP.NET Scaffolding
|
||||||
|
ScaffoldingReadMe.txt
|
||||||
|
|
||||||
|
# StyleCop
|
||||||
|
StyleCopReport.xml
|
||||||
|
|
||||||
|
# Files built by Visual Studio
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_h.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.iobj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.ipdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
# but not Directory.Build.rsp, as it configures directory-level build defaults
|
||||||
|
!Directory.Build.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*_wpftmp.csproj
|
||||||
|
*.log
|
||||||
|
*.tlog
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# Visual Studio Trace Files
|
||||||
|
*.e2e
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# AxoCover is a Code Coverage Tool
|
||||||
|
.axoCover/*
|
||||||
|
!.axoCover/settings.json
|
||||||
|
|
||||||
|
# Coverlet is a free, cross platform Code Coverage Tool
|
||||||
|
coverage*.json
|
||||||
|
coverage*.xml
|
||||||
|
coverage*.info
|
||||||
|
|
||||||
|
# Visual Studio code coverage results
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||||
|
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||||
|
# in these scripts will be unencrypted
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# NuGet Symbol Packages
|
||||||
|
*.snupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/[Pp]ackages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/[Pp]ackages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/[Pp]ackages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignorable files
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
|
||||||
|
# Windows Store app package directories and files
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
Package.StoreAssociation.xml
|
||||||
|
_pkginfo.txt
|
||||||
|
*.appx
|
||||||
|
*.appxbundle
|
||||||
|
*.appxupload
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!?*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.jfm
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# Including strong name files can present a security risk
|
||||||
|
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||||
|
#*.snk
|
||||||
|
|
||||||
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
|
#bower_components/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
ServiceFabricBackup/
|
||||||
|
*.rptproj.bak
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
*.ndf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
*.rptproj.rsuser
|
||||||
|
*- [Bb]ackup.rdl
|
||||||
|
*- [Bb]ackup ([0-9]).rdl
|
||||||
|
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||||
|
*.vbw
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
|
||||||
|
*.vbp
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
|
||||||
|
*.dsw
|
||||||
|
*.dsp
|
||||||
|
|
||||||
|
# Visual Studio 6 technical files
|
||||||
|
*.ncb
|
||||||
|
*.aps
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
paket-files/
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
||||||
|
|
||||||
|
# CodeRush personal settings
|
||||||
|
.cr/personal
|
||||||
|
|
||||||
|
# Python Tools for Visual Studio (PTVS)
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Cake - Uncomment if you are using it
|
||||||
|
# tools/**
|
||||||
|
# !tools/packages.config
|
||||||
|
|
||||||
|
# Tabs Studio
|
||||||
|
*.tss
|
||||||
|
|
||||||
|
# Telerik's JustMock configuration file
|
||||||
|
*.jmconfig
|
||||||
|
|
||||||
|
# BizTalk build output
|
||||||
|
*.btp.cs
|
||||||
|
*.btm.cs
|
||||||
|
*.odx.cs
|
||||||
|
*.xsd.cs
|
||||||
|
|
||||||
|
# OpenCover UI analysis results
|
||||||
|
OpenCover/
|
||||||
|
|
||||||
|
# Azure Stream Analytics local run output
|
||||||
|
ASALocalRun/
|
||||||
|
|
||||||
|
# MSBuild Binary and Structured Log
|
||||||
|
*.binlog
|
||||||
|
|
||||||
|
# NVidia Nsight GPU debugger configuration file
|
||||||
|
*.nvuser
|
||||||
|
|
||||||
|
# MFractors (Xamarin productivity tool) working folder
|
||||||
|
.mfractor/
|
||||||
|
|
||||||
|
# Local History for Visual Studio
|
||||||
|
.localhistory/
|
||||||
|
|
||||||
|
# Visual Studio History (VSHistory) files
|
||||||
|
.vshistory/
|
||||||
|
|
||||||
|
# BeatPulse healthcheck temp database
|
||||||
|
healthchecksdb
|
||||||
|
|
||||||
|
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||||
|
MigrationBackup/
|
||||||
|
|
||||||
|
# Ionide (cross platform F# VS Code tools) working folder
|
||||||
|
.ionide/
|
||||||
|
|
||||||
|
# Fody - auto-generated XML schema
|
||||||
|
FodyWeavers.xsd
|
||||||
|
|
||||||
|
# VS Code files for those working on multiple tools
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
*.code-workspace
|
||||||
|
|
||||||
|
# Local History for Visual Studio Code
|
||||||
|
.history/
|
||||||
|
|
||||||
|
# Windows Installer files from build outputs
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msix
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# JetBrains Rider
|
||||||
|
*.sln.iml
|
||||||
|
|
@ -0,0 +1,267 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using Obfuz.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml;
|
||||||
|
using UnityEditor.VersionControl;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Obfuz.Conf
|
||||||
|
{
|
||||||
|
public interface IRule<T>
|
||||||
|
{
|
||||||
|
void InheritParent(T parentRule);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public interface IMethodRule<R> where R: IRule<R>
|
||||||
|
{
|
||||||
|
string Name { get; set; }
|
||||||
|
NameMatcher NameMatcher { get; set; }
|
||||||
|
|
||||||
|
R Rule { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class MethodRuleBase<R> : IMethodRule<R> where R : IRule<R>
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public NameMatcher NameMatcher { get; set; }
|
||||||
|
|
||||||
|
public R Rule { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ITypeRule<T, R> where T: IMethodRule<R> where R : IRule<R>
|
||||||
|
{
|
||||||
|
string Name { get; set; }
|
||||||
|
|
||||||
|
NameMatcher NameMatcher { get; set; }
|
||||||
|
|
||||||
|
R Rule { get; set; }
|
||||||
|
|
||||||
|
List<T> Methods { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class TypeRuleBase<T, R> : ITypeRule<T, R> where T : IMethodRule<R> where R : IRule<R>
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public NameMatcher NameMatcher { get; set; }
|
||||||
|
|
||||||
|
public R Rule { get; set; }
|
||||||
|
|
||||||
|
public List<T> Methods { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IAssemblyRule<TType, TMethod, TRule> where TType : ITypeRule<TMethod, TRule> where TMethod : IMethodRule<TRule> where TRule : IRule<TRule>
|
||||||
|
{
|
||||||
|
string Name { get; set; }
|
||||||
|
|
||||||
|
TRule Rule { get; set; }
|
||||||
|
|
||||||
|
List<TType> Types { get; set; }
|
||||||
|
}
|
||||||
|
public abstract class AssemblyRuleBase<TType, TMethod, TRule> : IAssemblyRule<TType, TMethod, TRule> where TType : ITypeRule<TMethod, TRule> where TMethod : IMethodRule<TRule> where TRule : IRule<TRule>
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public TRule Rule { get; set; }
|
||||||
|
|
||||||
|
public List<TType> Types { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class XmlAssemblyTypeMethodRuleParser<TAssembly, TType, TMethod, TRule>
|
||||||
|
where TMethod : IMethodRule<TRule>, new()
|
||||||
|
where TType : ITypeRule<TMethod, TRule>, new()
|
||||||
|
where TAssembly : IAssemblyRule<TType, TMethod, TRule>, new()
|
||||||
|
where TRule : IRule<TRule>, new()
|
||||||
|
{
|
||||||
|
private readonly HashSet<string> _toObfuscatedAssemblyNames;
|
||||||
|
private readonly Func<string, XmlElement, TRule> _ruleParser;
|
||||||
|
private readonly Action<string, XmlElement> _unknownNodeTypeHandler;
|
||||||
|
private readonly Dictionary<string, TAssembly> _assemblySpecs = new Dictionary<string, TAssembly>();
|
||||||
|
|
||||||
|
public XmlAssemblyTypeMethodRuleParser(IEnumerable<string> toObfuscatedAssemblyNames, Func<string, XmlElement, TRule> ruleParser, Action<string, XmlElement> unknownNodeTypeHandler)
|
||||||
|
{
|
||||||
|
_toObfuscatedAssemblyNames = new HashSet<string>(toObfuscatedAssemblyNames);
|
||||||
|
_ruleParser = ruleParser;
|
||||||
|
_unknownNodeTypeHandler = unknownNodeTypeHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dictionary<string, TAssembly> AssemblySpecs => _assemblySpecs;
|
||||||
|
|
||||||
|
public void LoadConfigs(IEnumerable<string> configFiles)
|
||||||
|
{
|
||||||
|
foreach (var configFile in configFiles)
|
||||||
|
{
|
||||||
|
LoadConfig(configFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadConfig(string configFile)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(configFile))
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file {configFile}, file name is empty");
|
||||||
|
}
|
||||||
|
Debug.Log($"ConfigurableObfuscationPolicy::LoadConfig {configFile}");
|
||||||
|
var doc = new XmlDocument();
|
||||||
|
doc.Load(configFile);
|
||||||
|
var root = doc.DocumentElement;
|
||||||
|
if (root.Name != "obfuz")
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file {configFile}, root name should be 'obfuz'");
|
||||||
|
}
|
||||||
|
foreach (XmlNode node in root.ChildNodes)
|
||||||
|
{
|
||||||
|
if (!(node is XmlElement ele))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (ele.Name)
|
||||||
|
{
|
||||||
|
case "assembly":
|
||||||
|
{
|
||||||
|
TAssembly assSpec = ParseAssembly(configFile, ele);
|
||||||
|
_assemblySpecs.Add(assSpec.Name, assSpec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
if (_unknownNodeTypeHandler == null)
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file {configFile}, unknown node {ele.Name}");
|
||||||
|
}
|
||||||
|
_unknownNodeTypeHandler(configFile, ele);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private TAssembly ParseAssembly(string configFile, XmlElement ele)
|
||||||
|
{
|
||||||
|
var assemblySpec = new TAssembly();
|
||||||
|
string name = ele.GetAttribute("name");
|
||||||
|
if (!_toObfuscatedAssemblyNames.Contains(name))
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file {configFile}, assembly name {name} isn't in toObfuscatedAssemblyNames");
|
||||||
|
}
|
||||||
|
if (_assemblySpecs.ContainsKey(name))
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file {configFile}, assembly name {name} is duplicated");
|
||||||
|
}
|
||||||
|
assemblySpec.Name = name;
|
||||||
|
assemblySpec.Rule = _ruleParser(configFile, ele);
|
||||||
|
|
||||||
|
var types = new List<TType>();
|
||||||
|
assemblySpec.Types = types;
|
||||||
|
foreach (XmlNode node in ele.ChildNodes)
|
||||||
|
{
|
||||||
|
if (!(node is XmlElement childEle))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (childEle.Name)
|
||||||
|
{
|
||||||
|
case "type":
|
||||||
|
{
|
||||||
|
types.Add(ParseType(configFile, childEle));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file, unknown node {childEle.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return assemblySpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TType ParseType(string configFile, XmlElement element)
|
||||||
|
{
|
||||||
|
var typeSpec = new TType();
|
||||||
|
|
||||||
|
string name = element.GetAttribute("name");
|
||||||
|
typeSpec.Name = name;
|
||||||
|
typeSpec.NameMatcher = new NameMatcher(name);
|
||||||
|
typeSpec.Rule = _ruleParser(configFile, element);
|
||||||
|
|
||||||
|
var methods = new List<TMethod>();
|
||||||
|
typeSpec.Methods = methods;
|
||||||
|
foreach (XmlNode node in element.ChildNodes)
|
||||||
|
{
|
||||||
|
if (!(node is XmlElement ele))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (ele.Name)
|
||||||
|
{
|
||||||
|
case "method":
|
||||||
|
{
|
||||||
|
methods.Add(ParseMethod(configFile, ele));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file, unknown node {ele.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return typeSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TMethod ParseMethod(string configFile, XmlElement element)
|
||||||
|
{
|
||||||
|
var methodSpec = new TMethod();
|
||||||
|
string name = element.GetAttribute("name");
|
||||||
|
methodSpec.Name = name;
|
||||||
|
methodSpec.NameMatcher = new NameMatcher(name);
|
||||||
|
methodSpec.Rule = _ruleParser(configFile, element);
|
||||||
|
return methodSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TRule GetMethodRule(MethodDef method, TRule defaultRule)
|
||||||
|
{
|
||||||
|
var assemblyName = method.DeclaringType.Module.Assembly.Name;
|
||||||
|
if (!_assemblySpecs.TryGetValue(assemblyName, out var assSpec))
|
||||||
|
{
|
||||||
|
return defaultRule;
|
||||||
|
}
|
||||||
|
string declaringTypeName = method.DeclaringType.FullName;
|
||||||
|
foreach (var typeSpec in assSpec.Types)
|
||||||
|
{
|
||||||
|
if (typeSpec.NameMatcher.IsMatch(declaringTypeName))
|
||||||
|
{
|
||||||
|
foreach (var methodSpec in typeSpec.Methods)
|
||||||
|
{
|
||||||
|
if (methodSpec.NameMatcher.IsMatch(method.Name))
|
||||||
|
{
|
||||||
|
return methodSpec.Rule;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return typeSpec.Rule;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return assSpec.Rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InheritParentRules(TRule defaultRule)
|
||||||
|
{
|
||||||
|
foreach (TAssembly assSpec in _assemblySpecs.Values)
|
||||||
|
{
|
||||||
|
assSpec.Rule.InheritParent(defaultRule);
|
||||||
|
foreach (TType typeSpec in assSpec.Types)
|
||||||
|
{
|
||||||
|
typeSpec.Rule.InheritParent(assSpec.Rule);
|
||||||
|
foreach (TMethod methodSpec in typeSpec.Methods)
|
||||||
|
{
|
||||||
|
methodSpec.Rule.InheritParent(typeSpec.Rule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,208 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using Obfuz.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml;
|
||||||
|
using UnityEditor.VersionControl;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Obfuz.Conf
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class XmlFieldRuleParser<R> where R : class, new()
|
||||||
|
{
|
||||||
|
private readonly HashSet<string> _toObfuscatedAssemblyNames;
|
||||||
|
private readonly Func<string, XmlElement, R> _ruleParser;
|
||||||
|
private readonly Action<string, XmlElement> _unknownNodeTypeHandler;
|
||||||
|
private readonly Dictionary<string, AssemblySpec> _assemblySpecs = new Dictionary<string, AssemblySpec>();
|
||||||
|
|
||||||
|
|
||||||
|
private class FieldSpec
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public NameMatcher NameMatcher { get; set; }
|
||||||
|
|
||||||
|
public R Rule { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TypeSpec
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public NameMatcher NameMatcher { get; set; }
|
||||||
|
|
||||||
|
public List<FieldSpec> Fields { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class AssemblySpec
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public List<TypeSpec> Types { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public XmlFieldRuleParser(IEnumerable<string> toObfuscatedAssemblyNames, Func<string, XmlElement, R> ruleParser, Action<string, XmlElement> unknownNodeTypeHandler)
|
||||||
|
{
|
||||||
|
_toObfuscatedAssemblyNames = new HashSet<string>(toObfuscatedAssemblyNames);
|
||||||
|
_ruleParser = ruleParser;
|
||||||
|
_unknownNodeTypeHandler = unknownNodeTypeHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadConfigs(IEnumerable<string> configFiles)
|
||||||
|
{
|
||||||
|
foreach (var configFile in configFiles)
|
||||||
|
{
|
||||||
|
LoadConfig(configFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadConfig(string configFile)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(configFile))
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file {configFile}, file name is empty");
|
||||||
|
}
|
||||||
|
var doc = new XmlDocument();
|
||||||
|
doc.Load(configFile);
|
||||||
|
var root = doc.DocumentElement;
|
||||||
|
if (root.Name != "obfuz")
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file {configFile}, root name should be 'obfuz'");
|
||||||
|
}
|
||||||
|
foreach (XmlNode node in root.ChildNodes)
|
||||||
|
{
|
||||||
|
if (!(node is XmlElement ele))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (ele.Name)
|
||||||
|
{
|
||||||
|
case "assembly":
|
||||||
|
{
|
||||||
|
AssemblySpec assSpec = ParseAssembly(configFile, ele);
|
||||||
|
_assemblySpecs.Add(assSpec.Name, assSpec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
if (_unknownNodeTypeHandler == null)
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file {configFile}, unknown node {ele.Name}");
|
||||||
|
}
|
||||||
|
_unknownNodeTypeHandler(configFile, ele);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private AssemblySpec ParseAssembly(string configFile, XmlElement ele)
|
||||||
|
{
|
||||||
|
var assemblySpec = new AssemblySpec();
|
||||||
|
string name = ele.GetAttribute("name");
|
||||||
|
if (!_toObfuscatedAssemblyNames.Contains(name))
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file {configFile}, assembly name {name} isn't in toObfuscatedAssemblyNames");
|
||||||
|
}
|
||||||
|
if (_assemblySpecs.ContainsKey(name))
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file {configFile}, assembly name {name} is duplicated");
|
||||||
|
}
|
||||||
|
assemblySpec.Name = name;
|
||||||
|
|
||||||
|
var types = new List<TypeSpec>();
|
||||||
|
assemblySpec.Types = types;
|
||||||
|
foreach (XmlNode node in ele.ChildNodes)
|
||||||
|
{
|
||||||
|
if (!(node is XmlElement childEle))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (childEle.Name)
|
||||||
|
{
|
||||||
|
case "type":
|
||||||
|
{
|
||||||
|
types.Add(ParseType(configFile, childEle));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file, unknown node {childEle.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return assemblySpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TypeSpec ParseType(string configFile, XmlElement element)
|
||||||
|
{
|
||||||
|
var typeSpec = new TypeSpec();
|
||||||
|
|
||||||
|
string name = element.GetAttribute("name");
|
||||||
|
typeSpec.Name = name;
|
||||||
|
typeSpec.NameMatcher = new NameMatcher(name);
|
||||||
|
|
||||||
|
var fields = new List<FieldSpec>();
|
||||||
|
typeSpec.Fields = fields;
|
||||||
|
foreach (XmlNode node in element.ChildNodes)
|
||||||
|
{
|
||||||
|
if (!(node is XmlElement ele))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (ele.Name)
|
||||||
|
{
|
||||||
|
case "field":
|
||||||
|
{
|
||||||
|
fields.Add(ParseField(configFile, ele));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file, unknown node {ele.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return typeSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
private FieldSpec ParseField(string configFile, XmlElement element)
|
||||||
|
{
|
||||||
|
var fieldSpec = new FieldSpec();
|
||||||
|
string name = element.GetAttribute("name");
|
||||||
|
fieldSpec.Name = name;
|
||||||
|
fieldSpec.NameMatcher = new NameMatcher(name);
|
||||||
|
fieldSpec.Rule = _ruleParser(configFile, element);
|
||||||
|
return fieldSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
public R GetFieldRule(FieldDef field)
|
||||||
|
{
|
||||||
|
var assemblyName = field.DeclaringType.Module.Assembly.Name;
|
||||||
|
if (!_assemblySpecs.TryGetValue(assemblyName, out var assSpec))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
string declaringTypeName = field.DeclaringType.FullName;
|
||||||
|
foreach (var typeSpec in assSpec.Types)
|
||||||
|
{
|
||||||
|
if (typeSpec.NameMatcher.IsMatch(declaringTypeName))
|
||||||
|
{
|
||||||
|
foreach (var fieldSpec in typeSpec.Fields)
|
||||||
|
{
|
||||||
|
if (fieldSpec.NameMatcher.IsMatch(field.Name))
|
||||||
|
{
|
||||||
|
return fieldSpec.Rule;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,547 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using Obfuz.ObfusPasses;
|
||||||
|
using Obfuz.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Obfuz
|
||||||
|
{
|
||||||
|
public class ConfigurablePassPolicy
|
||||||
|
{
|
||||||
|
class PassRule
|
||||||
|
{
|
||||||
|
public ObfuscationPassType? enablePasses;
|
||||||
|
public ObfuscationPassType? disablePasses;
|
||||||
|
public ObfuscationPassType? addPasses;
|
||||||
|
public ObfuscationPassType? removePasses;
|
||||||
|
public ObfuscationPassType finalPasses;
|
||||||
|
|
||||||
|
public void InheritParent(PassRule parentRule, ObfuscationPassType globalEnabledPasses)
|
||||||
|
{
|
||||||
|
finalPasses = parentRule.finalPasses;
|
||||||
|
if (enablePasses != null)
|
||||||
|
{
|
||||||
|
finalPasses = enablePasses.Value;
|
||||||
|
}
|
||||||
|
if (disablePasses != null)
|
||||||
|
{
|
||||||
|
finalPasses = ~disablePasses.Value;
|
||||||
|
}
|
||||||
|
if (addPasses != null)
|
||||||
|
{
|
||||||
|
finalPasses |= addPasses.Value;
|
||||||
|
}
|
||||||
|
if (removePasses != null)
|
||||||
|
{
|
||||||
|
finalPasses &= ~removePasses.Value;
|
||||||
|
}
|
||||||
|
finalPasses &= globalEnabledPasses;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SpecBase
|
||||||
|
{
|
||||||
|
public string name;
|
||||||
|
public NameMatcher nameMatcher;
|
||||||
|
public PassRule rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MethodSpec : SpecBase
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
class FieldSpec : SpecBase
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
class PropertySpec : SpecBase
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
class EventSpec : SpecBase
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
class TypeSpec : SpecBase
|
||||||
|
{
|
||||||
|
public List<FieldSpec> fields = new List<FieldSpec>();
|
||||||
|
public List<MethodSpec> methods = new List<MethodSpec>();
|
||||||
|
public List<PropertySpec> properties = new List<PropertySpec>();
|
||||||
|
public List<EventSpec> events = new List<EventSpec>();
|
||||||
|
}
|
||||||
|
|
||||||
|
class AssemblySpec
|
||||||
|
{
|
||||||
|
public string name;
|
||||||
|
public NameMatcher nameMatcher;
|
||||||
|
public PassRule rule;
|
||||||
|
public List<TypeSpec> types = new List<TypeSpec>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly ObfuscationPassType _enabledPasses;
|
||||||
|
private readonly HashSet<string> _toObfuscatedAssemblyNames;
|
||||||
|
private readonly List<AssemblySpec> _assemblySpecs = new List<AssemblySpec>();
|
||||||
|
private readonly PassRule _defaultPassRule;
|
||||||
|
|
||||||
|
private string _curLoadingConfig;
|
||||||
|
|
||||||
|
public ConfigurablePassPolicy(IEnumerable<string> toObfuscatedAssemblyNames, ObfuscationPassType enabledPasses, List<string> configFiles)
|
||||||
|
{
|
||||||
|
_toObfuscatedAssemblyNames = new HashSet<string>(toObfuscatedAssemblyNames);
|
||||||
|
_enabledPasses = enabledPasses;
|
||||||
|
_defaultPassRule = new PassRule { finalPasses = enabledPasses };
|
||||||
|
LoadConfigs(configFiles);
|
||||||
|
InheritParentRules(enabledPasses);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadConfigs(IEnumerable<string> configFiles)
|
||||||
|
{
|
||||||
|
foreach (var configFile in configFiles)
|
||||||
|
{
|
||||||
|
LoadConfig(configFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InheritParentRules(ObfuscationPassType enablePasses)
|
||||||
|
{
|
||||||
|
var defaultRule = new PassRule
|
||||||
|
{
|
||||||
|
enablePasses = enablePasses,
|
||||||
|
finalPasses = enablePasses,
|
||||||
|
};
|
||||||
|
foreach (AssemblySpec assSpec in _assemblySpecs)
|
||||||
|
{
|
||||||
|
assSpec.rule.InheritParent(defaultRule, enablePasses);
|
||||||
|
foreach (TypeSpec typeSpec in assSpec.types)
|
||||||
|
{
|
||||||
|
typeSpec.rule.InheritParent(assSpec.rule, enablePasses);
|
||||||
|
foreach (FieldSpec fieldSpec in typeSpec.fields)
|
||||||
|
{
|
||||||
|
fieldSpec.rule.InheritParent(typeSpec.rule, enablePasses);
|
||||||
|
}
|
||||||
|
foreach (MethodSpec methodSpec in typeSpec.methods)
|
||||||
|
{
|
||||||
|
methodSpec.rule.InheritParent(typeSpec.rule, enablePasses);
|
||||||
|
}
|
||||||
|
foreach (PropertySpec propertySpec in typeSpec.properties)
|
||||||
|
{
|
||||||
|
propertySpec.rule.InheritParent(typeSpec.rule, enablePasses);
|
||||||
|
}
|
||||||
|
foreach (EventSpec eventSpec in typeSpec.events)
|
||||||
|
{
|
||||||
|
eventSpec.rule.InheritParent(typeSpec.rule, enablePasses);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadConfig(string configFile)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(configFile))
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file {configFile}, file name is empty");
|
||||||
|
}
|
||||||
|
_curLoadingConfig = configFile;
|
||||||
|
|
||||||
|
Debug.Log($"ConfigurablePassPolicy::LoadConfig {configFile}");
|
||||||
|
var doc = new XmlDocument();
|
||||||
|
doc.Load(configFile);
|
||||||
|
var root = doc.DocumentElement;
|
||||||
|
if (root.Name != "obfuz")
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file {configFile}, root name should be 'obfuz'");
|
||||||
|
}
|
||||||
|
foreach (XmlNode node in root.ChildNodes)
|
||||||
|
{
|
||||||
|
if (!(node is XmlElement ele))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (ele.Name)
|
||||||
|
{
|
||||||
|
case "assembly":
|
||||||
|
{
|
||||||
|
AssemblySpec assSpec = ParseAssembly(ele);
|
||||||
|
_assemblySpecs.Add(assSpec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file {configFile}, unknown node {ele.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(bool, ObfuscationPassType) ParseObfuscationType(string obfuscationPassTypesStr)
|
||||||
|
{
|
||||||
|
bool delta = false;
|
||||||
|
if (obfuscationPassTypesStr[0] == '+' || obfuscationPassTypesStr[0] == '-')
|
||||||
|
{
|
||||||
|
delta = true;
|
||||||
|
obfuscationPassTypesStr = obfuscationPassTypesStr.Substring(1);
|
||||||
|
}
|
||||||
|
ObfuscationPassType passType = ObfuscationPassType.None;
|
||||||
|
foreach (var passName in obfuscationPassTypesStr.Split('|'))
|
||||||
|
{
|
||||||
|
if (Enum.TryParse< ObfuscationPassType>(passName, out var pass))
|
||||||
|
{
|
||||||
|
passType |= pass;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file {_curLoadingConfig}, unknown pass type {passName}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (delta, passType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PassRule ParseRule(XmlElement ele)
|
||||||
|
{
|
||||||
|
var r = new PassRule();
|
||||||
|
if (ele.HasAttribute("enable"))
|
||||||
|
{
|
||||||
|
string enablePassStr = ele.GetAttribute("enable");
|
||||||
|
if (string.IsNullOrEmpty(enablePassStr))
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file {_curLoadingConfig}, enable attribute is empty");
|
||||||
|
}
|
||||||
|
var (delta, passType) = ParseObfuscationType(enablePassStr);
|
||||||
|
if (delta)
|
||||||
|
{
|
||||||
|
r.addPasses = passType;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
r.enablePasses = passType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ele.HasAttribute("disable"))
|
||||||
|
{
|
||||||
|
string disablePassStr = ele.GetAttribute("disable");
|
||||||
|
if (string.IsNullOrEmpty(disablePassStr))
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file {_curLoadingConfig}, disable attribute is empty");
|
||||||
|
}
|
||||||
|
var (delta, passType) = ParseObfuscationType(disablePassStr);
|
||||||
|
if (delta)
|
||||||
|
{
|
||||||
|
r.removePasses = passType;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
r.disablePasses = passType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (r.enablePasses != null && (r.disablePasses != null || r.addPasses != null || r.removePasses != null))
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file {_curLoadingConfig}, enable and disable can't be used together");
|
||||||
|
}
|
||||||
|
if (r.disablePasses != null && (r.enablePasses != null || r.addPasses != null || r.removePasses != null))
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file {_curLoadingConfig}, disable and enable can't be used together");
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AssemblySpec ParseAssembly(XmlElement ele)
|
||||||
|
{
|
||||||
|
var assemblySpec = new AssemblySpec();
|
||||||
|
string name = ele.GetAttribute("name");
|
||||||
|
if (!_toObfuscatedAssemblyNames.Contains(name))
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file {_curLoadingConfig}, assembly name {name} isn't in toObfuscatedAssemblyNames");
|
||||||
|
}
|
||||||
|
assemblySpec.name = name;
|
||||||
|
assemblySpec.nameMatcher = new NameMatcher(name);
|
||||||
|
assemblySpec.rule = ParseRule(ele);
|
||||||
|
|
||||||
|
|
||||||
|
var types = assemblySpec.types;
|
||||||
|
foreach (XmlNode node in ele.ChildNodes)
|
||||||
|
{
|
||||||
|
if (!(node is XmlElement childEle))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (childEle.Name)
|
||||||
|
{
|
||||||
|
case "type":
|
||||||
|
{
|
||||||
|
types.Add(ParseType(childEle));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file, unknown node {childEle.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return assemblySpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TypeSpec ParseType(XmlElement element)
|
||||||
|
{
|
||||||
|
var typeSpec = new TypeSpec();
|
||||||
|
|
||||||
|
string name = element.GetAttribute("name");
|
||||||
|
typeSpec.name = name;
|
||||||
|
typeSpec.nameMatcher = new NameMatcher(name);
|
||||||
|
typeSpec.rule = ParseRule(element);
|
||||||
|
|
||||||
|
List<FieldSpec> fields = typeSpec.fields;
|
||||||
|
List<MethodSpec> methods = typeSpec.methods;
|
||||||
|
List<PropertySpec> properties = typeSpec.properties;
|
||||||
|
List<EventSpec> events = typeSpec.events;
|
||||||
|
foreach (XmlNode node in element.ChildNodes)
|
||||||
|
{
|
||||||
|
if (!(node is XmlElement ele))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (ele.Name)
|
||||||
|
{
|
||||||
|
case "field":
|
||||||
|
{
|
||||||
|
fields.Add(ParseField(ele));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "method":
|
||||||
|
{
|
||||||
|
methods.Add(ParseMethod(ele));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "property":
|
||||||
|
{
|
||||||
|
properties.Add(ParseProperty(ele));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "event":
|
||||||
|
{
|
||||||
|
events.Add(ParseEvent(ele));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file, unknown node {ele.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return typeSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ParseSpecObject(XmlElement element, SpecBase obj)
|
||||||
|
{
|
||||||
|
string name = element.GetAttribute("name");
|
||||||
|
obj.name = name;
|
||||||
|
obj.nameMatcher = new NameMatcher(name);
|
||||||
|
obj.rule = ParseRule(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
private FieldSpec ParseField(XmlElement element)
|
||||||
|
{
|
||||||
|
var fieldSpec = new FieldSpec();
|
||||||
|
ParseSpecObject(element, fieldSpec);
|
||||||
|
return fieldSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MethodSpec ParseMethod(XmlElement element)
|
||||||
|
{
|
||||||
|
var methodSpec = new MethodSpec();
|
||||||
|
ParseSpecObject(element, methodSpec);
|
||||||
|
return methodSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PropertySpec ParseProperty(XmlElement element)
|
||||||
|
{
|
||||||
|
var propertySpec = new PropertySpec();
|
||||||
|
ParseSpecObject(element, propertySpec);
|
||||||
|
return propertySpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
private EventSpec ParseEvent(XmlElement element)
|
||||||
|
{
|
||||||
|
var eventSpec = new EventSpec();
|
||||||
|
ParseSpecObject(element, eventSpec);
|
||||||
|
return eventSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Dictionary<ModuleDef, (AssemblySpec, PassRule)> _modulePassRuleCaches = new Dictionary<ModuleDef, (AssemblySpec, PassRule)>();
|
||||||
|
private readonly Dictionary<TypeDef, (TypeSpec, PassRule)> _typePassRuleCaches = new Dictionary<TypeDef, (TypeSpec, PassRule)>();
|
||||||
|
private readonly Dictionary<MethodDef, (MethodSpec, PassRule)> _methodPassRuleCaches = new Dictionary<MethodDef, (MethodSpec, PassRule)>();
|
||||||
|
private readonly Dictionary<FieldDef, (FieldSpec, PassRule)> _fieldPassRuleCaches = new Dictionary<FieldDef, (FieldSpec, PassRule)>();
|
||||||
|
private readonly Dictionary<PropertyDef, (PropertySpec, PassRule)> _propertyPassRuleCaches = new Dictionary<PropertyDef, (PropertySpec, PassRule)>();
|
||||||
|
private readonly Dictionary<EventDef, (EventSpec, PassRule)> _eventPassRuleCaches = new Dictionary<EventDef, (EventSpec, PassRule)>();
|
||||||
|
|
||||||
|
|
||||||
|
private (AssemblySpec, PassRule) GetAssemblySpec(ModuleDef module)
|
||||||
|
{
|
||||||
|
if (!_modulePassRuleCaches.TryGetValue(module, out var result))
|
||||||
|
{
|
||||||
|
result = (null, _defaultPassRule);
|
||||||
|
string assName = module.Assembly.Name;
|
||||||
|
foreach (var ass in _assemblySpecs)
|
||||||
|
{
|
||||||
|
if (ass.nameMatcher.IsMatch(assName))
|
||||||
|
{
|
||||||
|
result = (ass, _defaultPassRule);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_modulePassRuleCaches.Add(module, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private (TypeSpec, PassRule) GetTypeSpec(TypeDef type)
|
||||||
|
{
|
||||||
|
if (!_typePassRuleCaches.TryGetValue(type, out var result))
|
||||||
|
{
|
||||||
|
var assResult = GetAssemblySpec(type.Module);
|
||||||
|
result = (null, assResult.Item2);
|
||||||
|
if (assResult.Item1 != null)
|
||||||
|
{
|
||||||
|
string typeName = type.FullName;
|
||||||
|
foreach (var typeSpec in assResult.Item1.types)
|
||||||
|
{
|
||||||
|
if (typeSpec.nameMatcher.IsMatch(typeName))
|
||||||
|
{
|
||||||
|
result = (typeSpec, typeSpec.rule);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_typePassRuleCaches.Add(type, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private (MethodSpec, PassRule) GetMethodSpec(MethodDef method)
|
||||||
|
{
|
||||||
|
if (!_methodPassRuleCaches.TryGetValue(method, out var result))
|
||||||
|
{
|
||||||
|
var typeResult = GetTypeSpec(method.DeclaringType);
|
||||||
|
result = (null, typeResult.Item2);
|
||||||
|
if (typeResult.Item1 != null)
|
||||||
|
{
|
||||||
|
string methodName = method.Name;
|
||||||
|
foreach (var methodSpec in typeResult.Item1.methods)
|
||||||
|
{
|
||||||
|
if (methodSpec.nameMatcher.IsMatch(methodName))
|
||||||
|
{
|
||||||
|
result = (methodSpec, methodSpec.rule);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_methodPassRuleCaches.Add(method, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private (FieldSpec, PassRule) GetFieldSpec(FieldDef field)
|
||||||
|
{
|
||||||
|
if (!_fieldPassRuleCaches.TryGetValue(field, out var result))
|
||||||
|
{
|
||||||
|
var typeResult = GetTypeSpec(field.DeclaringType);
|
||||||
|
result = (null, typeResult.Item2);
|
||||||
|
if (typeResult.Item1 != null)
|
||||||
|
{
|
||||||
|
string fieldName = field.Name;
|
||||||
|
foreach (var fieldSpec in typeResult.Item1.fields)
|
||||||
|
{
|
||||||
|
if (fieldSpec.nameMatcher.IsMatch(fieldName))
|
||||||
|
{
|
||||||
|
result = (fieldSpec, fieldSpec.rule);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_fieldPassRuleCaches.Add(field, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private (PropertySpec, PassRule) GetPropertySpec(PropertyDef property)
|
||||||
|
{
|
||||||
|
if (!_propertyPassRuleCaches.TryGetValue(property, out var result))
|
||||||
|
{
|
||||||
|
var typeResult = GetTypeSpec(property.DeclaringType);
|
||||||
|
result = (null, typeResult.Item2);
|
||||||
|
if (typeResult.Item1 != null)
|
||||||
|
{
|
||||||
|
string propertyName = property.Name;
|
||||||
|
foreach (var propertySpec in typeResult.Item1.properties)
|
||||||
|
{
|
||||||
|
if (propertySpec.nameMatcher.IsMatch(propertyName))
|
||||||
|
{
|
||||||
|
result = (propertySpec, propertySpec.rule);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_propertyPassRuleCaches.Add(property, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private (EventSpec, PassRule) GetEventSpec(EventDef eventDef)
|
||||||
|
{
|
||||||
|
if (!_eventPassRuleCaches.TryGetValue(eventDef, out var result))
|
||||||
|
{
|
||||||
|
var typeResult = GetTypeSpec(eventDef.DeclaringType);
|
||||||
|
result = (null, typeResult.Item2);
|
||||||
|
if (typeResult.Item1 != null)
|
||||||
|
{
|
||||||
|
string eventName = eventDef.Name;
|
||||||
|
foreach (var eventSpec in typeResult.Item1.events)
|
||||||
|
{
|
||||||
|
if (eventSpec.nameMatcher.IsMatch(eventName))
|
||||||
|
{
|
||||||
|
result = (eventSpec, eventSpec.rule);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_eventPassRuleCaches.Add(eventDef, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public ObfuscationPassType GetAssemblyObfuscationPasses(ModuleDef module)
|
||||||
|
{
|
||||||
|
return GetAssemblySpec(module).Item2.finalPasses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObfuscationPassType GetTypeObfuscationPasses(TypeDef type)
|
||||||
|
{
|
||||||
|
return GetTypeSpec(type).Item2.finalPasses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObfuscationPassType GetMethodObfuscationPasses(MethodDef method)
|
||||||
|
{
|
||||||
|
return GetMethodSpec(method).Item2.finalPasses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObfuscationPassType GetFieldObfuscationPasses(FieldDef field)
|
||||||
|
{
|
||||||
|
return GetFieldSpec(field).Item2.finalPasses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObfuscationPassType GetPropertyObfuscationPasses(PropertyDef property)
|
||||||
|
{
|
||||||
|
return GetPropertySpec(property).Item2.finalPasses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObfuscationPassType GetEventObfuscationPasses(EventDef eventDef)
|
||||||
|
{
|
||||||
|
return GetEventSpec(eventDef).Item2.finalPasses;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.Editor
|
||||||
|
{
|
||||||
|
public static class ConstValues
|
||||||
|
{
|
||||||
|
public const string ObfuzInternalSymbolNamePrefix = "$Obfuz$";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,344 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using dnlib.DotNet.Emit;
|
||||||
|
using Obfuz.Editor;
|
||||||
|
using Obfuz.Emit;
|
||||||
|
using Obfuz.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.NetworkInformation;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Assertions;
|
||||||
|
|
||||||
|
namespace Obfuz.Data
|
||||||
|
{
|
||||||
|
public class ModuleConstFieldAllocator : IGroupByModuleEntity
|
||||||
|
{
|
||||||
|
private ModuleDef _module;
|
||||||
|
private readonly EncryptionScopeProvider _encryptionScopeProvider;
|
||||||
|
private readonly RvaDataAllocator _rvaDataAllocator;
|
||||||
|
private readonly GroupByModuleEntityManager _moduleEntityManager;
|
||||||
|
private EncryptionScopeInfo _encryptionScope;
|
||||||
|
private RandomCreator _randomCreator;
|
||||||
|
private IEncryptor _encryptor;
|
||||||
|
|
||||||
|
private TypeDef _holderTypeDef;
|
||||||
|
|
||||||
|
class ConstFieldInfo
|
||||||
|
{
|
||||||
|
public FieldDef field;
|
||||||
|
public object value;
|
||||||
|
}
|
||||||
|
|
||||||
|
class AnyComparer : IEqualityComparer<object>
|
||||||
|
{
|
||||||
|
public new bool Equals(object x, object y)
|
||||||
|
{
|
||||||
|
if (x is byte[] xBytes && y is byte[] yBytes)
|
||||||
|
{
|
||||||
|
return StructuralComparisons.StructuralEqualityComparer.Equals(xBytes, yBytes);
|
||||||
|
}
|
||||||
|
return x.Equals(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int ComputeHashCode(object obj)
|
||||||
|
{
|
||||||
|
return HashUtil.ComputePrimitiveOrStringOrBytesHashCode(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetHashCode(object obj)
|
||||||
|
{
|
||||||
|
return ComputeHashCode(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Dictionary<object, ConstFieldInfo> _allocatedFields = new Dictionary<object, ConstFieldInfo>(new AnyComparer());
|
||||||
|
private readonly Dictionary<FieldDef, ConstFieldInfo> _field2Fields = new Dictionary<FieldDef, ConstFieldInfo>();
|
||||||
|
|
||||||
|
private readonly List<TypeDef> _holderTypeDefs = new List<TypeDef>();
|
||||||
|
private bool _done;
|
||||||
|
|
||||||
|
|
||||||
|
public ModuleConstFieldAllocator(EncryptionScopeProvider encryptionScopeProvider, RvaDataAllocator rvaDataAllocator, GroupByModuleEntityManager moduleEntityManager)
|
||||||
|
{
|
||||||
|
_encryptionScopeProvider = encryptionScopeProvider;
|
||||||
|
_rvaDataAllocator = rvaDataAllocator;
|
||||||
|
_moduleEntityManager = moduleEntityManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Init(ModuleDef mod)
|
||||||
|
{
|
||||||
|
_module = mod;
|
||||||
|
_encryptionScope = _encryptionScopeProvider.GetScope(mod);
|
||||||
|
_randomCreator = _encryptionScope.localRandomCreator;
|
||||||
|
_encryptor = _encryptionScope.encryptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int maxFieldCount = 1000;
|
||||||
|
|
||||||
|
|
||||||
|
private TypeSig GetTypeSigOfValue(object value)
|
||||||
|
{
|
||||||
|
if (value is int)
|
||||||
|
return _module.CorLibTypes.Int32;
|
||||||
|
if (value is long)
|
||||||
|
return _module.CorLibTypes.Int64;
|
||||||
|
if (value is float)
|
||||||
|
return _module.CorLibTypes.Single;
|
||||||
|
if (value is double)
|
||||||
|
return _module.CorLibTypes.Double;
|
||||||
|
if (value is string)
|
||||||
|
return _module.CorLibTypes.String;
|
||||||
|
if (value is byte[])
|
||||||
|
return new SZArraySig(_module.CorLibTypes.Byte);
|
||||||
|
throw new NotSupportedException($"Unsupported type: {value.GetType()}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConstFieldInfo CreateConstFieldInfo(object value)
|
||||||
|
{
|
||||||
|
if (_holderTypeDef == null || _holderTypeDef.Fields.Count >= maxFieldCount)
|
||||||
|
{
|
||||||
|
_module.EnableTypeDefFindCache = false;
|
||||||
|
ITypeDefOrRef objectTypeRef = _module.Import(typeof(object));
|
||||||
|
_holderTypeDef = new TypeDefUser($"{ConstValues.ObfuzInternalSymbolNamePrefix}ConstFieldHolder${_holderTypeDefs.Count}", objectTypeRef);
|
||||||
|
_module.Types.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.Private | FieldAttributes.InitOnly);
|
||||||
|
field.DeclaringType = _holderTypeDef;
|
||||||
|
return new ConstFieldInfo
|
||||||
|
{
|
||||||
|
field = field,
|
||||||
|
value = value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private FieldDef AllocateAny(object value)
|
||||||
|
{
|
||||||
|
if (_done)
|
||||||
|
{
|
||||||
|
throw new Exception("can't Allocate after done");
|
||||||
|
}
|
||||||
|
if (!_allocatedFields.TryGetValue(value, out var field))
|
||||||
|
{
|
||||||
|
field = CreateConstFieldInfo(value);
|
||||||
|
_allocatedFields.Add(value, field);
|
||||||
|
_field2Fields.Add(field.field, field);
|
||||||
|
}
|
||||||
|
return field.field;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldDef Allocate(int value)
|
||||||
|
{
|
||||||
|
return AllocateAny(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldDef Allocate(long value)
|
||||||
|
{
|
||||||
|
return AllocateAny(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldDef Allocate(float value)
|
||||||
|
{
|
||||||
|
return AllocateAny(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldDef Allocate(double value)
|
||||||
|
{
|
||||||
|
return AllocateAny(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldDef Allocate(string value)
|
||||||
|
{
|
||||||
|
return AllocateAny(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldDef Allocate(byte[] value)
|
||||||
|
{
|
||||||
|
return AllocateAny(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DefaultMetadataImporter GetModuleMetadataImporter()
|
||||||
|
{
|
||||||
|
return _moduleEntityManager.GetDefaultModuleMetadataImporter(_module, _encryptionScopeProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateCCtorOfRvaTypeDef(TypeDef type)
|
||||||
|
{
|
||||||
|
var cctor = new MethodDefUser(".cctor",
|
||||||
|
MethodSig.CreateStatic(_module.CorLibTypes.Void),
|
||||||
|
MethodImplAttributes.IL | MethodImplAttributes.Managed,
|
||||||
|
MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.Private);
|
||||||
|
cctor.DeclaringType = type;
|
||||||
|
//_rvaTypeDef.Methods.Add(cctor);
|
||||||
|
var body = new CilBody();
|
||||||
|
cctor.Body = body;
|
||||||
|
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 = GetModuleMetadataImporter();
|
||||||
|
// TODO. obfuscate init codes
|
||||||
|
foreach (var field in type.Fields)
|
||||||
|
{
|
||||||
|
ConstFieldInfo constInfo = _field2Fields[field];
|
||||||
|
IRandom localRandom = _randomCreator(HashUtil.ComputePrimitiveOrStringOrBytesHashCode(constInfo.value));
|
||||||
|
int ops = EncryptionUtil.GenerateEncryptionOpCodes(localRandom, _encryptor, 4);
|
||||||
|
int salt = localRandom.NextInt();
|
||||||
|
switch (constInfo.value)
|
||||||
|
{
|
||||||
|
case int i:
|
||||||
|
{
|
||||||
|
int encryptedValue = _encryptor.Encrypt(i, ops, salt);
|
||||||
|
RvaData rvaData = _rvaDataAllocator.Allocate(_module, 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));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case long l:
|
||||||
|
{
|
||||||
|
long encryptedValue = _encryptor.Encrypt(l, ops, salt);
|
||||||
|
RvaData rvaData = _rvaDataAllocator.Allocate(_module, 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.DecryptFromRvaLong));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case float f:
|
||||||
|
{
|
||||||
|
float encryptedValue = _encryptor.Encrypt(f, ops, salt);
|
||||||
|
RvaData rvaData = _rvaDataAllocator.Allocate(_module, 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.DecryptFromRvaFloat));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case double d:
|
||||||
|
{
|
||||||
|
double encryptedValue = _encryptor.Encrypt(d, ops, salt);
|
||||||
|
RvaData rvaData = _rvaDataAllocator.Allocate(_module, 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.DecryptFromRvaDouble));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case string s:
|
||||||
|
{
|
||||||
|
byte[] encryptedValue = _encryptor.Encrypt(s, ops, salt);
|
||||||
|
RvaData rvaData = _rvaDataAllocator.Allocate(_module, encryptedValue);
|
||||||
|
ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
|
||||||
|
ins.Add(Instruction.CreateLdcI4(rvaData.offset));
|
||||||
|
Assert.AreEqual(encryptedValue.Length, rvaData.size);
|
||||||
|
ins.Add(Instruction.CreateLdcI4(encryptedValue.Length));
|
||||||
|
ins.Add(Instruction.CreateLdcI4(ops));
|
||||||
|
ins.Add(Instruction.CreateLdcI4(salt));
|
||||||
|
ins.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaString));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case byte[] bs:
|
||||||
|
{
|
||||||
|
byte[] encryptedValue = _encryptor.Encrypt(bs, 0, bs.Length, ops, salt);
|
||||||
|
Assert.AreEqual(encryptedValue.Length, bs.Length);
|
||||||
|
RvaData rvaData = _rvaDataAllocator.Allocate(_module, encryptedValue);
|
||||||
|
ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
|
||||||
|
ins.Add(Instruction.CreateLdcI4(rvaData.offset));
|
||||||
|
ins.Add(Instruction.CreateLdcI4(bs.Length));
|
||||||
|
ins.Add(Instruction.CreateLdcI4(ops));
|
||||||
|
ins.Add(Instruction.CreateLdcI4(salt));
|
||||||
|
ins.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaBytes));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: throw new NotSupportedException($"Unsupported type: {constInfo.value.GetType()}");
|
||||||
|
}
|
||||||
|
ins.Add(Instruction.Create(OpCodes.Stsfld, field));
|
||||||
|
}
|
||||||
|
ins.Add(Instruction.Create(OpCodes.Ret));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Done()
|
||||||
|
{
|
||||||
|
if (_done)
|
||||||
|
{
|
||||||
|
throw new Exception("Already done");
|
||||||
|
}
|
||||||
|
_done = true;
|
||||||
|
foreach (var typeDef in _holderTypeDefs)
|
||||||
|
{
|
||||||
|
CreateCCtorOfRvaTypeDef(typeDef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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,354 @@
|
||||||
|
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 System.Threading.Tasks;
|
||||||
|
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 ModuleRvaDataAllocator : GroupByModuleEntityBase
|
||||||
|
{
|
||||||
|
// randomized
|
||||||
|
const int maxRvaDataSize = 0x1000;
|
||||||
|
|
||||||
|
private ModuleDef _module;
|
||||||
|
private readonly EncryptionScopeProvider _encryptionScopeProvider;
|
||||||
|
private readonly GroupByModuleEntityManager _moduleEntityManager;
|
||||||
|
|
||||||
|
private EncryptionScopeInfo _encryptionScope;
|
||||||
|
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 readonly List<RvaField> _rvaFields = new List<RvaField>();
|
||||||
|
private RvaField _currentField;
|
||||||
|
|
||||||
|
|
||||||
|
private TypeDef _rvaTypeDef;
|
||||||
|
|
||||||
|
private readonly Dictionary<int, TypeDef> _dataHolderTypeBySizes = new Dictionary<int, TypeDef>();
|
||||||
|
private bool _done;
|
||||||
|
|
||||||
|
public ModuleRvaDataAllocator(EncryptionScopeProvider encryptionScopeProvider, GroupByModuleEntityManager moduleEntityManager)
|
||||||
|
{
|
||||||
|
_encryptionScopeProvider = encryptionScopeProvider;
|
||||||
|
_moduleEntityManager = moduleEntityManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Init(ModuleDef mod)
|
||||||
|
{
|
||||||
|
_module = mod;
|
||||||
|
_encryptionScope = _encryptionScopeProvider.GetScope(mod);
|
||||||
|
_random = _encryptionScope.localRandomCreator(HashUtil.ComputeHash(mod.Name));
|
||||||
|
}
|
||||||
|
|
||||||
|
private (FieldDef, FieldDef) CreateDataHolderRvaField(TypeDef dataHolderType)
|
||||||
|
{
|
||||||
|
if (_rvaTypeDef == null)
|
||||||
|
{
|
||||||
|
_module.EnableTypeDefFindCache = false;
|
||||||
|
//_rvaTypeDef = _module.Find("$ObfuzRVA$", true);
|
||||||
|
//if (_rvaTypeDef != null)
|
||||||
|
//{
|
||||||
|
// throw new Exception($"can't obfuscate a obfuscated assembly");
|
||||||
|
//}
|
||||||
|
ITypeDefOrRef objectTypeRef = _module.Import(typeof(object));
|
||||||
|
_rvaTypeDef = new TypeDefUser("$Obfuz$RVA$", objectTypeRef);
|
||||||
|
_module.Types.Add(_rvaTypeDef);
|
||||||
|
_module.EnableTypeDefFindCache = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var holderField = new FieldDefUser($"$RVA_Data{_rvaFields.Count}", new FieldSig(dataHolderType.ToTypeSig()), FieldAttributes.InitOnly | FieldAttributes.Static | FieldAttributes.HasFieldRVA);
|
||||||
|
holderField.DeclaringType = _rvaTypeDef;
|
||||||
|
|
||||||
|
var runtimeValueField = new FieldDefUser($"$RVA_Value{_rvaFields.Count}", new FieldSig(new SZArraySig(_module.CorLibTypes.Byte)), FieldAttributes.Static);
|
||||||
|
runtimeValueField.DeclaringType = _rvaTypeDef;
|
||||||
|
return (holderField, runtimeValueField);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TypeDef GetDataHolderType(int size)
|
||||||
|
{
|
||||||
|
size = (size + 15) & ~15; // align to 6 bytes
|
||||||
|
if (_dataHolderTypeBySizes.TryGetValue(size, out var type))
|
||||||
|
return type;
|
||||||
|
var dataHolderType = new TypeDefUser($"$ObfuzRVA$DataHolder{size}", _module.Import(typeof(ValueType)));
|
||||||
|
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(),
|
||||||
|
};
|
||||||
|
_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 CreateCCtorOfRvaTypeDef()
|
||||||
|
{
|
||||||
|
if (_rvaTypeDef == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ModuleDef mod = _rvaTypeDef.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;
|
||||||
|
//_rvaTypeDef.Methods.Add(cctor);
|
||||||
|
var body = new CilBody();
|
||||||
|
cctorMethod.Body = body;
|
||||||
|
var ins = body.Instructions;
|
||||||
|
|
||||||
|
DefaultMetadataImporter importer = _moduleEntityManager.GetDefaultModuleMetadataImporter(mod, _encryptionScopeProvider);
|
||||||
|
foreach (var field in _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.InitializedArrayMethod));
|
||||||
|
|
||||||
|
// 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 _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 void Done()
|
||||||
|
{
|
||||||
|
if (_done)
|
||||||
|
{
|
||||||
|
throw new Exception("can't call Done twice");
|
||||||
|
}
|
||||||
|
_done = true;
|
||||||
|
SetFieldsRVA();
|
||||||
|
CreateCCtorOfRvaTypeDef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RvaDataAllocator
|
||||||
|
{
|
||||||
|
private readonly EncryptionScopeProvider _encryptionScopeProvider;
|
||||||
|
private readonly GroupByModuleEntityManager _moduleEntityManager;
|
||||||
|
|
||||||
|
public RvaDataAllocator(EncryptionScopeProvider encryptionScopeProvider, GroupByModuleEntityManager moduleEntityManager)
|
||||||
|
{
|
||||||
|
_encryptionScopeProvider = encryptionScopeProvider;
|
||||||
|
_moduleEntityManager = moduleEntityManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ModuleRvaDataAllocator GetModuleRvaDataAllocator(ModuleDef mod)
|
||||||
|
{
|
||||||
|
return _moduleEntityManager.GetEntity<ModuleRvaDataAllocator>(mod, () => new ModuleRvaDataAllocator(_encryptionScopeProvider, _moduleEntityManager));
|
||||||
|
}
|
||||||
|
|
||||||
|
public RvaData Allocate(ModuleDef mod, int value)
|
||||||
|
{
|
||||||
|
return GetModuleRvaDataAllocator(mod).Allocate(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RvaData Allocate(ModuleDef mod, long value)
|
||||||
|
{
|
||||||
|
return GetModuleRvaDataAllocator(mod).Allocate(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RvaData Allocate(ModuleDef mod, float value)
|
||||||
|
{
|
||||||
|
return GetModuleRvaDataAllocator(mod).Allocate(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RvaData Allocate(ModuleDef mod, double value)
|
||||||
|
{
|
||||||
|
return GetModuleRvaDataAllocator(mod).Allocate(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RvaData Allocate(ModuleDef mod, string value)
|
||||||
|
{
|
||||||
|
return GetModuleRvaDataAllocator(mod).Allocate(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RvaData Allocate(ModuleDef mod, byte[] value)
|
||||||
|
{
|
||||||
|
return GetModuleRvaDataAllocator(mod).Allocate(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Done()
|
||||||
|
{
|
||||||
|
foreach (var allocator in _moduleEntityManager.GetEntities<ModuleRvaDataAllocator>())
|
||||||
|
{
|
||||||
|
allocator.Done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,295 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using dnlib.DotNet.Emit;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.Remoting.Messaging;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.Emit
|
||||||
|
{
|
||||||
|
public class BasicBlock
|
||||||
|
{
|
||||||
|
public readonly List<Instruction> instructions = new List<Instruction>();
|
||||||
|
|
||||||
|
public readonly List<BasicBlock> inBlocks = new List<BasicBlock>();
|
||||||
|
|
||||||
|
public readonly List<BasicBlock> outBlocks = new List<BasicBlock>();
|
||||||
|
|
||||||
|
public bool inLoop;
|
||||||
|
|
||||||
|
public void AddTargetBasicBlock(BasicBlock target)
|
||||||
|
{
|
||||||
|
if (!outBlocks.Contains(target))
|
||||||
|
{
|
||||||
|
outBlocks.Add(target);
|
||||||
|
}
|
||||||
|
if (!target.inBlocks.Contains(this))
|
||||||
|
{
|
||||||
|
target.inBlocks.Add(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BasicBlockCollection
|
||||||
|
{
|
||||||
|
private readonly MethodDef _method;
|
||||||
|
|
||||||
|
private readonly List<BasicBlock> _blocks = new List<BasicBlock>();
|
||||||
|
private readonly Dictionary<Instruction, BasicBlock> _inst2BlockMap = new Dictionary<Instruction, BasicBlock>();
|
||||||
|
|
||||||
|
public IList<BasicBlock> Blocks => _blocks;
|
||||||
|
|
||||||
|
public BasicBlockCollection(MethodDef method)
|
||||||
|
{
|
||||||
|
_method = method;
|
||||||
|
HashSet<Instruction> splitPoints = BuildSplitPoint(method);
|
||||||
|
BuildBasicBlocks(method, splitPoints);
|
||||||
|
BuildInOutGraph(method);
|
||||||
|
|
||||||
|
var loopBlocks = FindLoopBlocks(_blocks);
|
||||||
|
foreach (var block in loopBlocks)
|
||||||
|
{
|
||||||
|
block.inLoop = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public BasicBlock GetBasicBlockByInstruction(Instruction inst)
|
||||||
|
{
|
||||||
|
return _inst2BlockMap[inst];
|
||||||
|
}
|
||||||
|
|
||||||
|
private HashSet<Instruction> BuildSplitPoint(MethodDef method)
|
||||||
|
{
|
||||||
|
var insts = method.Body.Instructions;
|
||||||
|
var splitPoints = new HashSet<Instruction>();
|
||||||
|
foreach (ExceptionHandler eh in method.Body.ExceptionHandlers)
|
||||||
|
{
|
||||||
|
if (eh.TryStart != null)
|
||||||
|
{
|
||||||
|
splitPoints.Add(eh.TryStart);
|
||||||
|
}
|
||||||
|
if (eh.TryEnd != null)
|
||||||
|
{
|
||||||
|
splitPoints.Add(eh.TryEnd);
|
||||||
|
}
|
||||||
|
if (eh.HandlerStart != null)
|
||||||
|
{
|
||||||
|
splitPoints.Add(eh.HandlerStart);
|
||||||
|
}
|
||||||
|
if (eh.HandlerEnd != null)
|
||||||
|
{
|
||||||
|
splitPoints.Add(eh.HandlerEnd);
|
||||||
|
}
|
||||||
|
if (eh.FilterStart != null)
|
||||||
|
{
|
||||||
|
splitPoints.Add(eh.FilterStart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0, n = insts.Count; i < n; i++)
|
||||||
|
{
|
||||||
|
Instruction curInst = insts[i];
|
||||||
|
Instruction nextInst = i + 1 < n ? insts[i + 1] : null;
|
||||||
|
switch (curInst.OpCode.FlowControl)
|
||||||
|
{
|
||||||
|
case FlowControl.Branch:
|
||||||
|
{
|
||||||
|
if (nextInst != null)
|
||||||
|
{
|
||||||
|
splitPoints.Add(nextInst);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FlowControl.Cond_Branch:
|
||||||
|
{
|
||||||
|
if (nextInst != null)
|
||||||
|
{
|
||||||
|
splitPoints.Add(nextInst);
|
||||||
|
}
|
||||||
|
if (curInst.Operand is Instruction targetInst)
|
||||||
|
{
|
||||||
|
splitPoints.Add(targetInst);
|
||||||
|
}
|
||||||
|
else if (curInst.Operand is Instruction[] targetInsts)
|
||||||
|
{
|
||||||
|
foreach (var target in targetInsts)
|
||||||
|
{
|
||||||
|
splitPoints.Add(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FlowControl.Return:
|
||||||
|
{
|
||||||
|
if (nextInst != null)
|
||||||
|
{
|
||||||
|
splitPoints.Add(nextInst);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FlowControl.Throw:
|
||||||
|
{
|
||||||
|
if (nextInst != null)
|
||||||
|
{
|
||||||
|
splitPoints.Add(nextInst);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return splitPoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void BuildBasicBlocks(MethodDef method, HashSet<Instruction> splitPoints)
|
||||||
|
{
|
||||||
|
var insts = method.Body.Instructions;
|
||||||
|
|
||||||
|
|
||||||
|
BasicBlock curBlock = new BasicBlock();
|
||||||
|
foreach (Instruction inst in insts)
|
||||||
|
{
|
||||||
|
if (splitPoints.Contains(inst) && curBlock.instructions.Count > 0)
|
||||||
|
{
|
||||||
|
_blocks.Add(curBlock);
|
||||||
|
curBlock = new BasicBlock();
|
||||||
|
}
|
||||||
|
curBlock.instructions.Add(inst);
|
||||||
|
_inst2BlockMap.Add(inst, curBlock);
|
||||||
|
}
|
||||||
|
if (curBlock.instructions.Count > 0)
|
||||||
|
{
|
||||||
|
_blocks.Add(curBlock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BuildInOutGraph(MethodDef method)
|
||||||
|
{
|
||||||
|
var insts = method.Body.Instructions;
|
||||||
|
for (int i = 0, n = _blocks.Count; i < n; i++)
|
||||||
|
{
|
||||||
|
BasicBlock curBlock = _blocks[i];
|
||||||
|
BasicBlock nextBlock = i + 1 < n ? _blocks[i + 1] : null;
|
||||||
|
Instruction lastInst = curBlock.instructions.Last();
|
||||||
|
switch (lastInst.OpCode.FlowControl)
|
||||||
|
{
|
||||||
|
case FlowControl.Branch:
|
||||||
|
{
|
||||||
|
Instruction targetInst = (Instruction)lastInst.Operand;
|
||||||
|
BasicBlock targetBlock = GetBasicBlockByInstruction(targetInst);
|
||||||
|
curBlock.AddTargetBasicBlock(targetBlock);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FlowControl.Cond_Branch:
|
||||||
|
{
|
||||||
|
if (lastInst.Operand is Instruction targetInst)
|
||||||
|
{
|
||||||
|
BasicBlock targetBlock = GetBasicBlockByInstruction(targetInst);
|
||||||
|
curBlock.AddTargetBasicBlock(targetBlock);
|
||||||
|
}
|
||||||
|
else if (lastInst.Operand is Instruction[] targetInsts)
|
||||||
|
{
|
||||||
|
foreach (var target in targetInsts)
|
||||||
|
{
|
||||||
|
BasicBlock targetBlock = GetBasicBlockByInstruction(target);
|
||||||
|
curBlock.AddTargetBasicBlock(targetBlock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("Invalid operand type for conditional branch");
|
||||||
|
}
|
||||||
|
if (nextBlock != null)
|
||||||
|
{
|
||||||
|
curBlock.AddTargetBasicBlock(nextBlock);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FlowControl.Return:
|
||||||
|
case FlowControl.Throw:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static HashSet<BasicBlock> FindLoopBlocks(List<BasicBlock> allBlocks)
|
||||||
|
{
|
||||||
|
// Tarjan算法找强连通分量
|
||||||
|
var sccList = FindStronglyConnectedComponents(allBlocks);
|
||||||
|
|
||||||
|
// 筛选有效循环
|
||||||
|
var loopBlocks = new HashSet<BasicBlock>();
|
||||||
|
foreach (var scc in sccList)
|
||||||
|
{
|
||||||
|
// 有效循环需满足以下条件之一:
|
||||||
|
// 1. 分量包含多个块
|
||||||
|
// 2. 单个块有自环(跳转自己)
|
||||||
|
if (scc.Count > 1 ||
|
||||||
|
(scc.Count == 1 && scc[0].outBlocks.Contains(scc[0])))
|
||||||
|
{
|
||||||
|
foreach (var block in scc)
|
||||||
|
{
|
||||||
|
loopBlocks.Add(block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return loopBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<List<BasicBlock>> FindStronglyConnectedComponents(List<BasicBlock> allBlocks)
|
||||||
|
{
|
||||||
|
int index = 0;
|
||||||
|
var stack = new Stack<BasicBlock>();
|
||||||
|
var indexes = new Dictionary<BasicBlock, int>();
|
||||||
|
var lowLinks = new Dictionary<BasicBlock, int>();
|
||||||
|
var onStack = new HashSet<BasicBlock>();
|
||||||
|
var sccList = new List<List<BasicBlock>>();
|
||||||
|
|
||||||
|
foreach (var block in allBlocks.Where(b => !indexes.ContainsKey(b)))
|
||||||
|
{
|
||||||
|
StrongConnect(block);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sccList;
|
||||||
|
|
||||||
|
void StrongConnect(BasicBlock v)
|
||||||
|
{
|
||||||
|
indexes[v] = index;
|
||||||
|
lowLinks[v] = index;
|
||||||
|
index++;
|
||||||
|
stack.Push(v);
|
||||||
|
onStack.Add(v);
|
||||||
|
|
||||||
|
foreach (var w in v.outBlocks)
|
||||||
|
{
|
||||||
|
if (!indexes.ContainsKey(w))
|
||||||
|
{
|
||||||
|
StrongConnect(w);
|
||||||
|
lowLinks[v] = System.Math.Min(lowLinks[v], lowLinks[w]);
|
||||||
|
}
|
||||||
|
else if (onStack.Contains(w))
|
||||||
|
{
|
||||||
|
lowLinks[v] = System.Math.Min(lowLinks[v], indexes[w]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lowLinks[v] == indexes[v])
|
||||||
|
{
|
||||||
|
var scc = new List<BasicBlock>();
|
||||||
|
BasicBlock w;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
w = stack.Pop();
|
||||||
|
onStack.Remove(w);
|
||||||
|
scc.Add(w);
|
||||||
|
} while (!w.Equals(v));
|
||||||
|
sccList.Add(scc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,193 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using System;
|
||||||
|
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;
|
||||||
|
|
||||||
|
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 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DefaultMetadataImporter : GroupByModuleEntityBase
|
||||||
|
{
|
||||||
|
private readonly EncryptionScopeProvider _encryptionScopeProvider;
|
||||||
|
private EncryptionScopeInfo _encryptionScope;
|
||||||
|
private EncryptionServiceMetadataImporter _defaultEncryptionServiceMetadataImporter;
|
||||||
|
|
||||||
|
|
||||||
|
private EncryptionServiceMetadataImporter _staticDefaultEncryptionServiceMetadataImporter;
|
||||||
|
private EncryptionServiceMetadataImporter _dynamicDefaultEncryptionServiceMetadataImporter;
|
||||||
|
|
||||||
|
public DefaultMetadataImporter(EncryptionScopeProvider encryptionScopeProvider)
|
||||||
|
{
|
||||||
|
_encryptionScopeProvider = encryptionScopeProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Init(ModuleDef mod)
|
||||||
|
{
|
||||||
|
_module = mod;
|
||||||
|
_encryptionScope = _encryptionScopeProvider.GetScope(mod);
|
||||||
|
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);
|
||||||
|
|
||||||
|
_staticDefaultEncryptionServiceMetadataImporter = new EncryptionServiceMetadataImporter(mod, typeof(EncryptionService<DefaultStaticEncryptionScope>));
|
||||||
|
_dynamicDefaultEncryptionServiceMetadataImporter = new EncryptionServiceMetadataImporter(mod, typeof(EncryptionService<DefaultDynamicEncryptionScope>));
|
||||||
|
if (_encryptionScopeProvider.IsDynamicSecretAssembly(mod))
|
||||||
|
{
|
||||||
|
_defaultEncryptionServiceMetadataImporter = _dynamicDefaultEncryptionServiceMetadataImporter;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_defaultEncryptionServiceMetadataImporter = _staticDefaultEncryptionServiceMetadataImporter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
public IMethod CastIntAsFloat => _castIntAsFloat;
|
||||||
|
public IMethod CastLongAsDouble => _castLongAsDouble;
|
||||||
|
public IMethod CastFloatAsInt => _castFloatAsInt;
|
||||||
|
public IMethod CastDoubleAsLong => _castDoubleAsLong;
|
||||||
|
|
||||||
|
public IMethod InitializedArrayMethod => _initializeArray;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.Emit
|
||||||
|
{
|
||||||
|
public interface IGroupByModuleEntity
|
||||||
|
{
|
||||||
|
void Init(ModuleDef mod);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class GroupByModuleEntityBase : IGroupByModuleEntity
|
||||||
|
{
|
||||||
|
public abstract void Init(ModuleDef mod);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GroupByModuleEntityManager
|
||||||
|
{
|
||||||
|
private readonly Dictionary<(ModuleDef, Type), IGroupByModuleEntity> _moduleEntityManagers = new Dictionary<(ModuleDef, Type), IGroupByModuleEntity>();
|
||||||
|
|
||||||
|
public T GetEntity<T>(ModuleDef mod, Func<T> creator = null) where T : IGroupByModuleEntity
|
||||||
|
{
|
||||||
|
var key = (mod, typeof(T));
|
||||||
|
if (_moduleEntityManagers.TryGetValue(key, out var emitManager))
|
||||||
|
{
|
||||||
|
return (T)emitManager;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
T newEmitManager;
|
||||||
|
if (creator != null)
|
||||||
|
{
|
||||||
|
newEmitManager = creator();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newEmitManager = (T)Activator.CreateInstance(typeof(T));
|
||||||
|
}
|
||||||
|
newEmitManager.Init(mod);
|
||||||
|
_moduleEntityManagers[key] = newEmitManager;
|
||||||
|
return newEmitManager;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<T> GetEntities<T>() where T: IGroupByModuleEntity
|
||||||
|
{
|
||||||
|
var managers = new List<T>();
|
||||||
|
foreach (var kv in _moduleEntityManagers)
|
||||||
|
{
|
||||||
|
if (kv.Key.Item2 == typeof(T))
|
||||||
|
{
|
||||||
|
managers.Add((T)kv.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return managers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DefaultMetadataImporter GetDefaultModuleMetadataImporter(ModuleDef module, EncryptionScopeProvider encryptionScopeProvider)
|
||||||
|
{
|
||||||
|
return GetEntity<DefaultMetadataImporter>(module, () => new DefaultMetadataImporter(encryptionScopeProvider));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
namespace Obfuz.EncryptionVM
|
||||||
|
{
|
||||||
|
public class EncryptionInstructionWithOpCode
|
||||||
|
{
|
||||||
|
public readonly ushort code;
|
||||||
|
|
||||||
|
public readonly IEncryptionInstruction function;
|
||||||
|
|
||||||
|
public EncryptionInstructionWithOpCode(ushort code, IEncryptionInstruction function)
|
||||||
|
{
|
||||||
|
this.code = code;
|
||||||
|
this.function = function;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Encrypt(int value, int[] secretKey, int salt)
|
||||||
|
{
|
||||||
|
return function.Encrypt(value, secretKey, salt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Decrypt(int value, int[] secretKey, int salt)
|
||||||
|
{
|
||||||
|
return function.Decrypt(value, secretKey, salt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Obfuz.EncryptionVM
|
||||||
|
{
|
||||||
|
public interface IEncryptionInstruction
|
||||||
|
{
|
||||||
|
int Encrypt(int value, int[] secretKey, int salt);
|
||||||
|
|
||||||
|
int Decrypt(int value, int[] secretKey, int salt);
|
||||||
|
|
||||||
|
void GenerateEncryptCode(List<string> lines, string indent);
|
||||||
|
|
||||||
|
void GenerateDecryptCode(List<string> lines, string indent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class EncryptionInstructionBase : IEncryptionInstruction
|
||||||
|
{
|
||||||
|
public abstract int Encrypt(int value, int[] secretKey, int salt);
|
||||||
|
public abstract int Decrypt(int value, int[] secretKey, int salt);
|
||||||
|
|
||||||
|
public abstract void GenerateEncryptCode(List<string> lines, string indent);
|
||||||
|
public abstract void GenerateDecryptCode(List<string> lines, string indent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Obfuz.EncryptionVM.Instructions
|
||||||
|
{
|
||||||
|
public class AddInstruction : EncryptionInstructionBase
|
||||||
|
{
|
||||||
|
private readonly int _addValue;
|
||||||
|
private readonly int _opKeyIndex;
|
||||||
|
|
||||||
|
public AddInstruction(int addValue, int opKeyIndex)
|
||||||
|
{
|
||||||
|
_addValue = addValue;
|
||||||
|
_opKeyIndex = opKeyIndex;
|
||||||
|
}
|
||||||
|
public override int Encrypt(int value, int[] secretKey, int salt)
|
||||||
|
{
|
||||||
|
return ((value + secretKey[_opKeyIndex]) ^ salt) + _addValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Decrypt(int value, int[] secretKey, int salt)
|
||||||
|
{
|
||||||
|
return ((value - _addValue) ^ salt) - secretKey[_opKeyIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void GenerateEncryptCode(List<string> lines, string indent)
|
||||||
|
{
|
||||||
|
lines.Add(indent + $"value = ((value + _secretKey[{_opKeyIndex}]) ^ salt) + {_addValue};");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void GenerateDecryptCode(List<string> lines, string indent)
|
||||||
|
{
|
||||||
|
lines.Add(indent + $"value = ((value - {_addValue}) ^ salt) - _secretKey[{_opKeyIndex}];");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.EncryptionVM.Instructions
|
||||||
|
{
|
||||||
|
public class AddRotateXorInstruction : EncryptionInstructionBase
|
||||||
|
{
|
||||||
|
// x = x + p1 + secretKey[index1];
|
||||||
|
// x = Rotate(x, p2)
|
||||||
|
// x = x ^ p3 ^ salt;
|
||||||
|
|
||||||
|
private readonly int _addValue;
|
||||||
|
private readonly int _index1;
|
||||||
|
private readonly int _rotateBitNum;
|
||||||
|
private readonly int _xorValue;
|
||||||
|
|
||||||
|
public AddRotateXorInstruction(int addValue, int index1, int rotateBitNum, int xorValue)
|
||||||
|
{
|
||||||
|
_addValue = addValue;
|
||||||
|
_index1 = index1;
|
||||||
|
_rotateBitNum = rotateBitNum;
|
||||||
|
_xorValue = xorValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Encrypt(int value, int[] secretKey, int salt)
|
||||||
|
{
|
||||||
|
value += _addValue + secretKey[_index1];
|
||||||
|
uint part1 = (uint)value << _rotateBitNum;
|
||||||
|
uint part2 = (uint)value >> (32 - _rotateBitNum);
|
||||||
|
value = (int)(part1 | part2);
|
||||||
|
value ^= _xorValue ^ salt;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Decrypt(int value, int[] secretKey, int salt)
|
||||||
|
{
|
||||||
|
value ^= _xorValue ^ salt;
|
||||||
|
uint value2 = (uint)value >> _rotateBitNum;
|
||||||
|
uint part1 = (uint)value << (32 - _rotateBitNum);
|
||||||
|
value = (int)(value2 | part1);
|
||||||
|
value -= _addValue + secretKey[_index1];
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void GenerateEncryptCode(List<string> lines, string indent)
|
||||||
|
{
|
||||||
|
lines.Add(indent + $"value += {_addValue} + _secretKey[{_index1}];");
|
||||||
|
lines.Add(indent + $"uint part1 = (uint)value << {_rotateBitNum};");
|
||||||
|
lines.Add(indent + $"uint part2 = (uint)value >> (32 - {_rotateBitNum});");
|
||||||
|
lines.Add(indent + $"value = (int)(part1 | part2);");
|
||||||
|
lines.Add(indent + $"value ^= {_xorValue} ^ salt;");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void GenerateDecryptCode(List<string> lines, string indent)
|
||||||
|
{
|
||||||
|
lines.Add(indent + $"value ^= {_xorValue} ^ salt;");
|
||||||
|
lines.Add(indent + $"uint value2 = (uint)value >> {_rotateBitNum};");
|
||||||
|
lines.Add(indent + $"uint part1 = (uint)value << (32 - {_rotateBitNum});");
|
||||||
|
lines.Add(indent + $"value = (int)(value2 | part1);");
|
||||||
|
lines.Add(indent + $"value -= {_addValue} + _secretKey[{_index1}];");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.EncryptionVM.Instructions
|
||||||
|
{
|
||||||
|
public class AddXorRotateInstruction : EncryptionInstructionBase
|
||||||
|
{
|
||||||
|
// x = x + p1 + secretKey[index1];
|
||||||
|
// x = x ^ p3 ^ salt;
|
||||||
|
// x = Rotate(x, p2)
|
||||||
|
|
||||||
|
private readonly int _addValue;
|
||||||
|
private readonly int _index1;
|
||||||
|
private readonly int _rotateBitNum;
|
||||||
|
private readonly int _xorValue;
|
||||||
|
|
||||||
|
public AddXorRotateInstruction(int addValue, int index1, int xorValue, int rotateBitNum)
|
||||||
|
{
|
||||||
|
_addValue = addValue;
|
||||||
|
_index1 = index1;
|
||||||
|
_rotateBitNum = rotateBitNum;
|
||||||
|
_xorValue = xorValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Encrypt(int value, int[] secretKey, int salt)
|
||||||
|
{
|
||||||
|
value += _addValue + secretKey[_index1];
|
||||||
|
value ^= _xorValue ^ salt;
|
||||||
|
uint part1 = (uint)value << _rotateBitNum;
|
||||||
|
uint part2 = (uint)value >> (32 - _rotateBitNum);
|
||||||
|
value = (int)(part1 | part2);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Decrypt(int value, int[] secretKey, int salt)
|
||||||
|
{
|
||||||
|
uint value2 = (uint)value >> _rotateBitNum;
|
||||||
|
uint part1 = (uint)value << (32 - _rotateBitNum);
|
||||||
|
value = (int)(value2 | part1);
|
||||||
|
value ^= _xorValue ^ salt;
|
||||||
|
value -= _addValue + secretKey[_index1];
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void GenerateEncryptCode(List<string> lines, string indent)
|
||||||
|
{
|
||||||
|
lines.Add(indent + $"value += {_addValue} + _secretKey[{_index1}];");
|
||||||
|
lines.Add(indent + $"value ^= {_xorValue} ^ salt;");
|
||||||
|
lines.Add(indent + $"uint part1 = (uint)value << {_rotateBitNum};");
|
||||||
|
lines.Add(indent + $"uint part2 = (uint)value >> (32 - {_rotateBitNum});");
|
||||||
|
lines.Add(indent + $"value = (int)(part1 | part2);");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void GenerateDecryptCode(List<string> lines, string indent)
|
||||||
|
{
|
||||||
|
lines.Add(indent + $"uint part1 = (uint)value >> {_rotateBitNum};");
|
||||||
|
lines.Add(indent + $"uint part2 = (uint)value << (32 - {_rotateBitNum});");
|
||||||
|
lines.Add(indent + $"value = (int)(part1 | part2);");
|
||||||
|
lines.Add(indent + $"value ^= {_xorValue} ^ salt;");
|
||||||
|
lines.Add(indent + $"value -= {_addValue} + _secretKey[{_index1}];");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Obfuz.EncryptionVM.Instructions
|
||||||
|
{
|
||||||
|
public class BitRotateInstruction : EncryptionInstructionBase
|
||||||
|
{
|
||||||
|
private readonly int _rotateBitNum;
|
||||||
|
private readonly int _opKeyIndex;
|
||||||
|
|
||||||
|
public BitRotateInstruction(int rotateBitNum, int opKeyIndex)
|
||||||
|
{
|
||||||
|
_rotateBitNum = rotateBitNum;
|
||||||
|
_opKeyIndex = opKeyIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Encrypt(int value, int[] secretKey, int salt)
|
||||||
|
{
|
||||||
|
uint part1 = (uint)value << _rotateBitNum;
|
||||||
|
uint part2 = (uint)value >> (32 - _rotateBitNum);
|
||||||
|
return ((int)(part1 | part2) ^ secretKey[_opKeyIndex]) + salt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Decrypt(int value, int[] secretKey, int salt)
|
||||||
|
{
|
||||||
|
uint value2 = (uint)((value - salt) ^ secretKey[_opKeyIndex]);
|
||||||
|
uint part1 = value2 >> _rotateBitNum;
|
||||||
|
uint part2 = value2 << (32 - _rotateBitNum);
|
||||||
|
return (int)(part1 | part2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void GenerateEncryptCode(List<string> lines, string indent)
|
||||||
|
{
|
||||||
|
lines.Add(indent + $"uint part1 = (uint)value << {_rotateBitNum};");
|
||||||
|
lines.Add(indent + $"uint part2 = (uint)value >> (32 - {_rotateBitNum});");
|
||||||
|
lines.Add(indent + $"value = ((int)(part1 | part2) ^ _secretKey[{_opKeyIndex}]) + salt;");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void GenerateDecryptCode(List<string> lines, string indent)
|
||||||
|
{
|
||||||
|
lines.Add(indent + $"uint value2 = (uint)((value - salt) ^ _secretKey[{_opKeyIndex}]);");
|
||||||
|
lines.Add(indent + $"uint part1 = value2 >> {_rotateBitNum};");
|
||||||
|
lines.Add(indent + $"uint part2 = value2 << (32 - {_rotateBitNum});");
|
||||||
|
lines.Add(indent + $"value = (int)(part1 | part2);");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.EncryptionVM.Instructions
|
||||||
|
{
|
||||||
|
|
||||||
|
public class EncryptFunction : EncryptionInstructionBase
|
||||||
|
{
|
||||||
|
private readonly IEncryptionInstruction[] _instructions;
|
||||||
|
|
||||||
|
public EncryptFunction(IEncryptionInstruction[] instructions)
|
||||||
|
{
|
||||||
|
_instructions = instructions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Encrypt(int value, int[] secretKey, int salt)
|
||||||
|
{
|
||||||
|
foreach (var instruction in _instructions)
|
||||||
|
{
|
||||||
|
value = instruction.Encrypt(value, secretKey, salt);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Decrypt(int value, int[] secretKey, int salt)
|
||||||
|
{
|
||||||
|
for (int i = _instructions.Length - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
value = _instructions[i].Decrypt(value, secretKey, salt);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void GenerateEncryptCode(List<string> lines, string indent)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void GenerateDecryptCode(List<string> lines, string indent)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
using NUnit.Framework;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Obfuz.EncryptionVM.Instructions
|
||||||
|
{
|
||||||
|
public class MultipleInstruction : EncryptionInstructionBase
|
||||||
|
{
|
||||||
|
private readonly int _multiValue;
|
||||||
|
private readonly int _revertMultiValue;
|
||||||
|
private readonly int _opKeyIndex;
|
||||||
|
|
||||||
|
public MultipleInstruction(int addValue, int opKeyIndex)
|
||||||
|
{
|
||||||
|
_multiValue = addValue;
|
||||||
|
_opKeyIndex = opKeyIndex;
|
||||||
|
_revertMultiValue = (int)ModInverseOdd((uint)addValue);
|
||||||
|
Verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Verify()
|
||||||
|
{
|
||||||
|
int a = 1122334;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
return value * _multiValue + secretKey[_opKeyIndex] + salt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Decrypt(int value, int[] secretKey, int salt)
|
||||||
|
{
|
||||||
|
return (value - secretKey[_opKeyIndex] - salt) * _revertMultiValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void GenerateEncryptCode(List<string> lines, string indent)
|
||||||
|
{
|
||||||
|
lines.Add(indent + $"value = value * {_multiValue} + _secretKey[{_opKeyIndex}] + salt;");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void GenerateDecryptCode(List<string> lines, string indent)
|
||||||
|
{
|
||||||
|
lines.Add(indent + $"value = (value - _secretKey[{_opKeyIndex}] - salt) * {_revertMultiValue};");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.EncryptionVM.Instructions
|
||||||
|
{
|
||||||
|
public class MultipleRotateXorInstruction : EncryptionInstructionBase
|
||||||
|
{
|
||||||
|
// x = x * p1 + secretKey[index1];
|
||||||
|
// x = Rotate(x, p2)
|
||||||
|
// x = x ^ p3 ^ salt;
|
||||||
|
|
||||||
|
private readonly int _multipleValue;
|
||||||
|
private readonly int _revertMultipleValue;
|
||||||
|
private readonly int _index1;
|
||||||
|
private readonly int _rotateBitNum;
|
||||||
|
private readonly int _xorValue;
|
||||||
|
|
||||||
|
public MultipleRotateXorInstruction(int multipleValue, int index1, int rotateBitNum, int xorValue)
|
||||||
|
{
|
||||||
|
_multipleValue = multipleValue;
|
||||||
|
_revertMultipleValue = (int)MultipleInstruction.ModInverseOdd((uint)multipleValue);
|
||||||
|
_index1 = index1;
|
||||||
|
_rotateBitNum = rotateBitNum;
|
||||||
|
_xorValue = xorValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Encrypt(int value, int[] secretKey, int salt)
|
||||||
|
{
|
||||||
|
value = value * _multipleValue + secretKey[_index1];
|
||||||
|
uint part1 = (uint)value << _rotateBitNum;
|
||||||
|
uint part2 = (uint)value >> (32 - _rotateBitNum);
|
||||||
|
value = (int)(part1 | part2);
|
||||||
|
value ^= _xorValue ^ salt;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Decrypt(int value, int[] secretKey, int salt)
|
||||||
|
{
|
||||||
|
value ^= _xorValue ^ salt;
|
||||||
|
uint value2 = (uint)value >> _rotateBitNum;
|
||||||
|
uint part1 = (uint)value << (32 - _rotateBitNum);
|
||||||
|
value = (int)(value2 | part1);
|
||||||
|
value = (value - secretKey[_index1]) * _revertMultipleValue;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void GenerateEncryptCode(List<string> lines, string indent)
|
||||||
|
{
|
||||||
|
lines.Add(indent + $"value = value * {_multipleValue} + _secretKey[{_index1}];");
|
||||||
|
lines.Add(indent + $"uint part1 = (uint)value << {_rotateBitNum};");
|
||||||
|
lines.Add(indent + $"uint part2 = (uint)value >> (32 - {_rotateBitNum});");
|
||||||
|
lines.Add(indent + $"value = (int)(part1 | part2);");
|
||||||
|
lines.Add(indent + $"value ^= {_xorValue} ^ salt;");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void GenerateDecryptCode(List<string> lines, string indent)
|
||||||
|
{
|
||||||
|
lines.Add(indent + $"value ^= {_xorValue} ^ salt;");
|
||||||
|
lines.Add(indent + $"uint value2 = (uint)value >> {_rotateBitNum};");
|
||||||
|
lines.Add(indent + $"uint part1 = (uint)value << (32 - {_rotateBitNum});");
|
||||||
|
lines.Add(indent + $"value = (int)(value2 | part1);");
|
||||||
|
lines.Add(indent + $"value = (value - _secretKey[{_index1}]) * {_revertMultipleValue};");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.EncryptionVM.Instructions
|
||||||
|
{
|
||||||
|
public class MultipleXorRotateInstruction : EncryptionInstructionBase
|
||||||
|
{
|
||||||
|
// x = x * p1 + secretKey[index1];
|
||||||
|
// x = x ^ p3 ^ salt;
|
||||||
|
// x = Rotate(x, p2)
|
||||||
|
|
||||||
|
private readonly int _multipleValue;
|
||||||
|
private readonly int _revertMultipleValue;
|
||||||
|
private readonly int _index1;
|
||||||
|
private readonly int _rotateBitNum;
|
||||||
|
private readonly int _xorValue;
|
||||||
|
|
||||||
|
public MultipleXorRotateInstruction(int multipleValue, int index1, int xorValue, int rotateBitNum)
|
||||||
|
{
|
||||||
|
_multipleValue = multipleValue;
|
||||||
|
_revertMultipleValue = (int)MultipleInstruction.ModInverseOdd((uint)multipleValue);
|
||||||
|
_index1 = index1;
|
||||||
|
_rotateBitNum = rotateBitNum;
|
||||||
|
_xorValue = xorValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Encrypt(int value, int[] secretKey, int salt)
|
||||||
|
{
|
||||||
|
value = value * _multipleValue + secretKey[_index1];
|
||||||
|
value ^= _xorValue ^ salt;
|
||||||
|
uint part1 = (uint)value << _rotateBitNum;
|
||||||
|
uint part2 = (uint)value >> (32 - _rotateBitNum);
|
||||||
|
value = (int)(part1 | part2);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Decrypt(int value, int[] secretKey, int salt)
|
||||||
|
{
|
||||||
|
uint value2 = (uint)value >> _rotateBitNum;
|
||||||
|
uint part1 = (uint)value << (32 - _rotateBitNum);
|
||||||
|
value = (int)(value2 | part1);
|
||||||
|
value ^= _xorValue ^ salt;
|
||||||
|
value = (value - secretKey[_index1]) * _revertMultipleValue;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void GenerateEncryptCode(List<string> lines, string indent)
|
||||||
|
{
|
||||||
|
lines.Add(indent + $"value = value * {_multipleValue} + _secretKey[{_index1}];");
|
||||||
|
lines.Add(indent + $"value ^= {_xorValue} ^ salt;");
|
||||||
|
lines.Add(indent + $"uint part1 = (uint)value << {_rotateBitNum};");
|
||||||
|
lines.Add(indent + $"uint part2 = (uint)value >> (32 - {_rotateBitNum});");
|
||||||
|
lines.Add(indent + $"value = (int)(part1 | part2);");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void GenerateDecryptCode(List<string> lines, string indent)
|
||||||
|
{
|
||||||
|
lines.Add(indent + $"uint value2 = (uint)value >> {_rotateBitNum};");
|
||||||
|
lines.Add(indent + $"uint part1 = (uint)value << (32 - {_rotateBitNum});");
|
||||||
|
lines.Add(indent + $"value = (int)(value2 | part1);");
|
||||||
|
lines.Add(indent + $"value ^= {_xorValue} ^ salt;");
|
||||||
|
lines.Add(indent + $"value = (value - _secretKey[{_index1}]) * {_revertMultipleValue};");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.EncryptionVM.Instructions
|
||||||
|
{
|
||||||
|
public class XorAddRotateInstruction : EncryptionInstructionBase
|
||||||
|
{
|
||||||
|
// x = x ^ p3 ^ salt;
|
||||||
|
// x = x + p1 + secretKey[index1];
|
||||||
|
// x = Rotate(x, p2)
|
||||||
|
|
||||||
|
private readonly int _addValue;
|
||||||
|
private readonly int _index1;
|
||||||
|
private readonly int _rotateBitNum;
|
||||||
|
private readonly int _xorValue;
|
||||||
|
|
||||||
|
public XorAddRotateInstruction(int xorValue, int addValue, int index1, int rotateBitNum)
|
||||||
|
{
|
||||||
|
_addValue = addValue;
|
||||||
|
_index1 = index1;
|
||||||
|
_rotateBitNum = rotateBitNum;
|
||||||
|
_xorValue = xorValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Encrypt(int value, int[] secretKey, int salt)
|
||||||
|
{
|
||||||
|
value ^= _xorValue ^ salt;
|
||||||
|
value += _addValue + secretKey[_index1];
|
||||||
|
uint part1 = (uint)value << _rotateBitNum;
|
||||||
|
uint part2 = (uint)value >> (32 - _rotateBitNum);
|
||||||
|
value = (int)(part1 | part2);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Decrypt(int value, int[] secretKey, int salt)
|
||||||
|
{
|
||||||
|
uint value2 = (uint)value >> _rotateBitNum;
|
||||||
|
uint part1 = (uint)value << (32 - _rotateBitNum);
|
||||||
|
value = (int)(value2 | part1);
|
||||||
|
value -= _addValue + secretKey[_index1];
|
||||||
|
value ^= _xorValue ^ salt;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void GenerateEncryptCode(List<string> lines, string indent)
|
||||||
|
{
|
||||||
|
lines.Add(indent + $"value ^= {_xorValue} ^ salt;");
|
||||||
|
lines.Add(indent + $"value += {_addValue} + _secretKey[{_index1}];");
|
||||||
|
lines.Add(indent + $"uint part1 = (uint)value << {_rotateBitNum};");
|
||||||
|
lines.Add(indent + $"uint part2 = (uint)value >> (32 - {_rotateBitNum});");
|
||||||
|
lines.Add(indent + $"value = (int)(part1 | part2);");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void GenerateDecryptCode(List<string> lines, string indent)
|
||||||
|
{
|
||||||
|
lines.Add(indent + $"uint value2 = (uint)value >> {_rotateBitNum};");
|
||||||
|
lines.Add(indent + $"uint part1 = (uint)value << (32 - {_rotateBitNum});");
|
||||||
|
lines.Add(indent + $"value = (int)(value2 | part1);");
|
||||||
|
lines.Add(indent + $"value -= {_addValue} + _secretKey[{_index1}];");
|
||||||
|
lines.Add(indent + $"value ^= {_xorValue} ^ salt;");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Obfuz.EncryptionVM.Instructions
|
||||||
|
{
|
||||||
|
public class XorInstruction : EncryptionInstructionBase
|
||||||
|
{
|
||||||
|
private readonly int _xorValue;
|
||||||
|
private readonly int _opKeyIndex;
|
||||||
|
|
||||||
|
public XorInstruction(int xorValue, int opKeyIndex)
|
||||||
|
{
|
||||||
|
_xorValue = xorValue;
|
||||||
|
_opKeyIndex = opKeyIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Encrypt(int value, int[] secretKey, int salt)
|
||||||
|
{
|
||||||
|
return ((value ^ secretKey[_opKeyIndex]) + salt) ^ _xorValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Decrypt(int value, int[] secretKey, int salt)
|
||||||
|
{
|
||||||
|
return ((value ^ _xorValue) - salt) ^ secretKey[_opKeyIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void GenerateEncryptCode(List<string> lines, string indent)
|
||||||
|
{
|
||||||
|
lines.Add(indent + $"value = ((value ^ _secretKey[{_opKeyIndex}]) + salt) ^ {_xorValue};");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void GenerateDecryptCode(List<string> lines, string indent)
|
||||||
|
{
|
||||||
|
lines.Add(indent + $"value = ((value ^ {_xorValue}) - salt) ^ _secretKey[{_opKeyIndex}];");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.EncryptionVM.Instructions
|
||||||
|
{
|
||||||
|
public class XorMultipleRotateInstruction : EncryptionInstructionBase
|
||||||
|
{
|
||||||
|
// x = x ^ p3 ^ salt;
|
||||||
|
// x = x * p1 + secretKey[index1];
|
||||||
|
// x = Rotate(x, p2)
|
||||||
|
|
||||||
|
private readonly int _multipleValue;
|
||||||
|
private readonly int _revertMultipleValue;
|
||||||
|
private readonly int _index1;
|
||||||
|
private readonly int _rotateBitNum;
|
||||||
|
private readonly int _xorValue;
|
||||||
|
|
||||||
|
public XorMultipleRotateInstruction(int xorValue, int multipleValue, int index1, int rotateBitNum)
|
||||||
|
{
|
||||||
|
_multipleValue = multipleValue;
|
||||||
|
_revertMultipleValue = (int)MultipleInstruction.ModInverseOdd((uint)multipleValue);
|
||||||
|
_index1 = index1;
|
||||||
|
_rotateBitNum = rotateBitNum;
|
||||||
|
_xorValue = xorValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Encrypt(int value, int[] secretKey, int salt)
|
||||||
|
{
|
||||||
|
value ^= _xorValue ^ salt;
|
||||||
|
value = value * _multipleValue + secretKey[_index1];
|
||||||
|
uint part1 = (uint)value << _rotateBitNum;
|
||||||
|
uint part2 = (uint)value >> (32 - _rotateBitNum);
|
||||||
|
value = (int)(part1 | part2);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Decrypt(int value, int[] secretKey, int salt)
|
||||||
|
{
|
||||||
|
uint value2 = (uint)value >> _rotateBitNum;
|
||||||
|
uint part1 = (uint)value << (32 - _rotateBitNum);
|
||||||
|
value = (int)(value2 | part1);
|
||||||
|
value = (value - secretKey[_index1]) * _revertMultipleValue;
|
||||||
|
value ^= _xorValue ^ salt;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void GenerateEncryptCode(List<string> lines, string indent)
|
||||||
|
{
|
||||||
|
lines.Add(indent + $"value ^= {_xorValue} ^ salt;");
|
||||||
|
lines.Add(indent + $"value = value * {_multipleValue} + _secretKey[{_index1}];");
|
||||||
|
lines.Add(indent + $"uint part1 = (uint)value << {_rotateBitNum};");
|
||||||
|
lines.Add(indent + $"uint part2 = (uint)value >> (32 - {_rotateBitNum});");
|
||||||
|
lines.Add(indent + $"value = (int)(part1 | part2);");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void GenerateDecryptCode(List<string> lines, string indent)
|
||||||
|
{
|
||||||
|
lines.Add(indent + $"uint value2 = (uint)value >> {_rotateBitNum};");
|
||||||
|
lines.Add(indent + $"uint part1 = (uint)value << (32 - {_rotateBitNum});");
|
||||||
|
lines.Add(indent + $"value = (int)(value2 | part1);");
|
||||||
|
lines.Add(indent + $"value = (value - _secretKey[{_index1}]) * {_revertMultipleValue};");
|
||||||
|
lines.Add(indent + $"value ^= {_xorValue} ^ salt;");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
namespace Obfuz.EncryptionVM
|
||||||
|
{
|
||||||
|
public class VirtualMachine
|
||||||
|
{
|
||||||
|
public const int SecretKeyLength = 1024;
|
||||||
|
|
||||||
|
public readonly int version;
|
||||||
|
public readonly string codeGenerationSecretKey;
|
||||||
|
public readonly EncryptionInstructionWithOpCode[] opCodes;
|
||||||
|
|
||||||
|
public VirtualMachine(int version, string codeGenerationSecretKey, EncryptionInstructionWithOpCode[] opCodes)
|
||||||
|
{
|
||||||
|
this.codeGenerationSecretKey = codeGenerationSecretKey;
|
||||||
|
this.opCodes = opCodes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,207 @@
|
||||||
|
using Obfuz.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Obfuz.EncryptionVM
|
||||||
|
{
|
||||||
|
public class VirtualMachineCodeGenerator
|
||||||
|
{
|
||||||
|
private readonly int _opCodeCount;
|
||||||
|
private readonly int _opCodeBits;
|
||||||
|
private readonly VirtualMachine _vm;
|
||||||
|
|
||||||
|
public VirtualMachineCodeGenerator(string vmCodeGenerateSecretKey, int opCodeCount)
|
||||||
|
{
|
||||||
|
_opCodeCount = opCodeCount;
|
||||||
|
_opCodeBits = EncryptionUtil.GetBitCount(opCodeCount - 1);
|
||||||
|
_vm = new VirtualMachineCreator(vmCodeGenerateSecretKey).CreateVirtualMachine(opCodeCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VirtualMachineCodeGenerator(VirtualMachine vm)
|
||||||
|
{
|
||||||
|
_opCodeCount = vm.opCodes.Length;
|
||||||
|
_opCodeBits = EncryptionUtil.GetBitCount(_opCodeCount - 1);
|
||||||
|
_vm = vm;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool ValidateMatch(string outputFile)
|
||||||
|
{
|
||||||
|
if (!File.Exists(outputFile))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
string oldCode = NormalizeText(File.ReadAllText(outputFile, Encoding.UTF8));
|
||||||
|
string newCode = NormalizeText(GenerateCode());
|
||||||
|
return oldCode == newCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string NormalizeText(string input)
|
||||||
|
{
|
||||||
|
return Regex.Replace(input, @"\s+", string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Generate(string outputFile)
|
||||||
|
{
|
||||||
|
FileUtil.CreateParentDir(outputFile);
|
||||||
|
|
||||||
|
string code = GenerateCode();
|
||||||
|
|
||||||
|
File.WriteAllText(outputFile, code, Encoding.UTF8);
|
||||||
|
Debug.Log($"Generate EncryptionVM code to {outputFile}");
|
||||||
|
UnityEditor.AssetDatabase.Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GenerateCode()
|
||||||
|
{
|
||||||
|
var lines = new List<string>();
|
||||||
|
AppendHeader(lines);
|
||||||
|
AppendEncryptCodes(lines);
|
||||||
|
AppendDecryptCodes(lines);
|
||||||
|
AppendTailer(lines);
|
||||||
|
return string.Join("\n", lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AppendEncryptCodes(List<string> lines)
|
||||||
|
{
|
||||||
|
lines.Add(@"
|
||||||
|
private int ExecuteEncrypt(int value, int opCode, int salt)
|
||||||
|
{
|
||||||
|
switch (opCode)
|
||||||
|
{");
|
||||||
|
foreach (var opCode in _vm.opCodes)
|
||||||
|
{
|
||||||
|
lines.Add($@" case {opCode.code}:
|
||||||
|
{{
|
||||||
|
// {opCode.function.GetType().Name}");
|
||||||
|
AppendEncryptCode(lines, opCode.function);
|
||||||
|
lines.Add(@" return value;
|
||||||
|
}");
|
||||||
|
}
|
||||||
|
|
||||||
|
lines.Add(@"
|
||||||
|
default:
|
||||||
|
throw new System.Exception($""Invalid opCode:{opCode}"");
|
||||||
|
}
|
||||||
|
}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AppendDecryptCodes(List<string> lines)
|
||||||
|
{
|
||||||
|
lines.Add(@"
|
||||||
|
private int ExecuteDecrypt(int value, int opCode, int salt)
|
||||||
|
{
|
||||||
|
switch (opCode)
|
||||||
|
{");
|
||||||
|
foreach (var opCode in _vm.opCodes)
|
||||||
|
{
|
||||||
|
lines.Add($@" case {opCode.code}:
|
||||||
|
{{
|
||||||
|
// {opCode.function.GetType().Name}");
|
||||||
|
AppendDecryptCode(lines, opCode.function);
|
||||||
|
lines.Add(@" return value;
|
||||||
|
}");
|
||||||
|
}
|
||||||
|
|
||||||
|
lines.Add(@"
|
||||||
|
default:
|
||||||
|
throw new System.Exception($""Invalid opCode:{opCode}"");
|
||||||
|
}
|
||||||
|
}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AppendHeader(List<string> lines)
|
||||||
|
{
|
||||||
|
|
||||||
|
lines.Add($"/// This file is auto-generated by Obfuz. Do not modify it.");
|
||||||
|
lines.Add($"///");
|
||||||
|
//lines.Add($"/// Created Time: {DateTime.Now}");
|
||||||
|
|
||||||
|
lines.Add($"/// Version: {_vm.version}");
|
||||||
|
lines.Add($"/// SecretKey: {_vm.codeGenerationSecretKey}");
|
||||||
|
lines.Add($"/// OpCodeCount: {_vm.opCodes.Length}");
|
||||||
|
|
||||||
|
lines.Add(@"
|
||||||
|
namespace Obfuz.EncryptionVM
|
||||||
|
{
|
||||||
|
public class GeneratedEncryptionVirtualMachine : Obfuz.EncryptorBase
|
||||||
|
{");
|
||||||
|
lines.Add($@"
|
||||||
|
private const int kOpCodeBits = {_opCodeBits};
|
||||||
|
|
||||||
|
private const int kOpCodeCount = {_opCodeCount};
|
||||||
|
|
||||||
|
private const int kOpCodeMask = {_opCodeCount - 1};
|
||||||
|
");
|
||||||
|
lines.Add(@"
|
||||||
|
|
||||||
|
private readonly int[] _secretKey;
|
||||||
|
|
||||||
|
public GeneratedEncryptionVirtualMachine(byte[] secretKey)
|
||||||
|
{
|
||||||
|
this._secretKey = ConvertToIntKey(secretKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int OpCodeCount => kOpCodeCount;
|
||||||
|
|
||||||
|
public override int Encrypt(int value, int opts, int salt)
|
||||||
|
{
|
||||||
|
uint uopts = (uint)opts;
|
||||||
|
uint revertOps = 0;
|
||||||
|
while (uopts != 0)
|
||||||
|
{
|
||||||
|
uint opCode = uopts & kOpCodeMask;
|
||||||
|
revertOps <<= kOpCodeBits;
|
||||||
|
revertOps |= opCode;
|
||||||
|
uopts >>= kOpCodeBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (revertOps != 0)
|
||||||
|
{
|
||||||
|
uint opCode = revertOps & kOpCodeMask;
|
||||||
|
value = ExecuteEncrypt(value, (int)opCode, salt);
|
||||||
|
revertOps >>= kOpCodeBits;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Decrypt(int value, int opts, int salt)
|
||||||
|
{
|
||||||
|
uint uopts = (uint)opts;
|
||||||
|
while (uopts != 0)
|
||||||
|
{
|
||||||
|
uint opCode = uopts & kOpCodeMask;
|
||||||
|
value = ExecuteDecrypt(value, (int)opCode, salt);
|
||||||
|
uopts >>= kOpCodeBits;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AppendTailer(List<string> lines)
|
||||||
|
{
|
||||||
|
lines.Add(@"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AppendEncryptCode(List<string> lines, IEncryptionInstruction instruction)
|
||||||
|
{
|
||||||
|
instruction.GenerateEncryptCode(lines, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AppendDecryptCode(List<string> lines, IEncryptionInstruction instruction)
|
||||||
|
{
|
||||||
|
instruction.GenerateDecryptCode(lines, " ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
using NUnit.Framework;
|
||||||
|
using Obfuz.EncryptionVM.Instructions;
|
||||||
|
using Obfuz.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine.Assertions;
|
||||||
|
using UnityEngine.UIElements;
|
||||||
|
|
||||||
|
namespace Obfuz.EncryptionVM
|
||||||
|
{
|
||||||
|
public class VirtualMachineCreator
|
||||||
|
{
|
||||||
|
private readonly string _vmGenerationSecretKey;
|
||||||
|
private readonly IRandom _random;
|
||||||
|
|
||||||
|
public const int CodeGenerationSecretKeyLength = 1024;
|
||||||
|
|
||||||
|
public const int VirtualMachineVersion = 1;
|
||||||
|
|
||||||
|
public VirtualMachineCreator(string vmGenerationSecretKey)
|
||||||
|
{
|
||||||
|
_vmGenerationSecretKey = vmGenerationSecretKey;
|
||||||
|
byte[] byteGenerationSecretKey = KeyGenerator.GenerateKey(vmGenerationSecretKey, CodeGenerationSecretKeyLength);
|
||||||
|
int[] intGenerationSecretKey = KeyGenerator.ConvertToIntKey(byteGenerationSecretKey);
|
||||||
|
_random = new RandomWithKey(intGenerationSecretKey, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly List<Func<IRandom, int, EncryptionInstructionBase>> _instructionCreators = new List<Func<IRandom, int, EncryptionInstructionBase>>
|
||||||
|
{
|
||||||
|
(r, len) => new AddInstruction(r.NextInt(), r.NextInt(len)),
|
||||||
|
(r, len) => new XorInstruction(r.NextInt(), r.NextInt(len)),
|
||||||
|
(r, len) => new BitRotateInstruction(r.NextInt(32), r.NextInt(len)),
|
||||||
|
(r, len) => new MultipleInstruction(r.NextInt() | 0x1, r.NextInt(len)),
|
||||||
|
(r, len) => new AddRotateXorInstruction(r.NextInt(), r.NextInt(len), r.NextInt(32), r.NextInt()),
|
||||||
|
(r, len) => new AddXorRotateInstruction(r.NextInt(), r.NextInt(len), r.NextInt(), r.NextInt(32)),
|
||||||
|
(r, len) => new XorAddRotateInstruction(r.NextInt(), r.NextInt(), r.NextInt(len), r.NextInt(32)),
|
||||||
|
(r, len) => new MultipleRotateXorInstruction(r.NextInt() | 0x1, r.NextInt(len), r.NextInt(32), r.NextInt()),
|
||||||
|
(r, len) => new MultipleXorRotateInstruction(r.NextInt() | 0x1, r.NextInt(len), r.NextInt(), r.NextInt(32)),
|
||||||
|
(r, len) => new XorMultipleRotateInstruction(r.NextInt(), r.NextInt() | 0x1, r.NextInt(len), r.NextInt(32)),
|
||||||
|
};
|
||||||
|
|
||||||
|
private IEncryptionInstruction CreateRandomInstruction(int intSecretKeyLength)
|
||||||
|
{
|
||||||
|
return _instructionCreators[_random.NextInt(_instructionCreators.Count)](_random, intSecretKeyLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
private EncryptionInstructionWithOpCode CreateEncryptOpCode(ushort code)
|
||||||
|
{
|
||||||
|
IEncryptionInstruction inst = CreateRandomInstruction(VirtualMachine.SecretKeyLength / sizeof(int));
|
||||||
|
return new EncryptionInstructionWithOpCode(code, inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VirtualMachine CreateVirtualMachine(int opCodeCount)
|
||||||
|
{
|
||||||
|
if (opCodeCount < 64)
|
||||||
|
{
|
||||||
|
throw new System.Exception("OpCode count should be >= 64");
|
||||||
|
}
|
||||||
|
if ((opCodeCount & (opCodeCount - 1)) != 0)
|
||||||
|
{
|
||||||
|
throw new System.Exception("OpCode count should be power of 2");
|
||||||
|
}
|
||||||
|
var opCodes = new EncryptionInstructionWithOpCode[opCodeCount];
|
||||||
|
for (int i = 0; i < opCodes.Length; i++)
|
||||||
|
{
|
||||||
|
opCodes[i] = CreateEncryptOpCode((ushort)i);
|
||||||
|
}
|
||||||
|
return new VirtualMachine(VirtualMachineVersion, _vmGenerationSecretKey, opCodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
using Obfuz.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Text;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Assertions;
|
||||||
|
using UnityEngine.UIElements;
|
||||||
|
|
||||||
|
namespace Obfuz.EncryptionVM
|
||||||
|
{
|
||||||
|
|
||||||
|
public class VirtualMachineSimulator : EncryptorBase
|
||||||
|
{
|
||||||
|
private readonly EncryptionInstructionWithOpCode[] _opCodes;
|
||||||
|
private readonly int[] _secretKey;
|
||||||
|
|
||||||
|
public override int OpCodeCount => _opCodes.Length;
|
||||||
|
|
||||||
|
public VirtualMachineSimulator(VirtualMachine vm, byte[] byteSecretKey)
|
||||||
|
{
|
||||||
|
_opCodes = vm.opCodes;
|
||||||
|
_secretKey = KeyGenerator.ConvertToIntKey(byteSecretKey);
|
||||||
|
|
||||||
|
VerifyInstructions();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void VerifyInstructions()
|
||||||
|
{
|
||||||
|
int value = 0x11223344;
|
||||||
|
for (int i = 0; i < _opCodes.Length; i++)
|
||||||
|
{
|
||||||
|
int encryptedValue = _opCodes[i].Encrypt(value, _secretKey, i);
|
||||||
|
int decryptedValue = _opCodes[i].Decrypt(encryptedValue, _secretKey, i);
|
||||||
|
//Debug.Log($"instruction type:{_opCodes[i].function.GetType()}");
|
||||||
|
Assert.AreEqual(value, decryptedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ops = 11223344;
|
||||||
|
int salt = 789;
|
||||||
|
Assert.AreEqual(1, Decrypt(Encrypt(1, ops, salt), ops, salt));
|
||||||
|
Assert.AreEqual(1L, Decrypt(Encrypt(1L, ops, salt), ops, salt));
|
||||||
|
Assert.AreEqual(1.0f, Decrypt(Encrypt(1.0f, ops, salt), ops, salt));
|
||||||
|
Assert.AreEqual(1.0, Decrypt(Encrypt(1.0, ops, salt), ops, salt));
|
||||||
|
|
||||||
|
byte[] strBytes = Encrypt("abcdef", ops, salt);
|
||||||
|
Assert.AreEqual("abcdef", DecryptString(strBytes, 0, strBytes.Length, ops, salt));
|
||||||
|
var arr = new byte[100];
|
||||||
|
for (int i = 0; i < arr.Length ; i++)
|
||||||
|
{
|
||||||
|
arr[i] = (byte)i;
|
||||||
|
}
|
||||||
|
EncryptBlock(arr, ops, salt);
|
||||||
|
DecryptBlock(arr, ops, salt);
|
||||||
|
for (int i = 0; i < arr.Length; i++)
|
||||||
|
{
|
||||||
|
Assert.AreEqual(i, arr[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<uint> DecodeOps(uint ops)
|
||||||
|
{
|
||||||
|
var codes = new List<uint>();
|
||||||
|
while (ops != 0)
|
||||||
|
{
|
||||||
|
uint code = ops % (uint)_opCodes.Length;
|
||||||
|
codes.Add(code);
|
||||||
|
ops /= (uint)_opCodes.Length;
|
||||||
|
}
|
||||||
|
return codes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Encrypt(int value, int ops, int salt)
|
||||||
|
{
|
||||||
|
var codes = DecodeOps((uint)ops);
|
||||||
|
for (int i = codes.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
var opCode = _opCodes[codes[i]];
|
||||||
|
value = opCode.Encrypt(value, _secretKey, salt);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Decrypt(int value, int ops, int salt)
|
||||||
|
{
|
||||||
|
var codes = DecodeOps((uint)ops);
|
||||||
|
foreach (var code in codes)
|
||||||
|
{
|
||||||
|
var opCode = _opCodes[code];
|
||||||
|
value = opCode.Decrypt(value, _secretKey, salt);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
using Obfuz.ObfusPasses;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz
|
||||||
|
{
|
||||||
|
public interface IObfuscationPass
|
||||||
|
{
|
||||||
|
ObfuscationPassType Type { get; }
|
||||||
|
|
||||||
|
void Start();
|
||||||
|
|
||||||
|
void Stop();
|
||||||
|
|
||||||
|
void Process();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
using dnlib.DotNet.Emit;
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Obfuz.Emit;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses
|
||||||
|
{
|
||||||
|
public abstract class BasicBlockObfuscationPassBase : ObfuscationPassBase
|
||||||
|
{
|
||||||
|
protected abstract bool NeedObfuscateMethod(MethodDef method);
|
||||||
|
|
||||||
|
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,
|
||||||
|
IList<Instruction> globalInstructions, List<Instruction> outputInstructions, List<Instruction> totalFinalInstructions);
|
||||||
|
|
||||||
|
private void ObfuscateData(MethodDef method)
|
||||||
|
{
|
||||||
|
BasicBlockCollection bbc = new BasicBlockCollection(method);
|
||||||
|
|
||||||
|
IList<Instruction> instructions = method.Body.Instructions;
|
||||||
|
|
||||||
|
var outputInstructions = new List<Instruction>();
|
||||||
|
var totalFinalInstructions = new List<Instruction>();
|
||||||
|
for (int i = 0; i < instructions.Count; i++)
|
||||||
|
{
|
||||||
|
Instruction inst = instructions[i];
|
||||||
|
BasicBlock block = bbc.GetBasicBlockByInstruction(inst);
|
||||||
|
outputInstructions.Clear();
|
||||||
|
if (TryObfuscateInstruction(method, inst, block, i, instructions, outputInstructions, totalFinalInstructions))
|
||||||
|
{
|
||||||
|
// current instruction may be the target of control flow instruction, so we can't remove it directly.
|
||||||
|
// we replace it with nop now, then remove it in CleanUpInstructionPass
|
||||||
|
inst.OpCode = outputInstructions[0].OpCode;
|
||||||
|
inst.Operand = outputInstructions[0].Operand;
|
||||||
|
totalFinalInstructions.Add(inst);
|
||||||
|
for (int k = 1; k < outputInstructions.Count; k++)
|
||||||
|
{
|
||||||
|
totalFinalInstructions.Add(outputInstructions[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
totalFinalInstructions.Add(inst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
instructions.Clear();
|
||||||
|
foreach (var obInst in totalFinalInstructions)
|
||||||
|
{
|
||||||
|
instructions.Add(obInst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,92 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using dnlib.DotNet.Emit;
|
||||||
|
using Obfuz.Utils;
|
||||||
|
using Obfuz.Emit;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine.Assertions;
|
||||||
|
using Obfuz.Settings;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.CallObfus
|
||||||
|
{
|
||||||
|
public class CallObfusPass : BasicBlockObfuscationPassBase
|
||||||
|
{
|
||||||
|
private readonly List<string> _configFiles;
|
||||||
|
private readonly int _obfuscationLevel;
|
||||||
|
private IObfuscator _dynamicProxyObfuscator;
|
||||||
|
private IObfuscationPolicy _dynamicProxyPolicy;
|
||||||
|
|
||||||
|
public override ObfuscationPassType Type => ObfuscationPassType.CallObfus;
|
||||||
|
|
||||||
|
public CallObfusPass(CallObfuscationSettings settings)
|
||||||
|
{
|
||||||
|
_configFiles = settings.ruleFiles.ToList();
|
||||||
|
_obfuscationLevel = settings.obfuscationLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Stop()
|
||||||
|
{
|
||||||
|
_dynamicProxyObfuscator.Done();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Start()
|
||||||
|
{
|
||||||
|
var ctx = ObfuscationPassContext.Current;
|
||||||
|
_dynamicProxyObfuscator = new DefaultCallProxyObfuscator(ctx.encryptionScopeProvider, ctx.constFieldAllocator, ctx.moduleEntityManager, _obfuscationLevel);
|
||||||
|
_dynamicProxyPolicy = new ConfigurableObfuscationPolicy(ctx.assembliesToObfuscate, _configFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool NeedObfuscateMethod(MethodDef method)
|
||||||
|
{
|
||||||
|
return _dynamicProxyPolicy.NeedObfuscateCallInMethod(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool TryObfuscateInstruction(MethodDef callerMethod, Instruction inst, BasicBlock block,
|
||||||
|
int instructionIndex, IList<Instruction> globalInstructions, List<Instruction> outputInstructions, List<Instruction> totalFinalInstructions)
|
||||||
|
{
|
||||||
|
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 (instructionIndex > 0 && globalInstructions[instructionIndex - 1].OpCode.Code == Code.Constrained)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
callVir = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_dynamicProxyPolicy.NeedObfuscateCalledMethod(callerMethod, calledMethod, callVir, block.inLoop))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObfuscationCachePolicy cachePolicy = _dynamicProxyPolicy.GetMethodObfuscationCachePolicy(callerMethod);
|
||||||
|
bool cachedCallIndex = block.inLoop ? cachePolicy.cacheInLoop : cachePolicy.cacheNotInLoop;
|
||||||
|
_dynamicProxyObfuscator.Obfuscate(callerMethod, calledMethod, callVir, cachedCallIndex, outputInstructions);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,293 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using dnlib.DotNet.Emit;
|
||||||
|
using Obfuz.Editor;
|
||||||
|
using Obfuz.Emit;
|
||||||
|
using Obfuz.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using MethodImplAttributes = dnlib.DotNet.MethodImplAttributes;
|
||||||
|
using TypeAttributes = dnlib.DotNet.TypeAttributes;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.CallObfus
|
||||||
|
{
|
||||||
|
public struct ProxyCallMethodData
|
||||||
|
{
|
||||||
|
public readonly MethodDef proxyMethod;
|
||||||
|
public readonly int encryptOps;
|
||||||
|
public readonly int salt;
|
||||||
|
public readonly int encryptedIndex;
|
||||||
|
public readonly int index;
|
||||||
|
|
||||||
|
public ProxyCallMethodData(MethodDef proxyMethod, int encryptOps, int salt, int encryptedIndex, int index)
|
||||||
|
{
|
||||||
|
this.proxyMethod = proxyMethod;
|
||||||
|
this.encryptOps = encryptOps;
|
||||||
|
this.salt = salt;
|
||||||
|
this.encryptedIndex = encryptedIndex;
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ModuleCallProxyAllocator : IGroupByModuleEntity
|
||||||
|
{
|
||||||
|
private ModuleDef _module;
|
||||||
|
private readonly EncryptionScopeProvider _encryptionScopeProvider;
|
||||||
|
private readonly int _encryptionLevel;
|
||||||
|
|
||||||
|
private EncryptionScopeInfo _encryptionScope;
|
||||||
|
private bool _done;
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
public MethodDef proxyMethod;
|
||||||
|
|
||||||
|
public int index;
|
||||||
|
public int encryptedOps;
|
||||||
|
public int salt;
|
||||||
|
public int encryptedIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Dictionary<MethodKey, MethodProxyInfo> _methodProxys = new Dictionary<MethodKey, MethodProxyInfo>();
|
||||||
|
|
||||||
|
|
||||||
|
const int maxProxyMethodPerDispatchMethod = 1000;
|
||||||
|
|
||||||
|
class CallInfo
|
||||||
|
{
|
||||||
|
public IMethod method;
|
||||||
|
public bool callVir;
|
||||||
|
}
|
||||||
|
|
||||||
|
class DispatchMethodInfo
|
||||||
|
{
|
||||||
|
public MethodDef methodDef;
|
||||||
|
public List<CallInfo> methods = new List<CallInfo>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Dictionary<MethodSig, List<DispatchMethodInfo>> _dispatchMethods = new Dictionary<MethodSig, List<DispatchMethodInfo>>(SignatureEqualityComparer.Instance);
|
||||||
|
|
||||||
|
|
||||||
|
private TypeDef _proxyTypeDef;
|
||||||
|
|
||||||
|
public ModuleCallProxyAllocator(EncryptionScopeProvider encryptionScopeProvider, int encryptionLevel)
|
||||||
|
{
|
||||||
|
_encryptionScopeProvider = encryptionScopeProvider;
|
||||||
|
_encryptionLevel = encryptionLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Init(ModuleDef mod)
|
||||||
|
{
|
||||||
|
_module = mod;
|
||||||
|
_encryptionScope = _encryptionScopeProvider.GetScope(mod);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TypeDef CreateProxyTypeDef()
|
||||||
|
{
|
||||||
|
var typeDef = new TypeDefUser($"{ConstValues.ObfuzInternalSymbolNamePrefix}ProxyCall", _module.CorLibTypes.Object.ToTypeDefOrRef());
|
||||||
|
typeDef.Attributes = TypeAttributes.NotPublic | TypeAttributes.Sealed;
|
||||||
|
_module.EnableTypeDefFindCache = false;
|
||||||
|
_module.Types.Add(typeDef);
|
||||||
|
_module.EnableTypeDefFindCache = true;
|
||||||
|
return typeDef;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MethodDef CreateDispatchMethodInfo(MethodSig methodSig)
|
||||||
|
{
|
||||||
|
if (_proxyTypeDef == null)
|
||||||
|
{
|
||||||
|
_proxyTypeDef = CreateProxyTypeDef();
|
||||||
|
}
|
||||||
|
MethodDef methodDef = new MethodDefUser($"{ConstValues.ObfuzInternalSymbolNamePrefix}ProxyCall$Dispatch${_proxyTypeDef.Methods.Count}", methodSig,
|
||||||
|
MethodImplAttributes.IL | MethodImplAttributes.Managed,
|
||||||
|
MethodAttributes.Static | MethodAttributes.Private);
|
||||||
|
methodDef.DeclaringType = _proxyTypeDef;
|
||||||
|
return methodDef;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MethodSig CreateDispatchMethodSig(IMethod method)
|
||||||
|
{
|
||||||
|
MethodSig methodSig = MetaUtil.ToSharedMethodSig(_module.CorLibTypes, MetaUtil.GetInflatedMethodSig(method));
|
||||||
|
//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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// extra param for index
|
||||||
|
methodSig.Params.Add(_module.CorLibTypes.Int32);
|
||||||
|
return MethodSig.CreateStatic(methodSig.RetType, methodSig.Params.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GenerateSalt(IRandom random)
|
||||||
|
{
|
||||||
|
return random.NextInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GenerateEncryptOps(IRandom random)
|
||||||
|
{
|
||||||
|
return EncryptionUtil.GenerateEncryptionOpCodes(random, _encryptionScope.encryptor, _encryptionLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DispatchMethodInfo GetDispatchMethod(IMethod method)
|
||||||
|
{
|
||||||
|
MethodSig methodSig = CreateDispatchMethodSig(method);
|
||||||
|
if (!_dispatchMethods.TryGetValue(methodSig, out var dispatchMethods))
|
||||||
|
{
|
||||||
|
dispatchMethods = new List<DispatchMethodInfo>();
|
||||||
|
_dispatchMethods.Add(methodSig, dispatchMethods);
|
||||||
|
}
|
||||||
|
if (dispatchMethods.Count == 0 || dispatchMethods.Last().methods.Count >= maxProxyMethodPerDispatchMethod)
|
||||||
|
{
|
||||||
|
var newDispatchMethodInfo = new DispatchMethodInfo
|
||||||
|
{
|
||||||
|
methodDef = CreateDispatchMethodInfo(methodSig),
|
||||||
|
};
|
||||||
|
dispatchMethods.Add(newDispatchMethodInfo);
|
||||||
|
}
|
||||||
|
return dispatchMethods.Last();
|
||||||
|
}
|
||||||
|
|
||||||
|
private IRandom CreateRandomForMethod(IMethod method, bool callVir)
|
||||||
|
{
|
||||||
|
int seed = MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method);
|
||||||
|
return _encryptionScope.localRandomCreator(seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProxyCallMethodData Allocate(IMethod method, bool callVir)
|
||||||
|
{
|
||||||
|
if (_done)
|
||||||
|
{
|
||||||
|
throw new Exception("can't Allocate after done");
|
||||||
|
}
|
||||||
|
var key = new MethodKey(method, callVir);
|
||||||
|
if (!_methodProxys.TryGetValue(key, out var proxyInfo))
|
||||||
|
{
|
||||||
|
var methodDispatcher = GetDispatchMethod(method);
|
||||||
|
|
||||||
|
int index = methodDispatcher.methods.Count;
|
||||||
|
IRandom localRandom = CreateRandomForMethod(method, callVir);
|
||||||
|
int encryptOps = GenerateEncryptOps(localRandom);
|
||||||
|
int salt = GenerateSalt(localRandom);
|
||||||
|
int encryptedIndex = _encryptionScope.encryptor.Encrypt(index, encryptOps, salt);
|
||||||
|
proxyInfo = new MethodProxyInfo()
|
||||||
|
{
|
||||||
|
proxyMethod = methodDispatcher.methodDef,
|
||||||
|
index = index,
|
||||||
|
encryptedOps = encryptOps,
|
||||||
|
salt = salt,
|
||||||
|
encryptedIndex = encryptedIndex,
|
||||||
|
};
|
||||||
|
methodDispatcher.methods.Add(new CallInfo { method = method, callVir = callVir});
|
||||||
|
_methodProxys.Add(key, proxyInfo);
|
||||||
|
}
|
||||||
|
return new ProxyCallMethodData(proxyInfo.proxyMethod, proxyInfo.encryptedOps, proxyInfo.salt, proxyInfo.encryptedIndex, proxyInfo.index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Done()
|
||||||
|
{
|
||||||
|
if (_done)
|
||||||
|
{
|
||||||
|
throw new Exception("Already done");
|
||||||
|
}
|
||||||
|
_done = true;
|
||||||
|
|
||||||
|
foreach (DispatchMethodInfo dispatchMethod in _dispatchMethods.Values.SelectMany(ms => ms))
|
||||||
|
{
|
||||||
|
var methodDef = dispatchMethod.methodDef;
|
||||||
|
var methodSig = methodDef.MethodSig;
|
||||||
|
|
||||||
|
|
||||||
|
var body = new CilBody();
|
||||||
|
methodDef.Body = body;
|
||||||
|
var ins = body.Instructions;
|
||||||
|
|
||||||
|
foreach (Parameter param in methodDef.Parameters)
|
||||||
|
{
|
||||||
|
ins.Add(Instruction.Create(OpCodes.Ldarg, param));
|
||||||
|
}
|
||||||
|
|
||||||
|
var switchCases = new List<Instruction>();
|
||||||
|
var switchInst = Instruction.Create(OpCodes.Switch, switchCases);
|
||||||
|
ins.Add(switchInst);
|
||||||
|
var ret = Instruction.Create(OpCodes.Ret);
|
||||||
|
foreach (CallInfo ci in dispatchMethod.methods)
|
||||||
|
{
|
||||||
|
var callTargetMethod = Instruction.Create(ci.callVir ? OpCodes.Callvirt : OpCodes.Call, ci.method);
|
||||||
|
switchCases.Add(callTargetMethod);
|
||||||
|
ins.Add(callTargetMethod);
|
||||||
|
ins.Add(Instruction.Create(OpCodes.Br, ret));
|
||||||
|
}
|
||||||
|
ins.Add(ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,372 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using Obfuz.Conf;
|
||||||
|
using Obfuz.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.CallObfus
|
||||||
|
{
|
||||||
|
public class ConfigurableObfuscationPolicy : ObfuscationPolicyBase
|
||||||
|
{
|
||||||
|
class WhiteListAssembly
|
||||||
|
{
|
||||||
|
public string name;
|
||||||
|
public NameMatcher nameMatcher;
|
||||||
|
public bool? obfuscateNone;
|
||||||
|
public List<WhiteListType> types = new List<WhiteListType>();
|
||||||
|
}
|
||||||
|
|
||||||
|
class WhiteListType
|
||||||
|
{
|
||||||
|
public string name;
|
||||||
|
public NameMatcher nameMatcher;
|
||||||
|
public bool? obfuscateNone;
|
||||||
|
public List<WhiteListMethod> methods = new List<WhiteListMethod>();
|
||||||
|
}
|
||||||
|
|
||||||
|
class WhiteListMethod
|
||||||
|
{
|
||||||
|
public string name;
|
||||||
|
public NameMatcher nameMatcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ObfuscationRule : IRule<ObfuscationRule>
|
||||||
|
{
|
||||||
|
public bool? disableObfuscation;
|
||||||
|
public bool? obfuscateCallInLoop;
|
||||||
|
public bool? cacheCallIndexInLoop;
|
||||||
|
public bool? cacheCallIndexNotLoop;
|
||||||
|
|
||||||
|
public void InheritParent(ObfuscationRule parentRule)
|
||||||
|
{
|
||||||
|
if (disableObfuscation == null)
|
||||||
|
{
|
||||||
|
disableObfuscation = parentRule.disableObfuscation;
|
||||||
|
}
|
||||||
|
if (obfuscateCallInLoop == null)
|
||||||
|
{
|
||||||
|
obfuscateCallInLoop = parentRule.obfuscateCallInLoop;
|
||||||
|
}
|
||||||
|
if (cacheCallIndexInLoop == null)
|
||||||
|
{
|
||||||
|
cacheCallIndexInLoop = parentRule.cacheCallIndexInLoop;
|
||||||
|
}
|
||||||
|
if (cacheCallIndexNotLoop == null)
|
||||||
|
{
|
||||||
|
cacheCallIndexNotLoop = parentRule.cacheCallIndexNotLoop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AssemblySpec : AssemblyRuleBase<TypeSpec, MethodSpec, ObfuscationRule>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
class TypeSpec : TypeRuleBase<MethodSpec, ObfuscationRule>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
class MethodSpec : MethodRuleBase<ObfuscationRule>
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly ObfuscationRule s_default = new ObfuscationRule()
|
||||||
|
{
|
||||||
|
disableObfuscation = false,
|
||||||
|
obfuscateCallInLoop = true,
|
||||||
|
cacheCallIndexInLoop = true,
|
||||||
|
cacheCallIndexNotLoop = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule> _configParser;
|
||||||
|
|
||||||
|
private ObfuscationRule _global;
|
||||||
|
private readonly List<WhiteListAssembly> _whiteListAssemblies = new List<WhiteListAssembly>();
|
||||||
|
|
||||||
|
private readonly Dictionary<IMethod, bool> _whiteListMethodCache = new Dictionary<IMethod, bool>(MethodEqualityComparer.CompareDeclaringTypes);
|
||||||
|
private readonly Dictionary<MethodDef, ObfuscationRule> _methodRuleCache = new Dictionary<MethodDef, ObfuscationRule>();
|
||||||
|
|
||||||
|
public ConfigurableObfuscationPolicy(List<string> toObfuscatedAssemblyNames, List<string> xmlConfigFiles)
|
||||||
|
{
|
||||||
|
_configParser = new XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule>(toObfuscatedAssemblyNames,
|
||||||
|
ParseObfuscationRule, ParseGlobalElement);
|
||||||
|
LoadConfigs(xmlConfigFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadConfigs(List<string> configFiles)
|
||||||
|
{
|
||||||
|
_configParser.LoadConfigs(configFiles);
|
||||||
|
|
||||||
|
if (_global == null)
|
||||||
|
{
|
||||||
|
_global = s_default;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_global.InheritParent(s_default);
|
||||||
|
}
|
||||||
|
_configParser.InheritParentRules(_global);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ParseGlobalElement(string configFile, XmlElement ele)
|
||||||
|
{
|
||||||
|
switch (ele.Name)
|
||||||
|
{
|
||||||
|
case "global": _global = ParseObfuscationRule(configFile, ele); break;
|
||||||
|
case "whitelist": ParseWhitelist(ele); break;
|
||||||
|
default: throw new Exception($"Invalid xml file {configFile}, unknown node {ele.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ObfuscationRule ParseObfuscationRule(string configFile, XmlElement ele)
|
||||||
|
{
|
||||||
|
var rule = new ObfuscationRule();
|
||||||
|
if (ele.HasAttribute("disableObfuscation"))
|
||||||
|
{
|
||||||
|
rule.disableObfuscation = ConfigUtil.ParseBool(ele.GetAttribute("disableObfuscation"));
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ParseWhitelist(XmlElement ruleEle)
|
||||||
|
{
|
||||||
|
foreach (XmlNode xmlNode in ruleEle.ChildNodes)
|
||||||
|
{
|
||||||
|
if (!(xmlNode is XmlElement childEle))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (childEle.Name)
|
||||||
|
{
|
||||||
|
case "assembly":
|
||||||
|
{
|
||||||
|
var ass = ParseWhiteListAssembly(childEle);
|
||||||
|
_whiteListAssemblies.Add(ass);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: throw new Exception($"Invalid xml file, unknown node {childEle.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private WhiteListAssembly ParseWhiteListAssembly(XmlElement element)
|
||||||
|
{
|
||||||
|
var ass = new WhiteListAssembly();
|
||||||
|
ass.name = element.GetAttribute("name");
|
||||||
|
ass.nameMatcher = new NameMatcher(ass.name);
|
||||||
|
if (element.HasAttribute("obfuscateNone"))
|
||||||
|
{
|
||||||
|
ass.obfuscateNone = ConfigUtil.ParseBool(element.GetAttribute("obfuscateNone"));
|
||||||
|
}
|
||||||
|
foreach (XmlNode node in element.ChildNodes)
|
||||||
|
{
|
||||||
|
if (!(node is XmlElement ele))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (ele.Name)
|
||||||
|
{
|
||||||
|
case "type":
|
||||||
|
ass.types.Add(ParseWhiteListType(ele));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception($"Invalid xml file, unknown node {ele.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ass;
|
||||||
|
}
|
||||||
|
|
||||||
|
private WhiteListType ParseWhiteListType(XmlElement element)
|
||||||
|
{
|
||||||
|
var type = new WhiteListType();
|
||||||
|
type.name = element.GetAttribute("name");
|
||||||
|
type.nameMatcher = new NameMatcher(type.name);
|
||||||
|
if (element.HasAttribute("obfuscateNone"))
|
||||||
|
{
|
||||||
|
type.obfuscateNone = ConfigUtil.ParseBool(element.GetAttribute("obfuscateNone"));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (XmlNode node in element.ChildNodes)
|
||||||
|
{
|
||||||
|
if (!(node is XmlElement ele))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (ele.Name)
|
||||||
|
{
|
||||||
|
case "method":
|
||||||
|
{
|
||||||
|
type.methods.Add(ParseWhiteListMethod(ele));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: throw new Exception($"Invalid xml file, unknown node {ele.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
private WhiteListMethod ParseWhiteListMethod(XmlElement element)
|
||||||
|
{
|
||||||
|
var method = new WhiteListMethod();
|
||||||
|
method.name = element.GetAttribute("name");
|
||||||
|
method.nameMatcher = new NameMatcher(method.name);
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ObfuscationRule GetMethodObfuscationRule(MethodDef method)
|
||||||
|
{
|
||||||
|
if (!_methodRuleCache.TryGetValue(method, out var rule))
|
||||||
|
{
|
||||||
|
rule = _configParser.GetMethodRule(method, s_default);
|
||||||
|
_methodRuleCache[method] = rule;
|
||||||
|
}
|
||||||
|
return rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedObfuscateCallInMethod(MethodDef method)
|
||||||
|
{
|
||||||
|
ObfuscationRule rule = GetMethodObfuscationRule(method);
|
||||||
|
return rule.disableObfuscation != true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
// special handle
|
||||||
|
// don't proxy call for List<T>.Enumerator GetEnumerator()
|
||||||
|
if (methodName == "GetEnumerator")
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ComputeIsInWhiteList(IMethod calledMethod)
|
||||||
|
{
|
||||||
|
ITypeDefOrRef declaringType = calledMethod.DeclaringType;
|
||||||
|
TypeSig declaringTypeSig = calledMethod.DeclaringType.ToTypeSig();
|
||||||
|
declaringTypeSig = declaringTypeSig.RemovePinnedAndModifiers();
|
||||||
|
switch (declaringTypeSig.ElementType)
|
||||||
|
{
|
||||||
|
case ElementType.ValueType:
|
||||||
|
case ElementType.Class:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ElementType.GenericInst:
|
||||||
|
{
|
||||||
|
if (MetaUtil.ContainsContainsGenericParameter(calledMethod))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeDef typeDef = declaringType.ResolveTypeDef();
|
||||||
|
|
||||||
|
if (IsSpecialNotObfuscatedMethod(typeDef, calledMethod))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
string assName = typeDef.Module.Assembly.Name;
|
||||||
|
string typeFullName = typeDef.FullName;
|
||||||
|
string methodName = calledMethod.Name;
|
||||||
|
foreach (var ass in _whiteListAssemblies)
|
||||||
|
{
|
||||||
|
if (!ass.nameMatcher.IsMatch(assName))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ass.obfuscateNone == true)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
foreach (var type in ass.types)
|
||||||
|
{
|
||||||
|
if (!type.nameMatcher.IsMatch(typeFullName))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (type.obfuscateNone == true)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
foreach (var method in type.methods)
|
||||||
|
{
|
||||||
|
if (method.nameMatcher.IsMatch(methodName))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsInWhiteList(IMethod method)
|
||||||
|
{
|
||||||
|
if (!_whiteListMethodCache.TryGetValue(method, out var isWhiteList))
|
||||||
|
{
|
||||||
|
isWhiteList = ComputeIsInWhiteList(method);
|
||||||
|
_whiteListMethodCache.Add(method, isWhiteList);
|
||||||
|
}
|
||||||
|
return isWhiteList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedObfuscateCalledMethod(MethodDef callerMethod, IMethod calledMethod, bool callVir, bool currentInLoop)
|
||||||
|
{
|
||||||
|
if (IsInWhiteList(calledMethod))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ObfuscationRule rule = GetMethodObfuscationRule(callerMethod);
|
||||||
|
if (currentInLoop && rule.obfuscateCallInLoop == false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
using dnlib.DotNet.Emit;
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Obfuz.Utils;
|
||||||
|
using Obfuz.Emit;
|
||||||
|
using Obfuz.Data;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.CallObfus
|
||||||
|
{
|
||||||
|
public class DefaultCallProxyObfuscator : ObfuscatorBase
|
||||||
|
{
|
||||||
|
private readonly EncryptionScopeProvider _encryptionScopeProvider;
|
||||||
|
private readonly ConstFieldAllocator _constFieldAllocator;
|
||||||
|
private readonly CallProxyAllocator _proxyCallAllocator;
|
||||||
|
private readonly GroupByModuleEntityManager _moduleEntityManager;
|
||||||
|
|
||||||
|
public DefaultCallProxyObfuscator(EncryptionScopeProvider encryptionScopeProvider, ConstFieldAllocator constFieldAllocator, GroupByModuleEntityManager moduleEntityManager, int encryptionLevel)
|
||||||
|
{
|
||||||
|
_encryptionScopeProvider = encryptionScopeProvider;
|
||||||
|
_constFieldAllocator = constFieldAllocator;
|
||||||
|
_moduleEntityManager = moduleEntityManager;
|
||||||
|
_proxyCallAllocator = new CallProxyAllocator(encryptionScopeProvider, moduleEntityManager, encryptionLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Done()
|
||||||
|
{
|
||||||
|
_proxyCallAllocator.Done();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Obfuscate(MethodDef callerMethod, IMethod calledMethod, bool callVir, bool needCacheCall, List<Instruction> obfuscatedInstructions)
|
||||||
|
{
|
||||||
|
|
||||||
|
MethodSig sharedMethodSig = MetaUtil.ToSharedMethodSig(calledMethod.Module.CorLibTypes, MetaUtil.GetInflatedMethodSig(calledMethod));
|
||||||
|
ProxyCallMethodData proxyCallMethodData = _proxyCallAllocator.Allocate(callerMethod.Module, calledMethod, callVir);
|
||||||
|
DefaultMetadataImporter importer = _moduleEntityManager.GetDefaultModuleMetadataImporter(callerMethod.Module, _encryptionScopeProvider);
|
||||||
|
|
||||||
|
if (needCacheCall)
|
||||||
|
{
|
||||||
|
FieldDef cacheField = _constFieldAllocator.Allocate(callerMethod.Module, proxyCallMethodData.index);
|
||||||
|
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
obfuscatedInstructions.Add(Instruction.CreateLdcI4(proxyCallMethodData.encryptedIndex));
|
||||||
|
obfuscatedInstructions.Add(Instruction.CreateLdcI4(proxyCallMethodData.encryptOps));
|
||||||
|
obfuscatedInstructions.Add(Instruction.CreateLdcI4(proxyCallMethodData.salt));
|
||||||
|
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, importer.DecryptInt));
|
||||||
|
}
|
||||||
|
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, proxyCallMethodData.proxyMethod));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.CallObfus
|
||||||
|
{
|
||||||
|
|
||||||
|
public struct ObfuscationCachePolicy
|
||||||
|
{
|
||||||
|
public bool cacheInLoop;
|
||||||
|
public bool cacheNotInLoop;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IObfuscationPolicy
|
||||||
|
{
|
||||||
|
bool NeedObfuscateCallInMethod(MethodDef method);
|
||||||
|
|
||||||
|
ObfuscationCachePolicy GetMethodObfuscationCachePolicy(MethodDef method);
|
||||||
|
|
||||||
|
bool NeedObfuscateCalledMethod(MethodDef callerMethod, IMethod calledMethod, bool callVir, bool currentInLoop);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class ObfuscationPolicyBase : IObfuscationPolicy
|
||||||
|
{
|
||||||
|
public abstract bool NeedObfuscateCallInMethod(MethodDef method);
|
||||||
|
|
||||||
|
public abstract ObfuscationCachePolicy GetMethodObfuscationCachePolicy(MethodDef method);
|
||||||
|
|
||||||
|
public abstract bool NeedObfuscateCalledMethod(MethodDef callerMethod, IMethod calledMethod, bool callVir, bool currentInLoop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
using dnlib.DotNet.Emit;
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.CallObfus
|
||||||
|
{
|
||||||
|
public interface IObfuscator
|
||||||
|
{
|
||||||
|
void Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, bool needCacheCall, List<Instruction> obfuscatedInstructions);
|
||||||
|
|
||||||
|
void Done();
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class ObfuscatorBase : IObfuscator
|
||||||
|
{
|
||||||
|
public abstract void Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, bool needCacheCall, List<Instruction> obfuscatedInstructions);
|
||||||
|
public abstract void Done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using dnlib.DotNet.Emit;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.CleanUp
|
||||||
|
{
|
||||||
|
public class CleanUpInstructionPass : ObfuscationPassBase
|
||||||
|
{
|
||||||
|
public override ObfuscationPassType Type => ObfuscationPassType.None;
|
||||||
|
|
||||||
|
public override void Start()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Stop()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Process()
|
||||||
|
{
|
||||||
|
var ctx = ObfuscationPassContext.Current;
|
||||||
|
foreach (ModuleDef mod in ctx.modulesToObfuscate)
|
||||||
|
{
|
||||||
|
foreach (TypeDef type in mod.GetTypes())
|
||||||
|
{
|
||||||
|
foreach (MethodDef method in type.Methods)
|
||||||
|
{
|
||||||
|
if (method.HasBody)
|
||||||
|
{
|
||||||
|
CilBody body = method.Body;
|
||||||
|
body.SimplifyBranches();
|
||||||
|
body.OptimizeMacros();
|
||||||
|
body.OptimizeBranches();
|
||||||
|
// TODO remove dup
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using dnlib.DotNet.Emit;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.CleanUp
|
||||||
|
{
|
||||||
|
public class RemoveObfuzAttributesPass : ObfuscationPassBase
|
||||||
|
{
|
||||||
|
public override ObfuscationPassType Type => ObfuscationPassType.None;
|
||||||
|
|
||||||
|
public override void Start()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Stop()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void RemoveObfuzAttributes(IHasCustomAttribute provider)
|
||||||
|
{
|
||||||
|
CustomAttributeCollection customAttributes = provider.CustomAttributes;
|
||||||
|
if (customAttributes.Count == 0)
|
||||||
|
return;
|
||||||
|
var toRemove = new List<CustomAttribute>();
|
||||||
|
customAttributes.RemoveAll("Obfuz.ObfuzIgnoreAttribute");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Process()
|
||||||
|
{
|
||||||
|
var ctx = ObfuscationPassContext.Current;
|
||||||
|
foreach (ModuleDef mod in ctx.modulesToObfuscate)
|
||||||
|
{
|
||||||
|
RemoveObfuzAttributes(mod);
|
||||||
|
foreach (TypeDef type in mod.GetTypes())
|
||||||
|
{
|
||||||
|
RemoveObfuzAttributes(type);
|
||||||
|
foreach (FieldDef field in type.Fields)
|
||||||
|
{
|
||||||
|
RemoveObfuzAttributes(field);
|
||||||
|
}
|
||||||
|
foreach (MethodDef method in type.Methods)
|
||||||
|
{
|
||||||
|
RemoveObfuzAttributes(method);
|
||||||
|
foreach (Parameter param in method.Parameters)
|
||||||
|
{
|
||||||
|
if (param.ParamDef != null)
|
||||||
|
{
|
||||||
|
RemoveObfuzAttributes(param.ParamDef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (PropertyDef property in type.Properties)
|
||||||
|
{
|
||||||
|
RemoveObfuzAttributes(property);
|
||||||
|
}
|
||||||
|
foreach (EventDef eventDef in type.Events)
|
||||||
|
{
|
||||||
|
RemoveObfuzAttributes(eventDef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,489 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using Obfuz.Conf;
|
||||||
|
using Obfuz.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.ConstEncrypt
|
||||||
|
{
|
||||||
|
|
||||||
|
public class ConfigurableEncryptPolicy : EncryptPolicyBase
|
||||||
|
{
|
||||||
|
class ObfuscationRule : IRule<ObfuscationRule>
|
||||||
|
{
|
||||||
|
public bool? disableEncrypt;
|
||||||
|
public bool? encryptInt;
|
||||||
|
public bool? encryptLong;
|
||||||
|
public bool? encryptFloat;
|
||||||
|
public bool? encryptDouble;
|
||||||
|
public bool? encryptArray;
|
||||||
|
public bool? encryptString;
|
||||||
|
|
||||||
|
public bool? encryptConstInLoop;
|
||||||
|
public bool? encryptStringInLoop;
|
||||||
|
|
||||||
|
public bool? cacheConstInLoop;
|
||||||
|
public bool? cacheConstNotInLoop;
|
||||||
|
public bool? cacheStringInLoop;
|
||||||
|
public bool? cacheStringNotInLoop;
|
||||||
|
|
||||||
|
public void InheritParent(ObfuscationRule parentRule)
|
||||||
|
{
|
||||||
|
if (disableEncrypt == null)
|
||||||
|
disableEncrypt = parentRule.disableEncrypt;
|
||||||
|
if (encryptInt == null)
|
||||||
|
encryptInt = parentRule.encryptInt;
|
||||||
|
if (encryptLong == null)
|
||||||
|
encryptLong = parentRule.encryptLong;
|
||||||
|
if (encryptFloat == null)
|
||||||
|
encryptFloat = parentRule.encryptFloat;
|
||||||
|
if (encryptDouble == null)
|
||||||
|
encryptDouble = parentRule.encryptDouble;
|
||||||
|
if (encryptArray == null)
|
||||||
|
encryptArray = parentRule.encryptArray;
|
||||||
|
if (encryptString == null)
|
||||||
|
encryptString = parentRule.encryptString;
|
||||||
|
|
||||||
|
if (encryptConstInLoop == null)
|
||||||
|
encryptConstInLoop = parentRule.encryptConstInLoop;
|
||||||
|
if (encryptStringInLoop == null)
|
||||||
|
encryptStringInLoop = parentRule.encryptStringInLoop;
|
||||||
|
|
||||||
|
if (cacheConstInLoop == null)
|
||||||
|
cacheConstInLoop = parentRule.cacheConstInLoop;
|
||||||
|
if (cacheConstNotInLoop == null)
|
||||||
|
cacheConstNotInLoop = parentRule.cacheConstNotInLoop;
|
||||||
|
if (cacheStringInLoop == null)
|
||||||
|
cacheStringInLoop = parentRule.cacheStringInLoop;
|
||||||
|
if (cacheStringNotInLoop == null)
|
||||||
|
cacheStringNotInLoop = parentRule.cacheStringNotInLoop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MethodSpec : MethodRuleBase<ObfuscationRule>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
class TypeSpec : TypeRuleBase<MethodSpec, ObfuscationRule>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
class AssemblySpec : AssemblyRuleBase<TypeSpec, MethodSpec, ObfuscationRule>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly ObfuscationRule s_default = new ObfuscationRule()
|
||||||
|
{
|
||||||
|
disableEncrypt = false,
|
||||||
|
encryptInt = true,
|
||||||
|
encryptLong = true,
|
||||||
|
encryptFloat = true,
|
||||||
|
encryptDouble = true,
|
||||||
|
encryptArray = true,
|
||||||
|
encryptString = true,
|
||||||
|
encryptConstInLoop = true,
|
||||||
|
encryptStringInLoop = true,
|
||||||
|
cacheConstInLoop = true,
|
||||||
|
cacheConstNotInLoop = false,
|
||||||
|
cacheStringInLoop = true,
|
||||||
|
cacheStringNotInLoop = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
private ObfuscationRule _global;
|
||||||
|
|
||||||
|
public HashSet<int> notEncryptInts = new HashSet<int>();
|
||||||
|
public HashSet<long> notEncryptLongs = new HashSet<long>();
|
||||||
|
public HashSet<string> notEncryptStrings = new HashSet<string>();
|
||||||
|
public List<NumberRange<int>> notEncryptIntRanges = new List<NumberRange<int>>();
|
||||||
|
public List<NumberRange<long>> notEncryptLongRanges = new List<NumberRange<long>>();
|
||||||
|
public List<NumberRange<float>> notEncryptFloatRanges = new List<NumberRange<float>>();
|
||||||
|
public List<NumberRange<double>> notEncryptDoubleRanges = new List<NumberRange<double>>();
|
||||||
|
public List<NumberRange<int>> notEncryptArrayLengthRanges = new List<NumberRange<int>>();
|
||||||
|
public List<NumberRange<int>> notEncryptStringLengthRanges = new List<NumberRange<int>>();
|
||||||
|
|
||||||
|
private readonly XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule> _xmlParser;
|
||||||
|
|
||||||
|
private readonly Dictionary<string, AssemblySpec> _assemblySpecs = new Dictionary<string, AssemblySpec>();
|
||||||
|
private readonly Dictionary<MethodDef, ObfuscationRule> _methodRuleCache = new Dictionary<MethodDef, ObfuscationRule>();
|
||||||
|
|
||||||
|
public ConfigurableEncryptPolicy(List<string> toObfuscatedAssemblyNames, List<string> xmlConfigFiles)
|
||||||
|
{
|
||||||
|
_xmlParser = new XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule>(
|
||||||
|
toObfuscatedAssemblyNames, ParseObfuscationRule, ParseGlobalElement);
|
||||||
|
LoadConfigs(xmlConfigFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadConfigs(List<string> configFiles)
|
||||||
|
{
|
||||||
|
_xmlParser.LoadConfigs(configFiles);
|
||||||
|
if (_global == null)
|
||||||
|
{
|
||||||
|
_global = s_default;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_global.InheritParent(s_default);
|
||||||
|
}
|
||||||
|
_xmlParser.InheritParentRules(_global);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ParseGlobalElement(string configFile, XmlElement ele)
|
||||||
|
{
|
||||||
|
switch (ele.Name)
|
||||||
|
{
|
||||||
|
case "global": _global = ParseObfuscationRule(configFile, ele); break;
|
||||||
|
case "whitelist": ParseWhitelist(configFile, ele); break;
|
||||||
|
default: throw new Exception($"Invalid xml file {configFile}, unknown node {ele.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ObfuscationRule ParseObfuscationRule(string configFile, XmlElement ele)
|
||||||
|
{
|
||||||
|
var rule = new ObfuscationRule();
|
||||||
|
if (ele.HasAttribute("disableEncrypt"))
|
||||||
|
{
|
||||||
|
rule.disableEncrypt = ConfigUtil.ParseBool(ele.GetAttribute("disableEncrypt"));
|
||||||
|
}
|
||||||
|
if (ele.HasAttribute("encryptInt"))
|
||||||
|
{
|
||||||
|
rule.encryptInt = ConfigUtil.ParseBool(ele.GetAttribute("encryptInt"));
|
||||||
|
}
|
||||||
|
if (ele.HasAttribute("encryptLong"))
|
||||||
|
{
|
||||||
|
rule.encryptLong = ConfigUtil.ParseBool(ele.GetAttribute("encryptLong"));
|
||||||
|
}
|
||||||
|
if (ele.HasAttribute("encryptFloat"))
|
||||||
|
{
|
||||||
|
rule.encryptFloat = ConfigUtil.ParseBool(ele.GetAttribute("encryptFloat"));
|
||||||
|
}
|
||||||
|
if (ele.HasAttribute("encryptDouble"))
|
||||||
|
{
|
||||||
|
rule.encryptDouble = ConfigUtil.ParseBool(ele.GetAttribute("encryptDouble"));
|
||||||
|
}
|
||||||
|
if (ele.HasAttribute("encryptBytes"))
|
||||||
|
{
|
||||||
|
rule.encryptArray = ConfigUtil.ParseBool(ele.GetAttribute("encryptArray"));
|
||||||
|
}
|
||||||
|
if (ele.HasAttribute("encryptString"))
|
||||||
|
{
|
||||||
|
rule.encryptString = ConfigUtil.ParseBool(ele.GetAttribute("encryptString"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ele.HasAttribute("encryptConstInLoop"))
|
||||||
|
{
|
||||||
|
rule.encryptConstInLoop = ConfigUtil.ParseBool(ele.GetAttribute("encryptConstInLoop"));
|
||||||
|
}
|
||||||
|
if (ele.HasAttribute("encryptStringInLoop"))
|
||||||
|
{
|
||||||
|
rule.encryptStringInLoop = ConfigUtil.ParseBool(ele.GetAttribute("encryptStringInLoop"));
|
||||||
|
}
|
||||||
|
if (ele.HasAttribute("cacheConstInLoop"))
|
||||||
|
{
|
||||||
|
rule.cacheConstInLoop = ConfigUtil.ParseBool(ele.GetAttribute("cacheConstInLoop"));
|
||||||
|
}
|
||||||
|
if (ele.HasAttribute("cacheConstNotInLoop"))
|
||||||
|
{
|
||||||
|
rule.cacheConstNotInLoop = ConfigUtil.ParseBool(ele.GetAttribute("cacheConstNotInLoop"));
|
||||||
|
}
|
||||||
|
if (ele.HasAttribute("cacheStringInLoop"))
|
||||||
|
{
|
||||||
|
rule.cacheStringInLoop = ConfigUtil.ParseBool(ele.GetAttribute("cacheStringInLoop"));
|
||||||
|
}
|
||||||
|
if (ele.HasAttribute("cacheStringNotInLoop"))
|
||||||
|
{
|
||||||
|
rule.cacheStringNotInLoop = ConfigUtil.ParseBool(ele.GetAttribute("cacheStringNotInLoop"));
|
||||||
|
}
|
||||||
|
return rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ParseWhitelist(string configFile, XmlElement childEle)
|
||||||
|
{
|
||||||
|
string type = childEle.GetAttribute("type");
|
||||||
|
if (string.IsNullOrEmpty(type))
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file, whitelist type is empty");
|
||||||
|
}
|
||||||
|
string value = childEle.InnerText;
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case "int":
|
||||||
|
{
|
||||||
|
notEncryptInts.AddRange(value.Split(',').Select(s => int.Parse(s.Trim())));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "long":
|
||||||
|
{
|
||||||
|
notEncryptLongs.AddRange(value.Split(',').Select(s => long.Parse(s.Trim())));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "string":
|
||||||
|
{
|
||||||
|
notEncryptStrings.AddRange(value.Split(',').Select(s => s.Trim()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "int-range":
|
||||||
|
{
|
||||||
|
var parts = value.Split(',');
|
||||||
|
if (parts.Length != 2)
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file, int-range {value} is invalid");
|
||||||
|
}
|
||||||
|
notEncryptIntRanges.Add(new NumberRange<int>(ConfigUtil.ParseNullableInt(parts[0]), ConfigUtil.ParseNullableInt(parts[1])));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "long-range":
|
||||||
|
{
|
||||||
|
var parts = value.Split(',');
|
||||||
|
if (parts.Length != 2)
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file, long-range {value} is invalid");
|
||||||
|
}
|
||||||
|
notEncryptLongRanges.Add(new NumberRange<long>(ConfigUtil.ParseNullableLong(parts[0]), ConfigUtil.ParseNullableLong(parts[1])));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "float-range":
|
||||||
|
{
|
||||||
|
var parts = value.Split(',');
|
||||||
|
if (parts.Length != 2)
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file, float-range {value} is invalid");
|
||||||
|
}
|
||||||
|
notEncryptFloatRanges.Add(new NumberRange<float>(ConfigUtil.ParseNullableFloat(parts[0]), ConfigUtil.ParseNullableFloat(parts[1])));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "double-range":
|
||||||
|
{
|
||||||
|
var parts = value.Split(',');
|
||||||
|
if (parts.Length != 2)
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file, double-range {value} is invalid");
|
||||||
|
}
|
||||||
|
notEncryptDoubleRanges.Add(new NumberRange<double>(ConfigUtil.ParseNullableDouble(parts[0]), ConfigUtil.ParseNullableDouble(parts[1])));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "string-length-range":
|
||||||
|
{
|
||||||
|
var parts = value.Split(',');
|
||||||
|
if (parts.Length != 2)
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file, string-length-range {value} is invalid");
|
||||||
|
}
|
||||||
|
notEncryptStringLengthRanges.Add(new NumberRange<int>(ConfigUtil.ParseNullableInt(parts[0]), ConfigUtil.ParseNullableInt(parts[1])));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "array-length-range":
|
||||||
|
{
|
||||||
|
var parts = value.Split(',');
|
||||||
|
if (parts.Length != 2)
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file, array-length-range {value} is invalid");
|
||||||
|
}
|
||||||
|
notEncryptArrayLengthRanges.Add(new NumberRange<int>(ConfigUtil.ParseNullableInt(parts[0]), ConfigUtil.ParseNullableInt(parts[1])));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: throw new Exception($"Invalid xml file, unknown whitelist type {type} in {childEle.Name} node");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ObfuscationRule GetMethodObfuscationRule(MethodDef method)
|
||||||
|
{
|
||||||
|
if (!_methodRuleCache.TryGetValue(method, out var rule))
|
||||||
|
{
|
||||||
|
rule = _xmlParser.GetMethodRule(method, _global);
|
||||||
|
_methodRuleCache[method] = rule;
|
||||||
|
}
|
||||||
|
return rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedObfuscateMethod(MethodDef method)
|
||||||
|
{
|
||||||
|
ObfuscationRule rule = GetMethodObfuscationRule(method);
|
||||||
|
return rule.disableEncrypt != true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ConstCachePolicy GetMethodConstCachePolicy(MethodDef method)
|
||||||
|
{
|
||||||
|
ObfuscationRule rule = GetMethodObfuscationRule(method);
|
||||||
|
return new ConstCachePolicy
|
||||||
|
{
|
||||||
|
cacheConstInLoop = rule.cacheConstInLoop.Value,
|
||||||
|
cacheConstNotInLoop = rule.cacheConstNotInLoop.Value,
|
||||||
|
cacheStringInLoop = rule.cacheStringInLoop.Value,
|
||||||
|
cacheStringNotInLoop = rule.cacheStringNotInLoop.Value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedObfuscateInt(MethodDef method, bool currentInLoop, int value)
|
||||||
|
{
|
||||||
|
ObfuscationRule rule = GetMethodObfuscationRule(method);
|
||||||
|
if (rule.encryptInt == false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (currentInLoop && rule.encryptConstInLoop == false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (notEncryptInts.Contains(value))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
foreach (var range in notEncryptIntRanges)
|
||||||
|
{
|
||||||
|
if (range.min != null && value < range.min)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (range.max != null && value > range.max)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedObfuscateLong(MethodDef method, bool currentInLoop, long value)
|
||||||
|
{
|
||||||
|
ObfuscationRule rule = GetMethodObfuscationRule(method);
|
||||||
|
if (rule.encryptLong == false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (currentInLoop && rule.encryptConstInLoop == false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (notEncryptLongs.Contains(value))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
foreach (var range in notEncryptLongRanges)
|
||||||
|
{
|
||||||
|
if (range.min != null && value < range.min)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (range.max != null && value > range.max)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedObfuscateFloat(MethodDef method, bool currentInLoop, float value)
|
||||||
|
{
|
||||||
|
ObfuscationRule rule = GetMethodObfuscationRule(method);
|
||||||
|
if (rule.encryptFloat == false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (currentInLoop && rule.encryptConstInLoop == false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
foreach (var range in notEncryptFloatRanges)
|
||||||
|
{
|
||||||
|
if (range.min != null && value < range.min)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (range.max != null && value > range.max)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedObfuscateDouble(MethodDef method, bool currentInLoop, double value)
|
||||||
|
{
|
||||||
|
ObfuscationRule rule = GetMethodObfuscationRule(method);
|
||||||
|
if (rule.encryptDouble == false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (currentInLoop && rule.encryptConstInLoop == false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
foreach (var range in notEncryptDoubleRanges)
|
||||||
|
{
|
||||||
|
if (range.min != null && value < range.min)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (range.max != null && value > range.max)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedObfuscateString(MethodDef method, bool currentInLoop, string value)
|
||||||
|
{
|
||||||
|
ObfuscationRule rule = GetMethodObfuscationRule(method);
|
||||||
|
if (rule.encryptString == false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (currentInLoop && rule.encryptConstInLoop == false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (notEncryptStrings.Contains(value))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
foreach (var range in notEncryptStringLengthRanges)
|
||||||
|
{
|
||||||
|
if (range.min != null && value.Length < range.min)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (range.max != null && value.Length > range.max)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedObfuscateArray(MethodDef method, bool currentInLoop, byte[] array)
|
||||||
|
{
|
||||||
|
ObfuscationRule rule = GetMethodObfuscationRule(method);
|
||||||
|
if (rule.encryptArray == false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (currentInLoop && rule.encryptConstInLoop == false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
foreach (var range in notEncryptArrayLengthRanges)
|
||||||
|
{
|
||||||
|
if (range.min != null && array.Length < range.min)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (range.max != null && array.Length > range.max)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,166 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using dnlib.DotNet.Emit;
|
||||||
|
using Obfuz.Emit;
|
||||||
|
using Obfuz.Settings;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine.Assertions;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.ConstEncrypt
|
||||||
|
{
|
||||||
|
|
||||||
|
public class ConstEncryptPass : BasicBlockObfuscationPassBase
|
||||||
|
{
|
||||||
|
private readonly List<string> _configFiles;
|
||||||
|
private readonly int _encryptionLevel;
|
||||||
|
private IEncryptPolicy _dataObfuscatorPolicy;
|
||||||
|
private IConstEncryptor _dataObfuscator;
|
||||||
|
public override ObfuscationPassType Type => ObfuscationPassType.ConstEncrypt;
|
||||||
|
|
||||||
|
public ConstEncryptPass(ConstEncryptionSettings settings)
|
||||||
|
{
|
||||||
|
_configFiles = settings.ruleFiles.ToList();
|
||||||
|
_encryptionLevel = settings.encryptionLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Start()
|
||||||
|
{
|
||||||
|
var ctx = ObfuscationPassContext.Current;
|
||||||
|
_dataObfuscatorPolicy = new ConfigurableEncryptPolicy(ctx.assembliesToObfuscate, _configFiles);
|
||||||
|
_dataObfuscator = new DefaultConstEncryptor(ctx.encryptionScopeProvider, ctx.rvaDataAllocator, ctx.constFieldAllocator, ctx.moduleEntityManager, _encryptionLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Stop()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool NeedObfuscateMethod(MethodDef method)
|
||||||
|
{
|
||||||
|
return _dataObfuscatorPolicy.NeedObfuscateMethod(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool TryObfuscateInstruction(MethodDef method, Instruction inst, BasicBlock block, int instructionIndex, IList<Instruction> globalInstructions,
|
||||||
|
List<Instruction> outputInstructions, List<Instruction> totalFinalInstructions)
|
||||||
|
{
|
||||||
|
bool currentInLoop = block.inLoop;
|
||||||
|
ConstCachePolicy constCachePolicy = _dataObfuscatorPolicy.GetMethodConstCachePolicy(method);
|
||||||
|
switch (inst.OpCode.OperandType)
|
||||||
|
{
|
||||||
|
case OperandType.InlineI:
|
||||||
|
case OperandType.InlineI8:
|
||||||
|
case OperandType.ShortInlineI:
|
||||||
|
case OperandType.ShortInlineR:
|
||||||
|
case OperandType.InlineR:
|
||||||
|
{
|
||||||
|
bool needCache = currentInLoop ? constCachePolicy.cacheConstInLoop : constCachePolicy.cacheConstNotInLoop;
|
||||||
|
object operand = inst.Operand;
|
||||||
|
if (operand is int)
|
||||||
|
{
|
||||||
|
int value = (int)operand;
|
||||||
|
if (_dataObfuscatorPolicy.NeedObfuscateInt(method, currentInLoop, value))
|
||||||
|
{
|
||||||
|
_dataObfuscator.ObfuscateInt(method, needCache, value, outputInstructions);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (operand is sbyte)
|
||||||
|
{
|
||||||
|
int value = (sbyte)operand;
|
||||||
|
if (_dataObfuscatorPolicy.NeedObfuscateInt(method, currentInLoop, value))
|
||||||
|
{
|
||||||
|
_dataObfuscator.ObfuscateInt(method, needCache, value, outputInstructions);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (operand is byte)
|
||||||
|
{
|
||||||
|
int value = (byte)operand;
|
||||||
|
if (_dataObfuscatorPolicy.NeedObfuscateInt(method, currentInLoop, value))
|
||||||
|
{
|
||||||
|
_dataObfuscator.ObfuscateInt(method, needCache, value, outputInstructions);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (operand is long)
|
||||||
|
{
|
||||||
|
long value = (long)operand;
|
||||||
|
if (_dataObfuscatorPolicy.NeedObfuscateLong(method, currentInLoop, value))
|
||||||
|
{
|
||||||
|
_dataObfuscator.ObfuscateLong(method, needCache, value, outputInstructions);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (operand is float)
|
||||||
|
{
|
||||||
|
float value = (float)operand;
|
||||||
|
if (_dataObfuscatorPolicy.NeedObfuscateFloat(method, currentInLoop, value))
|
||||||
|
{
|
||||||
|
_dataObfuscator.ObfuscateFloat(method, needCache, value, outputInstructions);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (operand is double)
|
||||||
|
{
|
||||||
|
double value = (double)operand;
|
||||||
|
if (_dataObfuscatorPolicy.NeedObfuscateDouble(method, currentInLoop, value))
|
||||||
|
{
|
||||||
|
_dataObfuscator.ObfuscateDouble(method, needCache, value, outputInstructions);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case OperandType.InlineString:
|
||||||
|
{
|
||||||
|
//RuntimeHelpers.InitializeArray
|
||||||
|
string value = (string)inst.Operand;
|
||||||
|
if (_dataObfuscatorPolicy.NeedObfuscateString(method, currentInLoop, value))
|
||||||
|
{
|
||||||
|
bool needCache = currentInLoop ? constCachePolicy.cacheStringInLoop : constCachePolicy.cacheStringNotInLoop;
|
||||||
|
_dataObfuscator.ObfuscateString(method, needCache, value, outputInstructions);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case OperandType.InlineMethod:
|
||||||
|
{
|
||||||
|
//if (((IMethod)inst.Operand).FullName == "System.Void System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(System.Array,System.RuntimeFieldHandle)")
|
||||||
|
//{
|
||||||
|
// Instruction prevInst = globalInstructions[instructionIndex - 1];
|
||||||
|
// if (prevInst.OpCode.Code == Code.Ldtoken)
|
||||||
|
// {
|
||||||
|
// IField rvaField = (IField)prevInst.Operand;
|
||||||
|
// FieldDef ravFieldDef = rvaField.ResolveFieldDefThrow();
|
||||||
|
// byte[] data = ravFieldDef.InitialValue;
|
||||||
|
// if (data != null && _dataObfuscatorPolicy.NeedObfuscateArray(method, currentInLoop, data))
|
||||||
|
// {
|
||||||
|
// if (_encryptedRvaFields.Add(ravFieldDef))
|
||||||
|
// {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // remove prev ldtoken instruction
|
||||||
|
// Assert.AreEqual(Code.Ldtoken, totalFinalInstructions.Last().OpCode.Code);
|
||||||
|
// //totalFinalInstructions.RemoveAt(totalFinalInstructions.Count - 1);
|
||||||
|
// // dup arr argument for decryption operation
|
||||||
|
// totalFinalInstructions.Insert(totalFinalInstructions.Count - 1, Instruction.Create(OpCodes.Dup));
|
||||||
|
// totalFinalInstructions.Add(inst.Clone());
|
||||||
|
// //bool needCache = currentInLoop ? constCachePolicy.cacheStringInLoop : constCachePolicy.cacheStringNotInLoop;
|
||||||
|
// bool needCache = false;
|
||||||
|
// _dataObfuscator.ObfuscateBytes(method, needCache, data, outputInstructions);
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,204 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using dnlib.DotNet.Emit;
|
||||||
|
using Obfuz.Emit;
|
||||||
|
using Obfuz.Data;
|
||||||
|
using Obfuz.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.ConstEncrypt
|
||||||
|
{
|
||||||
|
public class DefaultConstEncryptor : IConstEncryptor
|
||||||
|
{
|
||||||
|
private readonly EncryptionScopeProvider _encryptionScopeProvider;
|
||||||
|
private readonly RvaDataAllocator _rvaDataAllocator;
|
||||||
|
private readonly ConstFieldAllocator _constFieldAllocator;
|
||||||
|
private readonly GroupByModuleEntityManager _moduleEntityManager;
|
||||||
|
private readonly int _encryptionLevel;
|
||||||
|
|
||||||
|
public DefaultConstEncryptor(EncryptionScopeProvider encryptionScopeProvider, RvaDataAllocator rvaDataAllocator, ConstFieldAllocator constFieldAllocator, GroupByModuleEntityManager moduleEntityManager, int encryptionLevel)
|
||||||
|
{
|
||||||
|
_encryptionScopeProvider = encryptionScopeProvider;
|
||||||
|
_rvaDataAllocator = rvaDataAllocator;
|
||||||
|
_constFieldAllocator = constFieldAllocator;
|
||||||
|
_moduleEntityManager = moduleEntityManager;
|
||||||
|
_encryptionLevel = encryptionLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IRandom CreateRandomForValue(EncryptionScopeInfo encryptionScope, int value)
|
||||||
|
{
|
||||||
|
return encryptionScope.localRandomCreator(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GenerateEncryptionOperations(EncryptionScopeInfo encryptionScope, IRandom random)
|
||||||
|
{
|
||||||
|
return EncryptionUtil.GenerateEncryptionOpCodes(random, encryptionScope.encryptor, _encryptionLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GenerateSalt(IRandom random)
|
||||||
|
{
|
||||||
|
return random.NextInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
private DefaultMetadataImporter GetModuleMetadataImporter(MethodDef method)
|
||||||
|
{
|
||||||
|
return _moduleEntityManager.GetDefaultModuleMetadataImporter(method.Module, _encryptionScopeProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ObfuscateInt(MethodDef method, bool needCacheValue, int value, List<Instruction> obfuscatedInstructions)
|
||||||
|
{
|
||||||
|
if (needCacheValue)
|
||||||
|
{
|
||||||
|
FieldDef cacheField = _constFieldAllocator.Allocate(method.Module, value);
|
||||||
|
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EncryptionScopeInfo encryptionScope = _encryptionScopeProvider.GetScope(method.Module);
|
||||||
|
IRandom random = CreateRandomForValue(encryptionScope, value.GetHashCode());
|
||||||
|
int ops = GenerateEncryptionOperations(encryptionScope, random);
|
||||||
|
int salt = GenerateSalt(random);
|
||||||
|
int encryptedValue = encryptionScope.encryptor.Encrypt(value, ops, salt);
|
||||||
|
RvaData rvaData = _rvaDataAllocator.Allocate(method.Module, encryptedValue);
|
||||||
|
|
||||||
|
DefaultMetadataImporter importer = GetModuleMetadataImporter(method);
|
||||||
|
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
|
||||||
|
obfuscatedInstructions.Add(Instruction.CreateLdcI4(rvaData.offset));
|
||||||
|
obfuscatedInstructions.Add(Instruction.CreateLdcI4(ops));
|
||||||
|
obfuscatedInstructions.Add(Instruction.CreateLdcI4(salt));
|
||||||
|
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaInt));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ObfuscateLong(MethodDef method, bool needCacheValue, long value, List<Instruction> obfuscatedInstructions)
|
||||||
|
{
|
||||||
|
if (needCacheValue)
|
||||||
|
{
|
||||||
|
FieldDef cacheField = _constFieldAllocator.Allocate(method.Module, value);
|
||||||
|
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EncryptionScopeInfo encryptionScope = _encryptionScopeProvider.GetScope(method.Module);
|
||||||
|
IRandom random = CreateRandomForValue(encryptionScope, value.GetHashCode());
|
||||||
|
int ops = GenerateEncryptionOperations(encryptionScope, random);
|
||||||
|
int salt = GenerateSalt(random);
|
||||||
|
long encryptedValue = encryptionScope.encryptor.Encrypt(value, ops, salt);
|
||||||
|
RvaData rvaData = _rvaDataAllocator.Allocate(method.Module, encryptedValue);
|
||||||
|
|
||||||
|
DefaultMetadataImporter importer = GetModuleMetadataImporter(method);
|
||||||
|
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
|
||||||
|
obfuscatedInstructions.Add(Instruction.CreateLdcI4(rvaData.offset));
|
||||||
|
obfuscatedInstructions.Add(Instruction.CreateLdcI4(ops));
|
||||||
|
obfuscatedInstructions.Add(Instruction.CreateLdcI4(salt));
|
||||||
|
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaLong));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ObfuscateFloat(MethodDef method, bool needCacheValue, float value, List<Instruction> obfuscatedInstructions)
|
||||||
|
{
|
||||||
|
if (needCacheValue)
|
||||||
|
{
|
||||||
|
FieldDef cacheField = _constFieldAllocator.Allocate(method.Module, value);
|
||||||
|
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EncryptionScopeInfo encryptionScope = _encryptionScopeProvider.GetScope(method.Module);
|
||||||
|
IRandom random = CreateRandomForValue(encryptionScope, value.GetHashCode());
|
||||||
|
int ops = GenerateEncryptionOperations(encryptionScope, random);
|
||||||
|
int salt = GenerateSalt(random);
|
||||||
|
float encryptedValue = encryptionScope.encryptor.Encrypt(value, ops, salt);
|
||||||
|
RvaData rvaData = _rvaDataAllocator.Allocate(method.Module, encryptedValue);
|
||||||
|
|
||||||
|
DefaultMetadataImporter importer = GetModuleMetadataImporter(method);
|
||||||
|
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
|
||||||
|
obfuscatedInstructions.Add(Instruction.CreateLdcI4(rvaData.offset));
|
||||||
|
obfuscatedInstructions.Add(Instruction.CreateLdcI4(ops));
|
||||||
|
obfuscatedInstructions.Add(Instruction.CreateLdcI4(salt));
|
||||||
|
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaFloat));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ObfuscateDouble(MethodDef method, bool needCacheValue, double value, List<Instruction> obfuscatedInstructions)
|
||||||
|
{
|
||||||
|
if (needCacheValue)
|
||||||
|
{
|
||||||
|
FieldDef cacheField = _constFieldAllocator.Allocate(method.Module, value);
|
||||||
|
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EncryptionScopeInfo encryptionScope = _encryptionScopeProvider.GetScope(method.Module);
|
||||||
|
IRandom random = CreateRandomForValue(encryptionScope, value.GetHashCode());
|
||||||
|
int ops = GenerateEncryptionOperations(encryptionScope, random);
|
||||||
|
int salt = GenerateSalt(random);
|
||||||
|
double encryptedValue = encryptionScope.encryptor.Encrypt(value, ops, salt);
|
||||||
|
RvaData rvaData = _rvaDataAllocator.Allocate(method.Module, encryptedValue);
|
||||||
|
|
||||||
|
DefaultMetadataImporter importer = GetModuleMetadataImporter(method);
|
||||||
|
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
|
||||||
|
obfuscatedInstructions.Add(Instruction.CreateLdcI4(rvaData.offset));
|
||||||
|
obfuscatedInstructions.Add(Instruction.CreateLdcI4(ops));
|
||||||
|
obfuscatedInstructions.Add(Instruction.CreateLdcI4(salt));
|
||||||
|
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaDouble));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ObfuscateBytes(MethodDef method, bool needCacheValue, byte[] value, List<Instruction> obfuscatedInstructions)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("ObfuscateBytes is not supported yet.");
|
||||||
|
//if (needCacheValue)
|
||||||
|
//{
|
||||||
|
// FieldDef cacheField = _constFieldAllocator.Allocate(method.Module, value);
|
||||||
|
// obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField));
|
||||||
|
// return;
|
||||||
|
//}
|
||||||
|
|
||||||
|
//int ops = GenerateEncryptionOperations();
|
||||||
|
//int salt = GenerateSalt();
|
||||||
|
//byte[] encryptedValue = _encryptor.Encrypt(value, 0, value.Length, ops, salt);
|
||||||
|
//Assert.IsTrue(encryptedValue.Length % 4 == 0);
|
||||||
|
//RvaData rvaData = _rvaDataAllocator.Allocate(method.Module, encryptedValue);
|
||||||
|
|
||||||
|
//DefaultMetadataImporter importer = GetModuleMetadataImporter(method);
|
||||||
|
//obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
|
||||||
|
//obfuscatedInstructions.Add(Instruction.CreateLdcI4(rvaData.offset));
|
||||||
|
//// should use value.Length, can't use rvaData.size, because rvaData.size is align to 4, it's not the actual length.
|
||||||
|
//obfuscatedInstructions.Add(Instruction.CreateLdcI4(value.Length));
|
||||||
|
//obfuscatedInstructions.Add(Instruction.CreateLdcI4(ops));
|
||||||
|
//obfuscatedInstructions.Add(Instruction.CreateLdcI4(salt));
|
||||||
|
//obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaBytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ObfuscateString(MethodDef method, bool needCacheValue, string value, List<Instruction> obfuscatedInstructions)
|
||||||
|
{
|
||||||
|
if (needCacheValue)
|
||||||
|
{
|
||||||
|
FieldDef cacheField = _constFieldAllocator.Allocate(method.Module, value);
|
||||||
|
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EncryptionScopeInfo encryptionScope = _encryptionScopeProvider.GetScope(method.Module);
|
||||||
|
IRandom random = CreateRandomForValue(encryptionScope, value.GetHashCode());
|
||||||
|
int ops = GenerateEncryptionOperations(encryptionScope, random);
|
||||||
|
int salt = GenerateSalt(random);
|
||||||
|
int stringByteLength = Encoding.UTF8.GetByteCount(value);
|
||||||
|
byte[] encryptedValue = encryptionScope.encryptor.Encrypt(value, ops, salt);
|
||||||
|
Assert.IsTrue(encryptedValue.Length % 4 == 0);
|
||||||
|
RvaData rvaData = _rvaDataAllocator.Allocate(method.Module, encryptedValue);
|
||||||
|
|
||||||
|
DefaultMetadataImporter importer = GetModuleMetadataImporter(method);
|
||||||
|
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
|
||||||
|
obfuscatedInstructions.Add(Instruction.CreateLdcI4(rvaData.offset));
|
||||||
|
// should use stringByteLength, can't use rvaData.size, because rvaData.size is align to 4, it's not the actual length.
|
||||||
|
obfuscatedInstructions.Add(Instruction.CreateLdcI4(stringByteLength));
|
||||||
|
obfuscatedInstructions.Add(Instruction.CreateLdcI4(ops));
|
||||||
|
obfuscatedInstructions.Add(Instruction.CreateLdcI4(salt));
|
||||||
|
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaString));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Done()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using dnlib.DotNet.Emit;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.ConstEncrypt
|
||||||
|
{
|
||||||
|
public interface IConstEncryptor
|
||||||
|
{
|
||||||
|
void ObfuscateInt(MethodDef method, bool needCacheValue, int value, List<Instruction> obfuscatedInstructions);
|
||||||
|
|
||||||
|
void ObfuscateLong(MethodDef method, bool needCacheValue, long value, List<Instruction> obfuscatedInstructions);
|
||||||
|
|
||||||
|
void ObfuscateFloat(MethodDef method, bool needCacheValue, float value, List<Instruction> obfuscatedInstructions);
|
||||||
|
|
||||||
|
void ObfuscateDouble(MethodDef method, bool needCacheValue, double value, List<Instruction> obfuscatedInstructions);
|
||||||
|
|
||||||
|
void ObfuscateString(MethodDef method, bool needCacheValue, string value, List<Instruction> obfuscatedInstructions);
|
||||||
|
|
||||||
|
void ObfuscateBytes(MethodDef method, bool needCacheValue, byte[] value, List<Instruction> obfuscatedInstructions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class ConstEncryptorBase : IConstEncryptor
|
||||||
|
{
|
||||||
|
public abstract void ObfuscateBytes(MethodDef method, bool needCacheValue, byte[] value, List<Instruction> obfuscatedInstructions);
|
||||||
|
public abstract void ObfuscateDouble(MethodDef method, bool needCacheValue, double value, List<Instruction> obfuscatedInstructions);
|
||||||
|
public abstract void ObfuscateFloat(MethodDef method, bool needCacheValue, float value, List<Instruction> obfuscatedInstructions);
|
||||||
|
public abstract void ObfuscateInt(MethodDef method, bool needCacheValue, int value, List<Instruction> obfuscatedInstructions);
|
||||||
|
public abstract void ObfuscateLong(MethodDef method, bool needCacheValue, long value, List<Instruction> obfuscatedInstructions);
|
||||||
|
public abstract void ObfuscateString(MethodDef method, bool needCacheValue, string value, List<Instruction> obfuscatedInstructions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.ConstEncrypt
|
||||||
|
{
|
||||||
|
public struct ConstCachePolicy
|
||||||
|
{
|
||||||
|
public bool cacheConstInLoop;
|
||||||
|
public bool cacheConstNotInLoop;
|
||||||
|
public bool cacheStringInLoop;
|
||||||
|
public bool cacheStringNotInLoop;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IEncryptPolicy
|
||||||
|
{
|
||||||
|
bool NeedObfuscateMethod(MethodDef method);
|
||||||
|
|
||||||
|
ConstCachePolicy GetMethodConstCachePolicy(MethodDef method);
|
||||||
|
|
||||||
|
bool NeedObfuscateInt(MethodDef method, bool currentInLoop, int value);
|
||||||
|
|
||||||
|
bool NeedObfuscateLong(MethodDef method, bool currentInLoop, long value);
|
||||||
|
|
||||||
|
bool NeedObfuscateFloat(MethodDef method, bool currentInLoop, float value);
|
||||||
|
|
||||||
|
bool NeedObfuscateDouble(MethodDef method, bool currentInLoop, double value);
|
||||||
|
|
||||||
|
bool NeedObfuscateString(MethodDef method, bool currentInLoop, string value);
|
||||||
|
|
||||||
|
bool NeedObfuscateArray(MethodDef method, bool currentInLoop, byte[] array);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class EncryptPolicyBase : IEncryptPolicy
|
||||||
|
{
|
||||||
|
public abstract bool NeedObfuscateMethod(MethodDef method);
|
||||||
|
public abstract ConstCachePolicy GetMethodConstCachePolicy(MethodDef method);
|
||||||
|
public abstract bool NeedObfuscateDouble(MethodDef method, bool currentInLoop, double value);
|
||||||
|
public abstract bool NeedObfuscateFloat(MethodDef method, bool currentInLoop, float value);
|
||||||
|
public abstract bool NeedObfuscateInt(MethodDef method, bool currentInLoop, int value);
|
||||||
|
public abstract bool NeedObfuscateLong(MethodDef method, bool currentInLoop, long value);
|
||||||
|
public abstract bool NeedObfuscateString(MethodDef method, bool currentInLoop, string value);
|
||||||
|
public abstract bool NeedObfuscateArray(MethodDef method, bool currentInLoop, byte[] array);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using dnlib.DotNet.Emit;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.ExprObfus
|
||||||
|
{
|
||||||
|
public class ExprObfusPass : InstructionObfuscationPassBase
|
||||||
|
{
|
||||||
|
public override ObfuscationPassType Type => ObfuscationPassType.ExprObfus;
|
||||||
|
|
||||||
|
public override void Start()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Stop()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool NeedObfuscateMethod(MethodDef method)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool TryObfuscateInstruction(MethodDef callingMethod, Instruction inst, IList<Instruction> instructions, int instructionIndex, List<Instruction> outputInstructions, List<Instruction> totalFinalInstructions)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using Obfuz.Conf;
|
||||||
|
using Obfuz.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Xml;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.FieldEncrypt
|
||||||
|
{
|
||||||
|
public class ConfigurableEncryptPolicy : EncryptPolicyBase
|
||||||
|
{
|
||||||
|
class ObfuscationRule
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly XmlFieldRuleParser<ObfuscationRule> _configParser;
|
||||||
|
|
||||||
|
public ConfigurableEncryptPolicy(List<string> toObfuscatedAssemblyNames, List<string> configFiles)
|
||||||
|
{
|
||||||
|
_configParser = new XmlFieldRuleParser<ObfuscationRule>(toObfuscatedAssemblyNames, ParseRule, null);
|
||||||
|
_configParser.LoadConfigs(configFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ObfuscationRule ParseRule(string configFile, XmlElement ele)
|
||||||
|
{
|
||||||
|
return new ObfuscationRule();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedEncrypt(FieldDef field)
|
||||||
|
{
|
||||||
|
var rule = _configParser.GetFieldRule(field);
|
||||||
|
return rule != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,182 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using dnlib.DotNet.Emit;
|
||||||
|
using Obfuz.Emit;
|
||||||
|
using Obfuz.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using UnityEngine.Assertions;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.FieldEncrypt
|
||||||
|
{
|
||||||
|
public class DefaultFieldEncryptor : FieldEncryptorBase
|
||||||
|
{
|
||||||
|
private readonly EncryptionScopeProvider _encryptionScopeProvider;
|
||||||
|
private readonly GroupByModuleEntityManager _moduleEntityManager;
|
||||||
|
private readonly int _encryptionLevel;
|
||||||
|
|
||||||
|
public DefaultFieldEncryptor(EncryptionScopeProvider encryptionScopeProvider, GroupByModuleEntityManager moduleEntityManager, int encryptionLevel)
|
||||||
|
{
|
||||||
|
_encryptionScopeProvider = encryptionScopeProvider;
|
||||||
|
_moduleEntityManager = moduleEntityManager;
|
||||||
|
_encryptionLevel = encryptionLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DefaultMetadataImporter GetMetadataImporter(MethodDef method)
|
||||||
|
{
|
||||||
|
return _moduleEntityManager.GetDefaultModuleMetadataImporter(method.Module, _encryptionScopeProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
class FieldEncryptInfo
|
||||||
|
{
|
||||||
|
public int encryptOps;
|
||||||
|
public int salt;
|
||||||
|
public ElementType fieldType;
|
||||||
|
public long xorValueForZero;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Dictionary<FieldDef, FieldEncryptInfo> _fieldEncryptInfoCache = new Dictionary<FieldDef, FieldEncryptInfo>();
|
||||||
|
|
||||||
|
|
||||||
|
private long CalcXorValueForZero(IEncryptor encryptor, ElementType type, int encryptOps, int salt)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case ElementType.I4:
|
||||||
|
case ElementType.U4:
|
||||||
|
case ElementType.R4:
|
||||||
|
return encryptor.Encrypt(0, encryptOps, salt);
|
||||||
|
case ElementType.I8:
|
||||||
|
case ElementType.U8:
|
||||||
|
case ElementType.R8:
|
||||||
|
return encryptor.Encrypt(0L, encryptOps, salt);
|
||||||
|
default:
|
||||||
|
throw new NotSupportedException($"Unsupported field type: {type} for encryption");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private IRandom CreateRandomForField(RandomCreator randomCreator, FieldDef field)
|
||||||
|
{
|
||||||
|
return randomCreator(FieldEqualityComparer.CompareDeclaringTypes.GetHashCode(field));
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GenerateEncryptionOperations(IRandom random, IEncryptor encryptor)
|
||||||
|
{
|
||||||
|
return EncryptionUtil.GenerateEncryptionOpCodes(random, encryptor, _encryptionLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GenerateSalt(IRandom random)
|
||||||
|
{
|
||||||
|
return random.NextInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
private FieldEncryptInfo GetFieldEncryptInfo(FieldDef field)
|
||||||
|
{
|
||||||
|
if (_fieldEncryptInfoCache.TryGetValue(field, out var info))
|
||||||
|
{
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
EncryptionScopeInfo encryptionScope = _encryptionScopeProvider.GetScope(field.Module);
|
||||||
|
|
||||||
|
IRandom random = CreateRandomForField(encryptionScope.localRandomCreator, field);
|
||||||
|
IEncryptor encryptor = encryptionScope.encryptor;
|
||||||
|
int encryptOps = GenerateEncryptionOperations(random, encryptor);
|
||||||
|
int salt = GenerateSalt(random);
|
||||||
|
ElementType fieldType = field.FieldSig.Type.RemovePinnedAndModifiers().ElementType;
|
||||||
|
long xorValueForZero = CalcXorValueForZero(encryptor, fieldType, encryptOps, salt);
|
||||||
|
|
||||||
|
info = new FieldEncryptInfo
|
||||||
|
{
|
||||||
|
encryptOps = encryptOps,
|
||||||
|
salt = salt,
|
||||||
|
fieldType = fieldType,
|
||||||
|
xorValueForZero = xorValueForZero,
|
||||||
|
};
|
||||||
|
_fieldEncryptInfoCache[field] = info;
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Encrypt(MethodDef method, FieldDef field, List<Instruction> outputInstructions, Instruction currentInstruction)
|
||||||
|
{
|
||||||
|
DefaultMetadataImporter importer = GetMetadataImporter(method);
|
||||||
|
EncryptionServiceMetadataImporter encryptionServiceMetadataImporter = importer.GetEncryptionServiceMetadataImporterOfModule(field.Module);
|
||||||
|
FieldEncryptInfo fei = GetFieldEncryptInfo(field);
|
||||||
|
if (fei.fieldType == ElementType.I4 || fei.fieldType == ElementType.U4 || fei.fieldType == ElementType.R4)
|
||||||
|
{
|
||||||
|
// value has been put on stack
|
||||||
|
|
||||||
|
// encrypt
|
||||||
|
outputInstructions.Add(Instruction.CreateLdcI4(fei.encryptOps));
|
||||||
|
outputInstructions.Add(Instruction.CreateLdcI4(fei.salt));
|
||||||
|
outputInstructions.Add(Instruction.Create(OpCodes.Call, encryptionServiceMetadataImporter.EncryptInt));
|
||||||
|
// xor
|
||||||
|
outputInstructions.Add(Instruction.CreateLdcI4((int)fei.xorValueForZero));
|
||||||
|
outputInstructions.Add(Instruction.Create(OpCodes.Xor));
|
||||||
|
}
|
||||||
|
else if (fei.fieldType == ElementType.I8 || fei.fieldType == ElementType.U8 || fei.fieldType == ElementType.R8)
|
||||||
|
{
|
||||||
|
// value has been put on stack
|
||||||
|
|
||||||
|
// encrypt
|
||||||
|
outputInstructions.Add(Instruction.CreateLdcI4(fei.encryptOps));
|
||||||
|
outputInstructions.Add(Instruction.CreateLdcI4(fei.salt));
|
||||||
|
outputInstructions.Add(Instruction.Create(OpCodes.Call, encryptionServiceMetadataImporter.EncryptLong));
|
||||||
|
// xor
|
||||||
|
outputInstructions.Add(Instruction.Create(OpCodes.Ldc_I8, fei.xorValueForZero));
|
||||||
|
outputInstructions.Add(Instruction.Create(OpCodes.Xor));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Assert.IsTrue(false, $"Unsupported field type: {fei.fieldType} for encryption");
|
||||||
|
}
|
||||||
|
|
||||||
|
outputInstructions.Add(currentInstruction.Clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Decrypt(MethodDef method, FieldDef field, List<Instruction> outputInstructions, Instruction currentInstruction)
|
||||||
|
{
|
||||||
|
outputInstructions.Add(currentInstruction.Clone());
|
||||||
|
DefaultMetadataImporter importer = GetMetadataImporter(method);
|
||||||
|
EncryptionServiceMetadataImporter encryptionServiceMetadataImporter = importer.GetEncryptionServiceMetadataImporterOfModule(field.Module);
|
||||||
|
FieldEncryptInfo fei = GetFieldEncryptInfo(field);
|
||||||
|
if (fei.fieldType == ElementType.I4 || fei.fieldType == ElementType.U4 || fei.fieldType == ElementType.R4)
|
||||||
|
{
|
||||||
|
// value has been put on stack
|
||||||
|
// xor
|
||||||
|
if (fei.fieldType == ElementType.R4)
|
||||||
|
{
|
||||||
|
outputInstructions.Add(Instruction.Create(OpCodes.Call, importer.CastFloatAsInt));
|
||||||
|
}
|
||||||
|
outputInstructions.Add(Instruction.CreateLdcI4((int)fei.xorValueForZero));
|
||||||
|
outputInstructions.Add(Instruction.Create(OpCodes.Xor));
|
||||||
|
|
||||||
|
// decrypt
|
||||||
|
outputInstructions.Add(Instruction.CreateLdcI4(fei.encryptOps));
|
||||||
|
outputInstructions.Add(Instruction.CreateLdcI4(fei.salt));
|
||||||
|
outputInstructions.Add(Instruction.Create(OpCodes.Call, encryptionServiceMetadataImporter.DecryptInt));
|
||||||
|
}
|
||||||
|
else if (fei.fieldType == ElementType.I8 || fei.fieldType == ElementType.U8 || fei.fieldType == ElementType.R8)
|
||||||
|
{
|
||||||
|
// value has been put on stack
|
||||||
|
// xor
|
||||||
|
if (fei.fieldType == ElementType.R8)
|
||||||
|
{
|
||||||
|
outputInstructions.Add(Instruction.Create(OpCodes.Call, importer.CastDoubleAsLong));
|
||||||
|
}
|
||||||
|
outputInstructions.Add(Instruction.Create(OpCodes.Ldc_I8, fei.xorValueForZero));
|
||||||
|
outputInstructions.Add(Instruction.Create(OpCodes.Xor));
|
||||||
|
|
||||||
|
// decrypt
|
||||||
|
outputInstructions.Add(Instruction.CreateLdcI4(fei.encryptOps));
|
||||||
|
outputInstructions.Add(Instruction.CreateLdcI4(fei.salt));
|
||||||
|
outputInstructions.Add(Instruction.Create(OpCodes.Call, encryptionServiceMetadataImporter.DecryptLong));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Assert.IsTrue(false, $"Unsupported field type: {fei.fieldType} for decryption");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,108 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using dnlib.DotNet.Emit;
|
||||||
|
using Obfuz;
|
||||||
|
using Obfuz.Settings;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.FieldEncrypt
|
||||||
|
{
|
||||||
|
|
||||||
|
public class FieldEncryptPass : InstructionObfuscationPassBase
|
||||||
|
{
|
||||||
|
private readonly List<string> _configFiles;
|
||||||
|
private readonly int _encryptionLevel;
|
||||||
|
private IEncryptPolicy _encryptionPolicy;
|
||||||
|
private IFieldEncryptor _memoryEncryptor;
|
||||||
|
|
||||||
|
public override ObfuscationPassType Type => ObfuscationPassType.FieldEncrypt;
|
||||||
|
|
||||||
|
public FieldEncryptPass(FieldEncryptionSettings settings)
|
||||||
|
{
|
||||||
|
_configFiles = settings.ruleFiles.ToList();
|
||||||
|
_encryptionLevel = settings.encryptionLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool ForceProcessAllAssembliesAndIgnoreAllPolicy => true;
|
||||||
|
|
||||||
|
public override void Start()
|
||||||
|
{
|
||||||
|
var ctx = ObfuscationPassContext.Current;
|
||||||
|
_memoryEncryptor = new DefaultFieldEncryptor(ctx.encryptionScopeProvider, ctx.moduleEntityManager, _encryptionLevel);
|
||||||
|
_encryptionPolicy = new ConfigurableEncryptPolicy(ctx.assembliesToObfuscate, _configFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Stop()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool NeedObfuscateMethod(MethodDef method)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsSupportedFieldType(TypeSig type)
|
||||||
|
{
|
||||||
|
type = type.RemovePinnedAndModifiers();
|
||||||
|
switch (type.ElementType)
|
||||||
|
{
|
||||||
|
case ElementType.I4:
|
||||||
|
case ElementType.I8:
|
||||||
|
case ElementType.U4:
|
||||||
|
case ElementType.U8:
|
||||||
|
case ElementType.R4:
|
||||||
|
case ElementType.R8:
|
||||||
|
return true;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool TryObfuscateInstruction(MethodDef callingMethod, Instruction inst, IList<Instruction> instructions, int instructionIndex, List<Instruction> outputInstructions, List<Instruction> totalFinalInstructions)
|
||||||
|
{
|
||||||
|
Code code = inst.OpCode.Code;
|
||||||
|
if (!(inst.Operand is IField field) || !field.IsField)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
FieldDef fieldDef = field.ResolveFieldDefThrow();
|
||||||
|
if (!IsSupportedFieldType(fieldDef.FieldSig.Type) || !_encryptionPolicy.NeedEncrypt(fieldDef))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
switch (code)
|
||||||
|
{
|
||||||
|
case Code.Ldfld:
|
||||||
|
{
|
||||||
|
_memoryEncryptor.Decrypt(callingMethod, fieldDef, outputInstructions, inst);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Code.Stfld:
|
||||||
|
{
|
||||||
|
_memoryEncryptor.Encrypt(callingMethod, fieldDef, outputInstructions, inst);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Code.Ldsfld:
|
||||||
|
{
|
||||||
|
_memoryEncryptor.Decrypt(callingMethod, fieldDef, outputInstructions, inst);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Code.Stsfld:
|
||||||
|
{
|
||||||
|
_memoryEncryptor.Encrypt(callingMethod, fieldDef, outputInstructions, inst);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Code.Ldflda:
|
||||||
|
case Code.Ldsflda:
|
||||||
|
{
|
||||||
|
throw new System.Exception($"You shouldn't get reference to memory encryption field: {field}");
|
||||||
|
}
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
//Debug.Log($"memory encrypt field: {field}");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.FieldEncrypt
|
||||||
|
{
|
||||||
|
public interface IEncryptPolicy
|
||||||
|
{
|
||||||
|
bool NeedEncrypt(FieldDef field);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class EncryptPolicyBase : IEncryptPolicy
|
||||||
|
{
|
||||||
|
public abstract bool NeedEncrypt(FieldDef field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using dnlib.DotNet.Emit;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.FieldEncrypt
|
||||||
|
{
|
||||||
|
public class MemoryEncryptionContext
|
||||||
|
{
|
||||||
|
public ModuleDef module;
|
||||||
|
|
||||||
|
public Instruction currentInstruction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IFieldEncryptor
|
||||||
|
{
|
||||||
|
void Encrypt(MethodDef method, FieldDef field, List<Instruction> outputInstructions, Instruction currentInstruction);
|
||||||
|
|
||||||
|
void Decrypt(MethodDef method, FieldDef field, List<Instruction> outputInstructions, Instruction currentInstruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class FieldEncryptorBase : IFieldEncryptor
|
||||||
|
{
|
||||||
|
public abstract void Encrypt(MethodDef method, FieldDef field, List<Instruction> outputInstructions, Instruction currentInstruction);
|
||||||
|
public abstract void Decrypt(MethodDef method, FieldDef field, List<Instruction> outputInstructions, Instruction currentInstruction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
using dnlib.DotNet.Emit;
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses
|
||||||
|
{
|
||||||
|
public abstract class InstructionObfuscationPassBase : ObfuscationPassBase
|
||||||
|
{
|
||||||
|
protected virtual bool ForceProcessAllAssembliesAndIgnoreAllPolicy => false;
|
||||||
|
|
||||||
|
protected abstract bool NeedObfuscateMethod(MethodDef method);
|
||||||
|
|
||||||
|
public override void Process()
|
||||||
|
{
|
||||||
|
var ctx = ObfuscationPassContext.Current;
|
||||||
|
var modules = ForceProcessAllAssembliesAndIgnoreAllPolicy ? ctx.allObfuscationRelativeModules : ctx.modulesToObfuscate;
|
||||||
|
ObfuscationMethodWhitelist whiteList = ctx.whiteList;
|
||||||
|
ConfigurablePassPolicy passPolicy = ctx.passPolicy;
|
||||||
|
foreach (ModuleDef mod in modules)
|
||||||
|
{
|
||||||
|
if (!ForceProcessAllAssembliesAndIgnoreAllPolicy && (whiteList.IsInWhiteList(mod) || !Support(passPolicy.GetAssemblyObfuscationPasses(mod))))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// ToArray to avoid modify list exception
|
||||||
|
foreach (TypeDef type in mod.GetTypes().ToArray())
|
||||||
|
{
|
||||||
|
if (!ForceProcessAllAssembliesAndIgnoreAllPolicy && (whiteList.IsInWhiteList(type) || !Support(passPolicy.GetTypeObfuscationPasses(type))))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// ToArray to avoid modify list exception
|
||||||
|
foreach (MethodDef method in type.Methods.ToArray())
|
||||||
|
{
|
||||||
|
if (!method.HasBody || (!ForceProcessAllAssembliesAndIgnoreAllPolicy && (ctx.whiteList.IsInWhiteList(method) || !Support(passPolicy.GetMethodObfuscationPasses(method)) || !NeedObfuscateMethod(method))))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// TODO if isGeneratedBy Obfuscator, continue
|
||||||
|
ObfuscateData(method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected abstract bool TryObfuscateInstruction(MethodDef callingMethod, Instruction inst, IList<Instruction> instructions, int instructionIndex,
|
||||||
|
List<Instruction> outputInstructions, List<Instruction> totalFinalInstructions);
|
||||||
|
|
||||||
|
private void ObfuscateData(MethodDef method)
|
||||||
|
{
|
||||||
|
IList<Instruction> instructions = method.Body.Instructions;
|
||||||
|
var outputInstructions = new List<Instruction>();
|
||||||
|
var totalFinalInstructions = new List<Instruction>();
|
||||||
|
for (int i = 0; i < instructions.Count; i++)
|
||||||
|
{
|
||||||
|
Instruction inst = instructions[i];
|
||||||
|
outputInstructions.Clear();
|
||||||
|
if (TryObfuscateInstruction(method, inst, instructions, i, outputInstructions, totalFinalInstructions))
|
||||||
|
{
|
||||||
|
// current instruction may be the target of control flow instruction, so we can't remove it directly.
|
||||||
|
// we replace it with nop now, then remove it in CleanUpInstructionPass
|
||||||
|
inst.OpCode = outputInstructions[0].OpCode;
|
||||||
|
inst.Operand = outputInstructions[0].Operand;
|
||||||
|
totalFinalInstructions.Add(inst);
|
||||||
|
for (int k = 1; k < outputInstructions.Count; k++)
|
||||||
|
{
|
||||||
|
totalFinalInstructions.Add(outputInstructions[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
totalFinalInstructions.Add(inst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
instructions.Clear();
|
||||||
|
foreach (var obInst in totalFinalInstructions)
|
||||||
|
{
|
||||||
|
instructions.Add(obInst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
using Obfuz.Emit;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses
|
||||||
|
{
|
||||||
|
public abstract class ObfuscationPassBase : IObfuscationPass
|
||||||
|
{
|
||||||
|
public abstract ObfuscationPassType Type { get; }
|
||||||
|
|
||||||
|
public bool Support(ObfuscationPassType passType)
|
||||||
|
{
|
||||||
|
return passType.HasFlag(Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void Start();
|
||||||
|
|
||||||
|
public abstract void Stop();
|
||||||
|
|
||||||
|
public abstract void Process();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
public enum ObfuscationPassType
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
|
||||||
|
ConstEncrypt = 0x1,
|
||||||
|
FieldEncrypt = 0x2,
|
||||||
|
|
||||||
|
SymbolObfus = 0x100,
|
||||||
|
CallObfus = 0x200,
|
||||||
|
ExprObfus = 0x400,
|
||||||
|
ControlFlowObfus = 0x800,
|
||||||
|
|
||||||
|
AllObfus = SymbolObfus | CallObfus | ExprObfus | ControlFlowObfus,
|
||||||
|
AllEncrypt = ConstEncrypt | FieldEncrypt,
|
||||||
|
|
||||||
|
MethodBodyObfusOrEncrypt = ConstEncrypt | CallObfus | ExprObfus | ControlFlowObfus,
|
||||||
|
|
||||||
|
All = ~0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.SymbolObfus
|
||||||
|
{
|
||||||
|
public interface INameMaker
|
||||||
|
{
|
||||||
|
void AddPreservedName(TypeDef typeDef, string name);
|
||||||
|
|
||||||
|
void AddPreservedNamespace(TypeDef typeDef, string name);
|
||||||
|
|
||||||
|
void AddPreservedName(MethodDef methodDef, string name);
|
||||||
|
|
||||||
|
void AddPreservedName(ParamDef paramDef, string name);
|
||||||
|
|
||||||
|
void AddPreservedName(FieldDef fieldDef, string name);
|
||||||
|
|
||||||
|
void AddPreservedName(PropertyDef propertyDef, string name);
|
||||||
|
|
||||||
|
void AddPreservedName(EventDef eventDef, string name);
|
||||||
|
|
||||||
|
string GetNewName(TypeDef typeDef, string originalName);
|
||||||
|
|
||||||
|
string GetNewNamespace(TypeDef typeDef, string originalNamespace, bool reuse);
|
||||||
|
|
||||||
|
string GetNewName(MethodDef methodDef, string originalName);
|
||||||
|
|
||||||
|
string GetNewName(ParamDef param, string originalName);
|
||||||
|
|
||||||
|
string GetNewName(FieldDef fieldDef, string originalName);
|
||||||
|
|
||||||
|
string GetNewName(PropertyDef propertyDef, string originalName);
|
||||||
|
|
||||||
|
string GetNewName(EventDef eventDef, string originalName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.SymbolObfus
|
||||||
|
{
|
||||||
|
public interface IObfuscationPolicy
|
||||||
|
{
|
||||||
|
bool NeedRename(TypeDef typeDef);
|
||||||
|
|
||||||
|
bool NeedRename(MethodDef methodDef);
|
||||||
|
|
||||||
|
bool NeedRename(FieldDef fieldDef);
|
||||||
|
|
||||||
|
bool NeedRename(PropertyDef propertyDef);
|
||||||
|
|
||||||
|
bool NeedRename(EventDef eventDef);
|
||||||
|
|
||||||
|
bool NeedRename(ParamDef paramDef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.SymbolObfus.NameMakers
|
||||||
|
{
|
||||||
|
public class DebugNameMaker : NameMakerBase
|
||||||
|
{
|
||||||
|
private class TestNameScope : NameScopeBase
|
||||||
|
{
|
||||||
|
private int _nextIndex;
|
||||||
|
protected override void BuildNewName(StringBuilder nameBuilder, string originalName, string lastName)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(lastName))
|
||||||
|
{
|
||||||
|
nameBuilder.Append($"${originalName}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nameBuilder.Append($"${originalName}{_nextIndex++}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override INameScope CreateNameScope()
|
||||||
|
{
|
||||||
|
return new TestNameScope();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
namespace Obfuz.ObfusPasses.SymbolObfus.NameMakers
|
||||||
|
{
|
||||||
|
public interface INameScope
|
||||||
|
{
|
||||||
|
void AddPreservedName(string name);
|
||||||
|
|
||||||
|
string GetNewName(string originalName, bool reuse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,108 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.SymbolObfus.NameMakers
|
||||||
|
{
|
||||||
|
public abstract class NameMakerBase : INameMaker
|
||||||
|
{
|
||||||
|
|
||||||
|
private readonly Dictionary<object, INameScope> _nameScopes = new Dictionary<object, INameScope>();
|
||||||
|
|
||||||
|
private readonly object _namespaceScope = new object();
|
||||||
|
|
||||||
|
protected abstract INameScope CreateNameScope();
|
||||||
|
|
||||||
|
protected INameScope GetNameScope(object key)
|
||||||
|
{
|
||||||
|
if (!_nameScopes.TryGetValue(key, out var nameScope))
|
||||||
|
{
|
||||||
|
nameScope = CreateNameScope();
|
||||||
|
_nameScopes[key] = nameScope;
|
||||||
|
}
|
||||||
|
return nameScope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddPreservedName(TypeDef typeDef, string name)
|
||||||
|
{
|
||||||
|
GetNameScope(typeDef.Module).AddPreservedName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddPreservedName(MethodDef methodDef, string name)
|
||||||
|
{
|
||||||
|
GetNameScope(methodDef.DeclaringType).AddPreservedName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddPreservedName(ParamDef paramDef, string name)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddPreservedName(FieldDef fieldDef, string name)
|
||||||
|
{
|
||||||
|
GetNameScope(fieldDef.DeclaringType).AddPreservedName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddPreservedName(PropertyDef propertyDef, string name)
|
||||||
|
{
|
||||||
|
GetNameScope(propertyDef.DeclaringType).AddPreservedName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddPreservedName(EventDef eventDef, string name)
|
||||||
|
{
|
||||||
|
GetNameScope(eventDef.DeclaringType).AddPreservedName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddPreservedNamespace(TypeDef typeDef, string name)
|
||||||
|
{
|
||||||
|
GetNameScope(_namespaceScope).AddPreservedName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetDefaultNewName(object scope, string originName)
|
||||||
|
{
|
||||||
|
return GetNameScope(scope).GetNewName(originName, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetNewNamespace(TypeDef typeDef, string originalNamespace, bool reuse)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(originalNamespace))
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
return GetNameScope(_namespaceScope).GetNewName(originalNamespace, reuse);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetNewName(TypeDef typeDef, string originalName)
|
||||||
|
{
|
||||||
|
return GetDefaultNewName(typeDef.Module, originalName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetNewName(MethodDef methodDef, string originalName)
|
||||||
|
{
|
||||||
|
return GetDefaultNewName(methodDef.DeclaringType, originalName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual string GetNewName(ParamDef param, string originalName)
|
||||||
|
{
|
||||||
|
return "1";
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetNewName(FieldDef fieldDef, string originalName)
|
||||||
|
{
|
||||||
|
return GetDefaultNewName(fieldDef.DeclaringType, originalName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetNewName(PropertyDef propertyDef, string originalName)
|
||||||
|
{
|
||||||
|
return GetDefaultNewName(propertyDef.DeclaringType, originalName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetNewName(EventDef eventDef, string originalName)
|
||||||
|
{
|
||||||
|
return GetDefaultNewName(eventDef.DeclaringType, originalName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.Remoting.Messaging;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.SymbolObfus.NameMakers
|
||||||
|
{
|
||||||
|
public static class NameMakerFactory
|
||||||
|
{
|
||||||
|
public static INameMaker CreateDebugNameMaker()
|
||||||
|
{
|
||||||
|
return new DebugNameMaker();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static INameMaker CreateNameMakerBaseASCIICharSet(string namePrefix)
|
||||||
|
{
|
||||||
|
var words = new List<string>();
|
||||||
|
for (int i = 0; i < 26; i++)
|
||||||
|
{
|
||||||
|
words.Add(((char)('a' + i)).ToString());
|
||||||
|
words.Add(((char)('A' + i)).ToString());
|
||||||
|
}
|
||||||
|
return new WordSetNameMaker(namePrefix, words);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
using Microsoft.SqlServer.Server;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.SymbolObfus.NameMakers
|
||||||
|
{
|
||||||
|
|
||||||
|
public class NameScope : NameScopeBase
|
||||||
|
{
|
||||||
|
private readonly string _namePrefix;
|
||||||
|
private readonly List<string> _wordSet;
|
||||||
|
private int _nextIndex;
|
||||||
|
|
||||||
|
public NameScope(string namePrefix, List<string> wordSet)
|
||||||
|
{
|
||||||
|
_namePrefix = namePrefix;
|
||||||
|
_wordSet = wordSet;
|
||||||
|
_nextIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void BuildNewName(StringBuilder nameBuilder, string originalName, string lastName)
|
||||||
|
{
|
||||||
|
nameBuilder.Append(_namePrefix);
|
||||||
|
for (int i = _nextIndex++; ;)
|
||||||
|
{
|
||||||
|
nameBuilder.Append(_wordSet[i % _wordSet.Count]);
|
||||||
|
i = i / _wordSet.Count;
|
||||||
|
if (i == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.SymbolObfus.NameMakers
|
||||||
|
{
|
||||||
|
public abstract class NameScopeBase : INameScope
|
||||||
|
{
|
||||||
|
|
||||||
|
private readonly Dictionary<string, string> _nameMap = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
private readonly HashSet<string> _preservedNames = new HashSet<string>();
|
||||||
|
|
||||||
|
|
||||||
|
public void AddPreservedName(string name)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(name))
|
||||||
|
{
|
||||||
|
_preservedNames.Add(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected abstract void BuildNewName(StringBuilder nameBuilder, string originalName, string lastName);
|
||||||
|
|
||||||
|
private string CreateNewName(string originalName)
|
||||||
|
{
|
||||||
|
var nameBuilder = new StringBuilder();
|
||||||
|
string lastName = null;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
nameBuilder.Clear();
|
||||||
|
BuildNewName(nameBuilder, originalName, lastName);
|
||||||
|
string newName = nameBuilder.ToString();
|
||||||
|
lastName = newName;
|
||||||
|
if (_preservedNames.Add(newName))
|
||||||
|
{
|
||||||
|
return newName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetNewName(string originalName, bool reuse)
|
||||||
|
{
|
||||||
|
if (!reuse)
|
||||||
|
{
|
||||||
|
return CreateNewName(originalName);
|
||||||
|
}
|
||||||
|
if (_nameMap.TryGetValue(originalName, out var newName))
|
||||||
|
{
|
||||||
|
return newName;
|
||||||
|
}
|
||||||
|
newName = CreateNewName(originalName);
|
||||||
|
_nameMap[originalName] = newName;
|
||||||
|
return newName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.SymbolObfus.NameMakers
|
||||||
|
{
|
||||||
|
|
||||||
|
public class WordSetNameMaker : NameMakerBase
|
||||||
|
{
|
||||||
|
private readonly string _namePrefix;
|
||||||
|
private readonly List<string> _wordSet;
|
||||||
|
|
||||||
|
public WordSetNameMaker(string namePrefix, List<string> wordSet)
|
||||||
|
{
|
||||||
|
_namePrefix = namePrefix;
|
||||||
|
_wordSet = wordSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override INameScope CreateNameScope()
|
||||||
|
{
|
||||||
|
return new NameScope(_namePrefix, _wordSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.SymbolObfus.Policies
|
||||||
|
{
|
||||||
|
public class CacheRenamePolicy : ObfuscationPolicyBase
|
||||||
|
{
|
||||||
|
private readonly IObfuscationPolicy _underlyingPolicy;
|
||||||
|
|
||||||
|
private readonly Dictionary<object, bool> _computeCache = new Dictionary<object, bool>();
|
||||||
|
|
||||||
|
public CacheRenamePolicy(IObfuscationPolicy underlyingPolicy)
|
||||||
|
{
|
||||||
|
_underlyingPolicy = underlyingPolicy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedRename(TypeDef typeDef)
|
||||||
|
{
|
||||||
|
if (!_computeCache.TryGetValue(typeDef, out var value))
|
||||||
|
{
|
||||||
|
value = _underlyingPolicy.NeedRename(typeDef);
|
||||||
|
_computeCache[typeDef] = value;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedRename(MethodDef methodDef)
|
||||||
|
{
|
||||||
|
if (!_computeCache.TryGetValue(methodDef, out var value))
|
||||||
|
{
|
||||||
|
value = _underlyingPolicy.NeedRename(methodDef);
|
||||||
|
_computeCache[methodDef] = value;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedRename(FieldDef fieldDef)
|
||||||
|
{
|
||||||
|
if (!_computeCache.TryGetValue(fieldDef, out var value))
|
||||||
|
{
|
||||||
|
value = _underlyingPolicy.NeedRename(fieldDef);
|
||||||
|
_computeCache[fieldDef] = value;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedRename(PropertyDef propertyDef)
|
||||||
|
{
|
||||||
|
if (!_computeCache.TryGetValue(propertyDef, out var value))
|
||||||
|
{
|
||||||
|
value = _underlyingPolicy.NeedRename(propertyDef);
|
||||||
|
_computeCache[propertyDef] = value;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedRename(EventDef eventDef)
|
||||||
|
{
|
||||||
|
if (!_computeCache.TryGetValue(eventDef, out var value))
|
||||||
|
{
|
||||||
|
value = _underlyingPolicy.NeedRename(eventDef);
|
||||||
|
_computeCache[eventDef] = value;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedRename(ParamDef paramDef)
|
||||||
|
{
|
||||||
|
if (!_computeCache.TryGetValue(paramDef, out var value))
|
||||||
|
{
|
||||||
|
value = _underlyingPolicy.NeedRename(paramDef);
|
||||||
|
_computeCache[paramDef] = value;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.SymbolObfus.Policies
|
||||||
|
{
|
||||||
|
public class CombineRenamePolicy : IObfuscationPolicy
|
||||||
|
{
|
||||||
|
private readonly IObfuscationPolicy[] _policies;
|
||||||
|
|
||||||
|
public CombineRenamePolicy(params IObfuscationPolicy[] policies)
|
||||||
|
{
|
||||||
|
_policies = policies;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool NeedRename(TypeDef typeDef)
|
||||||
|
{
|
||||||
|
return _policies.All(policy => policy.NeedRename(typeDef));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool NeedRename(MethodDef methodDef)
|
||||||
|
{
|
||||||
|
return _policies.All(policy => policy.NeedRename(methodDef));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool NeedRename(FieldDef fieldDef)
|
||||||
|
{
|
||||||
|
return _policies.All(policy => policy.NeedRename(fieldDef));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool NeedRename(PropertyDef propertyDef)
|
||||||
|
{
|
||||||
|
return _policies.All(policy => policy.NeedRename(propertyDef));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool NeedRename(EventDef eventDef)
|
||||||
|
{
|
||||||
|
return _policies.All(policy => policy.NeedRename(eventDef));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool NeedRename(ParamDef paramDef)
|
||||||
|
{
|
||||||
|
return _policies.All(policy => policy.NeedRename(paramDef));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,895 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using Obfuz.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.SymbolObfus.Policies
|
||||||
|
{
|
||||||
|
|
||||||
|
public class ConfigurableRenamePolicy : ObfuscationPolicyBase
|
||||||
|
{
|
||||||
|
enum ObfuscationType
|
||||||
|
{
|
||||||
|
Name = 1,
|
||||||
|
Namespace = 2,
|
||||||
|
NestType = 3,
|
||||||
|
Method = 4,
|
||||||
|
Field = 5,
|
||||||
|
Property = 6,
|
||||||
|
Event = 7,
|
||||||
|
Param = 8,
|
||||||
|
MethodBody = 9,
|
||||||
|
Getter = 10,
|
||||||
|
Setter = 11,
|
||||||
|
Add = 12,
|
||||||
|
Remove = 13,
|
||||||
|
Fire = 14,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum RuleType
|
||||||
|
{
|
||||||
|
Assembly = 1,
|
||||||
|
Type = 2,
|
||||||
|
Method = 3,
|
||||||
|
Field = 4,
|
||||||
|
Property = 5,
|
||||||
|
Event = 6,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ModifierType
|
||||||
|
{
|
||||||
|
Private = 0,
|
||||||
|
Protected = 1,
|
||||||
|
Public = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IRule
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class MethodRuleSpec
|
||||||
|
{
|
||||||
|
public NameMatcher nameMatcher;
|
||||||
|
public ModifierType modifierType;
|
||||||
|
public MethodRule rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MethodRule : IRule
|
||||||
|
{
|
||||||
|
public string ruleName;
|
||||||
|
public bool obfuscateName;
|
||||||
|
public bool obfuscateParam;
|
||||||
|
public bool obfuscateBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
class FieldRuleSpec
|
||||||
|
{
|
||||||
|
public NameMatcher nameMatcher;
|
||||||
|
public ModifierType modifierType;
|
||||||
|
public FieldRule rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
class FieldRule : IRule
|
||||||
|
{
|
||||||
|
public string ruleName;
|
||||||
|
public bool obfuscateName;
|
||||||
|
}
|
||||||
|
|
||||||
|
class PropertyRuleSpec
|
||||||
|
{
|
||||||
|
public NameMatcher nameMatcher;
|
||||||
|
public PropertyRule rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
class PropertyRule : IRule
|
||||||
|
{
|
||||||
|
public string ruleName;
|
||||||
|
public bool obfuscateName;
|
||||||
|
public MethodRuleSpec getter;
|
||||||
|
public MethodRuleSpec setter;
|
||||||
|
}
|
||||||
|
|
||||||
|
class EventRuleSpec
|
||||||
|
{
|
||||||
|
public NameMatcher nameMatcher;
|
||||||
|
public EventRule rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
class EventRule : IRule
|
||||||
|
{
|
||||||
|
public string ruleName;
|
||||||
|
public bool obfuscateName;
|
||||||
|
public MethodRuleSpec add;
|
||||||
|
public MethodRuleSpec remove;
|
||||||
|
public MethodRuleSpec fire;
|
||||||
|
}
|
||||||
|
|
||||||
|
class TypeRuleSpec
|
||||||
|
{
|
||||||
|
public NameMatcher nameMatcher;
|
||||||
|
public ModifierType modifierType;
|
||||||
|
public TypeRule rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
class TypeRule : IRule
|
||||||
|
{
|
||||||
|
public string ruleName;
|
||||||
|
|
||||||
|
public bool obfuscateName;
|
||||||
|
public bool obfuscateNamespace;
|
||||||
|
|
||||||
|
//public List<TypeRuleSpec> nestTypeRuleSpecs;
|
||||||
|
public List<FieldRuleSpec> fieldRuleSpecs;
|
||||||
|
public List<MethodRuleSpec> methodRuleSpecs;
|
||||||
|
public List<PropertyRuleSpec> propertyRuleSpecs;
|
||||||
|
public List<EventRuleSpec> eventRuleSpecs;
|
||||||
|
}
|
||||||
|
|
||||||
|
class AssemblyRule : IRule
|
||||||
|
{
|
||||||
|
public string ruleName;
|
||||||
|
|
||||||
|
public bool obfuscateName;
|
||||||
|
|
||||||
|
public List<TypeRuleSpec> typeRuleSpecs;
|
||||||
|
}
|
||||||
|
|
||||||
|
class AssemblyRuleSpec
|
||||||
|
{
|
||||||
|
public string assemblyName;
|
||||||
|
public AssemblyRule rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
//class DefaultRule : IRule
|
||||||
|
//{
|
||||||
|
|
||||||
|
//}
|
||||||
|
|
||||||
|
//private readonly static IRule _defaultRule = new DefaultRule();
|
||||||
|
//private readonly static IRule _noneRule = new DefaultRule();
|
||||||
|
|
||||||
|
private readonly Dictionary<(string, RuleType), IRule> _rules = new Dictionary<(string, RuleType), IRule>();
|
||||||
|
|
||||||
|
private readonly Dictionary<(string, RuleType), XmlElement> _rawRuleElements = new Dictionary<(string, RuleType), XmlElement>();
|
||||||
|
|
||||||
|
private readonly Dictionary<string, AssemblyRuleSpec> _assemblyRuleSpecs = new Dictionary<string, AssemblyRuleSpec>();
|
||||||
|
|
||||||
|
|
||||||
|
private static readonly MethodRule s_noneMethodRule = new MethodRule
|
||||||
|
{
|
||||||
|
ruleName = "none",
|
||||||
|
obfuscateName = false,
|
||||||
|
obfuscateParam = false,
|
||||||
|
obfuscateBody = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly EventRule s_noneEventRule = new EventRule
|
||||||
|
{
|
||||||
|
ruleName = "none",
|
||||||
|
obfuscateName = false,
|
||||||
|
add = new MethodRuleSpec { rule = s_noneMethodRule},
|
||||||
|
remove = new MethodRuleSpec { rule = s_noneMethodRule },
|
||||||
|
fire = new MethodRuleSpec { rule = s_noneMethodRule },
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly PropertyRule s_nonePropertyRule = new PropertyRule
|
||||||
|
{
|
||||||
|
ruleName = "none",
|
||||||
|
obfuscateName = false,
|
||||||
|
getter = new MethodRuleSpec { rule = s_noneMethodRule },
|
||||||
|
setter = new MethodRuleSpec { rule = s_noneMethodRule },
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly FieldRule s_noneFieldRule = new FieldRule
|
||||||
|
{
|
||||||
|
ruleName = "none",
|
||||||
|
obfuscateName = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly TypeRule s_noneTypeRule = new TypeRule
|
||||||
|
{
|
||||||
|
ruleName = "none",
|
||||||
|
obfuscateName = false,
|
||||||
|
obfuscateNamespace = false,
|
||||||
|
//nestTypeRuleSpecs = new List<TypeRuleSpec>(),
|
||||||
|
fieldRuleSpecs = new List<FieldRuleSpec> { new FieldRuleSpec { rule = s_noneFieldRule} },
|
||||||
|
methodRuleSpecs = new List<MethodRuleSpec> { new MethodRuleSpec { rule = s_noneMethodRule} },
|
||||||
|
propertyRuleSpecs = new List<PropertyRuleSpec> { new PropertyRuleSpec { rule = s_nonePropertyRule} },
|
||||||
|
eventRuleSpecs = new List<EventRuleSpec> { new EventRuleSpec { rule = s_noneEventRule} },
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly AssemblyRule s_noneAssemblyRule = new AssemblyRule
|
||||||
|
{
|
||||||
|
ruleName = "none",
|
||||||
|
obfuscateName = false,
|
||||||
|
typeRuleSpecs = new List<TypeRuleSpec> { new TypeRuleSpec { rule = s_noneTypeRule } },
|
||||||
|
};
|
||||||
|
|
||||||
|
//static ObfuscateRuleConfig()
|
||||||
|
//{
|
||||||
|
// s_noneTypeRule.nestTypeRuleSpecs.Add(new TypeRuleSpec
|
||||||
|
// {
|
||||||
|
// rule = s_noneTypeRule,
|
||||||
|
// });
|
||||||
|
//}
|
||||||
|
|
||||||
|
private IRule GetOrParseRule(string ruleName, RuleType ruleType, XmlElement ele)
|
||||||
|
{
|
||||||
|
IRule rule = null;
|
||||||
|
XmlElement element;
|
||||||
|
if (!string.IsNullOrEmpty(ruleName))
|
||||||
|
{
|
||||||
|
if (ruleName == "none")
|
||||||
|
{
|
||||||
|
switch (ruleType)
|
||||||
|
{
|
||||||
|
case RuleType.Assembly: return s_noneAssemblyRule;
|
||||||
|
case RuleType.Type: return s_noneTypeRule;
|
||||||
|
case RuleType.Method: return s_noneMethodRule;
|
||||||
|
case RuleType.Field: return s_noneFieldRule;
|
||||||
|
case RuleType.Property: return s_nonePropertyRule;
|
||||||
|
case RuleType.Event: return s_noneEventRule;
|
||||||
|
default: throw new Exception($"Invalid rule type {ruleType}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_rules.TryGetValue((ruleName, ruleType), out rule))
|
||||||
|
{
|
||||||
|
return rule;
|
||||||
|
}
|
||||||
|
if (!_rawRuleElements.TryGetValue((ruleName, ruleType), out element))
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file, rule {ruleName} type {ruleType} not found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
element = ele;
|
||||||
|
}
|
||||||
|
switch (ruleType)
|
||||||
|
{
|
||||||
|
case RuleType.Assembly:
|
||||||
|
rule = ParseAssemblyRule(ruleName, element);
|
||||||
|
break;
|
||||||
|
case RuleType.Type:
|
||||||
|
rule = ParseTypeRule(ruleName, element);
|
||||||
|
break;
|
||||||
|
case RuleType.Method:
|
||||||
|
rule = ParseMethodRule(ruleName, element);
|
||||||
|
break;
|
||||||
|
case RuleType.Field:
|
||||||
|
rule = ParseFieldRule(ruleName, element);
|
||||||
|
break;
|
||||||
|
case RuleType.Property:
|
||||||
|
rule = ParsePropertyRule(ruleName, element);
|
||||||
|
break;
|
||||||
|
case RuleType.Event:
|
||||||
|
rule = ParseEventRule(ruleName, element);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception($"Invalid rule type {ruleType}");
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(ruleName))
|
||||||
|
{
|
||||||
|
_rules.Add((ruleName, ruleType), rule);
|
||||||
|
}
|
||||||
|
return rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool ParseBoolNoneOrFalse(string str)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(str))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
switch (str.ToLowerInvariant())
|
||||||
|
{
|
||||||
|
case "1":
|
||||||
|
case "true": throw new Exception($"Invalid bool value '{str}', only accept '0' or 'false' because default is true"); // true is default
|
||||||
|
case "0":
|
||||||
|
case "false": return false;
|
||||||
|
default: throw new Exception($"Invalid bool value {str}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private AssemblyRule ParseAssemblyRule(string ruleName, XmlElement element)
|
||||||
|
{
|
||||||
|
var rule = new AssemblyRule();
|
||||||
|
rule.ruleName = ruleName;
|
||||||
|
rule.obfuscateName = ParseBoolNoneOrFalse(element.GetAttribute("ob-name"));
|
||||||
|
rule.typeRuleSpecs = new List<TypeRuleSpec>();
|
||||||
|
foreach (XmlNode node in element.ChildNodes)
|
||||||
|
{
|
||||||
|
if (!(node is XmlElement childElement))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (childElement.Name != "type")
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file, unknown node {childElement.Name}");
|
||||||
|
}
|
||||||
|
var typeRuleSpec = new TypeRuleSpec();
|
||||||
|
typeRuleSpec.nameMatcher = new NameMatcher(childElement.GetAttribute("name"));
|
||||||
|
typeRuleSpec.modifierType = ParseModifierType(childElement.GetAttribute("modifier"));
|
||||||
|
typeRuleSpec.rule = (TypeRule)GetOrParseRule(childElement.GetAttribute("rule"), RuleType.Type, childElement);
|
||||||
|
rule.typeRuleSpecs.Add(typeRuleSpec);
|
||||||
|
}
|
||||||
|
return rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TypeRule ParseTypeRule(string ruleName, XmlElement element)
|
||||||
|
{
|
||||||
|
var rule = new TypeRule();
|
||||||
|
rule.ruleName = ruleName;
|
||||||
|
rule.obfuscateName = ParseBoolNoneOrFalse(element.GetAttribute("ob-name"));
|
||||||
|
rule.obfuscateNamespace = ParseBoolNoneOrFalse(element.GetAttribute("ob-namespace"));
|
||||||
|
//rule.nestTypeRuleSpecs = new List<TypeRuleSpec>();
|
||||||
|
rule.fieldRuleSpecs = new List<FieldRuleSpec>();
|
||||||
|
rule.methodRuleSpecs = new List<MethodRuleSpec>();
|
||||||
|
rule.propertyRuleSpecs = new List<PropertyRuleSpec>();
|
||||||
|
rule.eventRuleSpecs = new List<EventRuleSpec>();
|
||||||
|
foreach (XmlNode node in element.ChildNodes)
|
||||||
|
{
|
||||||
|
if (!(node is XmlElement childElement))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (childElement.Name)
|
||||||
|
{
|
||||||
|
//case "nesttype":
|
||||||
|
//{
|
||||||
|
// var typeRuleSpec = new TypeRuleSpec();
|
||||||
|
// typeRuleSpec.nameMatcher = new NameMatcher(childElement.GetAttribute("name"));
|
||||||
|
// typeRuleSpec.modifierType = ParseModifierType(childElement.GetAttribute("modifier"));
|
||||||
|
// typeRuleSpec.rule = (TypeRule)GetOrParseRule(childElement.GetAttribute("rule"), RuleType.Type, childElement);
|
||||||
|
// rule.nestTypeRuleSpecs.Add(typeRuleSpec);
|
||||||
|
// break;
|
||||||
|
//}
|
||||||
|
case "field":
|
||||||
|
{
|
||||||
|
var fieldRuleSpec = new FieldRuleSpec();
|
||||||
|
fieldRuleSpec.nameMatcher = new NameMatcher(childElement.GetAttribute("name"));
|
||||||
|
fieldRuleSpec.modifierType = ParseModifierType(childElement.GetAttribute("modifier"));
|
||||||
|
fieldRuleSpec.rule = (FieldRule)GetOrParseRule(childElement.GetAttribute("rule"), RuleType.Field, childElement);
|
||||||
|
rule.fieldRuleSpecs.Add(fieldRuleSpec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "method":
|
||||||
|
{
|
||||||
|
rule.methodRuleSpecs.Add(ParseMethodRuleSpec(childElement));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "property":
|
||||||
|
{
|
||||||
|
var propertyRulerSpec = new PropertyRuleSpec();
|
||||||
|
propertyRulerSpec.nameMatcher = new NameMatcher(childElement.GetAttribute("name"));
|
||||||
|
propertyRulerSpec.rule = (PropertyRule)GetOrParseRule(childElement.GetAttribute("rule"), RuleType.Property, childElement);
|
||||||
|
rule.propertyRuleSpecs.Add(propertyRulerSpec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "event":
|
||||||
|
{
|
||||||
|
var eventRuleSpec = new EventRuleSpec();
|
||||||
|
eventRuleSpec.nameMatcher = new NameMatcher(childElement.GetAttribute("name"));
|
||||||
|
eventRuleSpec.rule = (EventRule)GetOrParseRule(childElement.GetAttribute("rule"), RuleType.Event, childElement);
|
||||||
|
rule.eventRuleSpecs.Add(eventRuleSpec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: throw new Exception($"Invalid xml file, unknown node {childElement.Name} in type rule {ruleName}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MethodRuleSpec ParseMethodRuleSpec(XmlElement el)
|
||||||
|
{
|
||||||
|
var methodRuleSpec = new MethodRuleSpec();
|
||||||
|
methodRuleSpec.nameMatcher = new NameMatcher(el.GetAttribute("name"));
|
||||||
|
methodRuleSpec.modifierType = ParseModifierType(el.GetAttribute("modifier"));
|
||||||
|
methodRuleSpec.rule = (MethodRule)GetOrParseRule(el.GetAttribute("rule"), RuleType.Method, el);
|
||||||
|
return methodRuleSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MethodRule ParseMethodRule(string ruleName, XmlElement element)
|
||||||
|
{
|
||||||
|
var rule = new MethodRule();
|
||||||
|
rule.ruleName = ruleName;
|
||||||
|
rule.obfuscateName = ParseBoolNoneOrFalse(element.GetAttribute("ob-name"));
|
||||||
|
rule.obfuscateParam = ParseBoolNoneOrFalse(element.GetAttribute("ob-param"));
|
||||||
|
rule.obfuscateBody = ParseBoolNoneOrFalse(element.GetAttribute("ob-body"));
|
||||||
|
return rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
private FieldRule ParseFieldRule(string ruleName, XmlElement element)
|
||||||
|
{
|
||||||
|
var rule = new FieldRule();
|
||||||
|
rule.ruleName = ruleName;
|
||||||
|
rule.obfuscateName = ParseBoolNoneOrFalse(element.GetAttribute("ob-name"));
|
||||||
|
return rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PropertyRule ParsePropertyRule(string ruleName, XmlElement element)
|
||||||
|
{
|
||||||
|
var rule = new PropertyRule();
|
||||||
|
rule.ruleName = ruleName;
|
||||||
|
rule.obfuscateName = ParseBoolNoneOrFalse(element.GetAttribute("ob-name"));
|
||||||
|
|
||||||
|
foreach (XmlNode node in element.ChildNodes)
|
||||||
|
{
|
||||||
|
if (!(node is XmlElement childElement))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (node.Name)
|
||||||
|
{
|
||||||
|
case "getter":
|
||||||
|
{
|
||||||
|
if (rule.getter != null)
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file, duplicate getter rule in property rule {ruleName}");
|
||||||
|
}
|
||||||
|
rule.getter = ParseMethodRuleSpec(childElement);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "setter":
|
||||||
|
{
|
||||||
|
if (rule.setter != null)
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file, duplicate setter rule in property rule {ruleName}");
|
||||||
|
}
|
||||||
|
rule.setter = ParseMethodRuleSpec(childElement);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: throw new Exception($"Invalid xml file, unknown node {childElement.Name} in property rule {ruleName}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
private EventRule ParseEventRule(string ruleName, XmlElement element)
|
||||||
|
{
|
||||||
|
var rule = new EventRule();
|
||||||
|
rule.ruleName = ruleName;
|
||||||
|
rule.obfuscateName = ParseBoolNoneOrFalse(element.GetAttribute("ob-name"));
|
||||||
|
|
||||||
|
foreach (XmlNode node in element.ChildNodes)
|
||||||
|
{
|
||||||
|
if (!(node is XmlElement childElement))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (node.Name)
|
||||||
|
{
|
||||||
|
case "add":
|
||||||
|
{
|
||||||
|
if (rule.add != null)
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file, duplicate getter rule in property rule {ruleName}");
|
||||||
|
}
|
||||||
|
rule.add = ParseMethodRuleSpec(childElement);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "remove":
|
||||||
|
{
|
||||||
|
if (rule.remove != null)
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file, duplicate setter rule in property rule {ruleName}");
|
||||||
|
}
|
||||||
|
rule.remove = ParseMethodRuleSpec(childElement);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "fire":
|
||||||
|
{
|
||||||
|
if (rule.fire != null)
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file, duplicate fire rule in property rule {ruleName}");
|
||||||
|
}
|
||||||
|
rule.fire = ParseMethodRuleSpec(childElement);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: throw new Exception($"Invalid xml file, unknown node {childElement.Name} in event rule {ruleName}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadXmls(List<string> xmlFiles)
|
||||||
|
{
|
||||||
|
var rawAssemblySpecElements = new List<XmlElement>();
|
||||||
|
foreach (string file in xmlFiles)
|
||||||
|
{
|
||||||
|
LoadRawXml(file, rawAssemblySpecElements);
|
||||||
|
}
|
||||||
|
ResolveAssemblySpecs(rawAssemblySpecElements);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ResolveAssemblySpecs(List<XmlElement> rawAssemblySpecElements)
|
||||||
|
{
|
||||||
|
foreach (XmlElement ele in rawAssemblySpecElements)
|
||||||
|
{
|
||||||
|
string assemblyName = ele.GetAttribute("name");
|
||||||
|
if (string.IsNullOrEmpty(assemblyName))
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file, assembly name is empty");
|
||||||
|
}
|
||||||
|
if (!_obfuscationAssemblyNames.Contains(assemblyName))
|
||||||
|
{
|
||||||
|
throw new Exception($"unknown assembly name:{assemblyName}, not in ObfuzSettings.obfuscationAssemblyNames");
|
||||||
|
}
|
||||||
|
if (_assemblyRuleSpecs.ContainsKey(assemblyName))
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file, duplicate assembly name {assemblyName}");
|
||||||
|
}
|
||||||
|
var assemblyRule = new AssemblyRuleSpec()
|
||||||
|
{
|
||||||
|
assemblyName = assemblyName,
|
||||||
|
rule = (AssemblyRule)GetOrParseRule(ele.GetAttribute("rule"), RuleType.Assembly, ele),
|
||||||
|
};
|
||||||
|
_assemblyRuleSpecs.Add(assemblyName, assemblyRule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private RuleType ParseRuleType(string ruleType)
|
||||||
|
{
|
||||||
|
switch (ruleType)
|
||||||
|
{
|
||||||
|
case "assembly": return RuleType.Assembly;
|
||||||
|
case "type": return RuleType.Type;
|
||||||
|
case "method": return RuleType.Method;
|
||||||
|
case "field": return RuleType.Field;
|
||||||
|
case "property": return RuleType.Property;
|
||||||
|
case "event": return RuleType.Event;
|
||||||
|
default: throw new Exception($"Invalid rule type {ruleType}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ModifierType ParseModifierType(string modifierType)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(modifierType))
|
||||||
|
{
|
||||||
|
return ModifierType.Private;
|
||||||
|
}
|
||||||
|
switch (modifierType)
|
||||||
|
{
|
||||||
|
case "public": return ModifierType.Public;
|
||||||
|
case "protected": return ModifierType.Protected;
|
||||||
|
case "private": return ModifierType.Private;
|
||||||
|
default: throw new Exception($"Invalid modifier type {modifierType}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadRawXml(string xmlFile, List<XmlElement> rawAssemblyElements)
|
||||||
|
{
|
||||||
|
Debug.Log($"ObfuscateRule::LoadXml {xmlFile}");
|
||||||
|
var doc = new XmlDocument();
|
||||||
|
//var nsManager = new XmlNamespaceManager(doc.NameTable);
|
||||||
|
//nsManager.AddNamespace("ob", "https://github.com/focus-creative-games/Obfuz"); // 绑定前缀到 URI
|
||||||
|
doc.Load(xmlFile);
|
||||||
|
var root = doc.DocumentElement;
|
||||||
|
if (root.Name != "obfuz")
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file {xmlFile}, root name should be 'obfuz'");
|
||||||
|
}
|
||||||
|
foreach (XmlNode node in root.ChildNodes)
|
||||||
|
{
|
||||||
|
if (!(node is XmlElement element))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (element.Name)
|
||||||
|
{
|
||||||
|
case "rules":
|
||||||
|
{
|
||||||
|
ParseRules(xmlFile, element);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "assembly":
|
||||||
|
{
|
||||||
|
rawAssemblyElements.Add(element);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file {xmlFile}, unknown node {element.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ParseRules(string xmlFile, XmlElement rulesNode)
|
||||||
|
{
|
||||||
|
foreach (XmlNode node in rulesNode)
|
||||||
|
{
|
||||||
|
if (!(node is XmlElement ruleEle))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
string ruleName = ruleEle.GetAttribute("name");
|
||||||
|
string ruleTypeName = ruleEle.Name;
|
||||||
|
RuleType ruleType = ParseRuleType(ruleTypeName);
|
||||||
|
var key = (ruleName, ruleType);
|
||||||
|
if (_rawRuleElements.ContainsKey(key))
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file {xmlFile}, duplicate rule name:{ruleName} type:{ruleType}");
|
||||||
|
}
|
||||||
|
_rawRuleElements.Add(key, ruleEle);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private ModifierType ComputeModifierType(TypeAttributes visibility)
|
||||||
|
{
|
||||||
|
if (visibility == TypeAttributes.NotPublic || visibility == TypeAttributes.NestedPrivate)
|
||||||
|
{
|
||||||
|
return ModifierType.Private;
|
||||||
|
}
|
||||||
|
if (visibility == TypeAttributes.Public || visibility == TypeAttributes.NestedPublic)
|
||||||
|
{
|
||||||
|
return ModifierType.Public;
|
||||||
|
}
|
||||||
|
return ModifierType.Protected;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ModifierType ComputeModifierType(FieldAttributes access)
|
||||||
|
{
|
||||||
|
if (access == FieldAttributes.Private || access == FieldAttributes.PrivateScope)
|
||||||
|
{
|
||||||
|
return ModifierType.Private;
|
||||||
|
}
|
||||||
|
if (access == FieldAttributes.Public)
|
||||||
|
{
|
||||||
|
return ModifierType.Public;
|
||||||
|
}
|
||||||
|
return ModifierType.Protected;
|
||||||
|
}
|
||||||
|
|
||||||
|
//private ModifierType ComputeModifierType(MethodAttributes access)
|
||||||
|
//{
|
||||||
|
// if (access == MethodAttributes.Private || access == MethodAttributes.PrivateScope)
|
||||||
|
// {
|
||||||
|
// return ModifierType.Private;
|
||||||
|
// }
|
||||||
|
// if (access == MethodAttributes.Public)
|
||||||
|
// {
|
||||||
|
// return ModifierType.Public;
|
||||||
|
// }
|
||||||
|
// return ModifierType.Protected;
|
||||||
|
//}
|
||||||
|
|
||||||
|
private bool MatchModifier(ModifierType modifierType, TypeDef typeDef)
|
||||||
|
{
|
||||||
|
return modifierType <= ComputeModifierType(typeDef.Visibility);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool MatchModifier(ModifierType modifierType, FieldDef fieldDef)
|
||||||
|
{
|
||||||
|
return modifierType <= ComputeModifierType(fieldDef.Access);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool MatchModifier(ModifierType modifierType, MethodDef methodDef)
|
||||||
|
{
|
||||||
|
return modifierType <= ComputeModifierType((FieldAttributes)methodDef.Access);
|
||||||
|
}
|
||||||
|
|
||||||
|
//private bool MatchModifier(ModifierType modifierType, PropertyDef propertyDef)
|
||||||
|
//{
|
||||||
|
// return modifierType <= ComputeModifierType((FieldAttributes)propertyDef.Attributes);
|
||||||
|
//}
|
||||||
|
|
||||||
|
private class MethodComputeCache
|
||||||
|
{
|
||||||
|
public bool obfuscateName = true;
|
||||||
|
public bool obfuscateParam = true;
|
||||||
|
public bool obfuscateBody = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TypeDefComputeCache
|
||||||
|
{
|
||||||
|
public bool obfuscateName = true;
|
||||||
|
public bool obfuscateNamespace = true;
|
||||||
|
|
||||||
|
public readonly Dictionary<MethodDef, MethodComputeCache> methods = new Dictionary<MethodDef, MethodComputeCache>();
|
||||||
|
|
||||||
|
public readonly HashSet<FieldDef> notObfuscatedFields = new HashSet<FieldDef>();
|
||||||
|
|
||||||
|
public readonly HashSet<PropertyDef> notObfuscatedProperties = new HashSet<PropertyDef>();
|
||||||
|
|
||||||
|
public readonly HashSet<EventDef> notObfuscatedEvents = new HashSet<EventDef>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Dictionary<TypeDef, TypeDefComputeCache> _typeRenameCache = new Dictionary<TypeDef, TypeDefComputeCache>();
|
||||||
|
|
||||||
|
private readonly HashSet<string> _obfuscationAssemblyNames;
|
||||||
|
|
||||||
|
public ConfigurableRenamePolicy(List<string> obfuscationAssemblyNames, List<string> xmlFiles)
|
||||||
|
{
|
||||||
|
_obfuscationAssemblyNames = new HashSet<string>(obfuscationAssemblyNames);
|
||||||
|
LoadXmls(xmlFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TypeDefComputeCache GetOrCreateTypeDefRenameComputeCache(TypeDef typeDef)
|
||||||
|
{
|
||||||
|
if (_typeRenameCache.TryGetValue(typeDef, out var cache))
|
||||||
|
{
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
cache = new TypeDefComputeCache();
|
||||||
|
_typeRenameCache.Add(typeDef, cache);
|
||||||
|
|
||||||
|
if (!_assemblyRuleSpecs.TryGetValue(typeDef.Module.Assembly.Name, out var assemblyRuleSpec) || assemblyRuleSpec.rule == null)
|
||||||
|
{
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
string typeName = typeDef.FullName;
|
||||||
|
var totalMethodSpecs = new List<MethodRuleSpec>();
|
||||||
|
var totalMethodSpecFromPropertyAndEvents = new List<(MethodDef, MethodRuleSpec)>();
|
||||||
|
foreach (var typeRule in assemblyRuleSpec.rule.typeRuleSpecs)
|
||||||
|
{
|
||||||
|
if ((typeRule.nameMatcher != null && !typeRule.nameMatcher.IsMatch(typeName)) || !MatchModifier(typeRule.modifierType, typeDef))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
cache.obfuscateNamespace &= typeRule.rule.obfuscateNamespace;
|
||||||
|
cache.obfuscateName &= typeRule.rule.obfuscateName;
|
||||||
|
|
||||||
|
totalMethodSpecs.AddRange(typeRule.rule.methodRuleSpecs);
|
||||||
|
|
||||||
|
foreach (var eventDef in typeDef.Events)
|
||||||
|
{
|
||||||
|
foreach (var eventSpec in typeRule.rule.eventRuleSpecs)
|
||||||
|
{
|
||||||
|
if (eventSpec.nameMatcher != null && !eventSpec.nameMatcher.IsMatch(eventDef.Name))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
EventRule eventRule = eventSpec.rule;
|
||||||
|
if (!eventRule.obfuscateName)
|
||||||
|
{
|
||||||
|
cache.notObfuscatedEvents.Add(eventDef);
|
||||||
|
}
|
||||||
|
if (eventDef.AddMethod != null && eventRule.add != null && MatchModifier(eventRule.add.modifierType, eventDef.AddMethod))
|
||||||
|
{
|
||||||
|
totalMethodSpecFromPropertyAndEvents.Add((eventDef.AddMethod,eventRule.add));
|
||||||
|
}
|
||||||
|
if (eventDef.RemoveMethod != null && eventRule.remove != null && MatchModifier(eventRule.remove.modifierType, eventDef.RemoveMethod))
|
||||||
|
{
|
||||||
|
totalMethodSpecFromPropertyAndEvents.Add((eventDef.RemoveMethod, eventRule.remove));
|
||||||
|
}
|
||||||
|
if (eventDef.InvokeMethod != null && eventRule.fire != null && MatchModifier(eventRule.fire.modifierType, eventDef.InvokeMethod))
|
||||||
|
{
|
||||||
|
totalMethodSpecFromPropertyAndEvents.Add((eventDef.InvokeMethod, eventRule.fire));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var propertyDef in typeDef.Properties)
|
||||||
|
{
|
||||||
|
foreach (var propertySpec in typeRule.rule.propertyRuleSpecs)
|
||||||
|
{
|
||||||
|
if (propertySpec.nameMatcher != null && !propertySpec.nameMatcher.IsMatch(propertyDef.Name))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
PropertyRule propertyRule = propertySpec.rule;
|
||||||
|
if (!propertyRule.obfuscateName)
|
||||||
|
{
|
||||||
|
cache.notObfuscatedProperties.Add(propertyDef);
|
||||||
|
}
|
||||||
|
if (propertyDef.GetMethod != null && propertyRule.getter != null && MatchModifier(propertyRule.getter.modifierType, propertyDef.GetMethod))
|
||||||
|
{
|
||||||
|
totalMethodSpecFromPropertyAndEvents.Add((propertyDef.GetMethod, propertyRule.getter));
|
||||||
|
}
|
||||||
|
if (propertyDef.SetMethod != null && propertyRule.setter != null && MatchModifier(propertyRule.setter.modifierType, propertyDef.SetMethod))
|
||||||
|
{
|
||||||
|
totalMethodSpecFromPropertyAndEvents.Add((propertyDef.SetMethod, propertyRule.setter));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var fieldDef in typeDef.Fields)
|
||||||
|
{
|
||||||
|
foreach (var fieldRule in typeRule.rule.fieldRuleSpecs)
|
||||||
|
{
|
||||||
|
if ((fieldRule.nameMatcher == null || fieldRule.nameMatcher.IsMatch(fieldDef.Name)) && MatchModifier(fieldRule.modifierType, fieldDef) && !fieldRule.rule.obfuscateName)
|
||||||
|
{
|
||||||
|
cache.notObfuscatedFields.Add(fieldDef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (MethodDef methodDef in typeDef.Methods)
|
||||||
|
{
|
||||||
|
foreach (var e in totalMethodSpecFromPropertyAndEvents)
|
||||||
|
{
|
||||||
|
if (e.Item1 != methodDef)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!cache.methods.TryGetValue(methodDef, out var methodCache))
|
||||||
|
{
|
||||||
|
methodCache = new MethodComputeCache();
|
||||||
|
cache.methods.Add(methodDef, methodCache);
|
||||||
|
}
|
||||||
|
MethodRule methodRule = e.Item2.rule;
|
||||||
|
methodCache.obfuscateName &= methodRule.obfuscateName;
|
||||||
|
methodCache.obfuscateParam &= methodRule.obfuscateParam;
|
||||||
|
methodCache.obfuscateBody &= methodRule.obfuscateBody;
|
||||||
|
}
|
||||||
|
foreach (MethodRuleSpec methodSpec in totalMethodSpecs)
|
||||||
|
{
|
||||||
|
if ((methodSpec.nameMatcher != null && !methodSpec.nameMatcher.IsMatch(methodDef.Name)) || !MatchModifier(methodSpec.modifierType, methodDef))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!cache.methods.TryGetValue(methodDef, out var methodCache))
|
||||||
|
{
|
||||||
|
methodCache = new MethodComputeCache();
|
||||||
|
cache.methods.Add(methodDef, methodCache);
|
||||||
|
}
|
||||||
|
MethodRule methodRule = methodSpec.rule;
|
||||||
|
methodCache.obfuscateName &= methodRule.obfuscateName;
|
||||||
|
methodCache.obfuscateParam &= methodRule.obfuscateParam;
|
||||||
|
methodCache.obfuscateBody &= methodRule.obfuscateBody;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedRename(TypeDef typeDef)
|
||||||
|
{
|
||||||
|
TypeDefComputeCache cache = GetOrCreateTypeDefRenameComputeCache(typeDef);
|
||||||
|
return cache.obfuscateName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedRename(MethodDef methodDef)
|
||||||
|
{
|
||||||
|
TypeDef typeDef = methodDef.DeclaringType;
|
||||||
|
TypeDefComputeCache cache = GetOrCreateTypeDefRenameComputeCache(typeDef);
|
||||||
|
if (!cache.methods.TryGetValue(methodDef, out var methodCache))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return methodCache.obfuscateName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedRename(FieldDef fieldDef)
|
||||||
|
{
|
||||||
|
TypeDef typeDef = fieldDef.DeclaringType;
|
||||||
|
TypeDefComputeCache cache = GetOrCreateTypeDefRenameComputeCache(typeDef);
|
||||||
|
return !cache.notObfuscatedFields.Contains(fieldDef);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedRename(PropertyDef propertyDef)
|
||||||
|
{
|
||||||
|
TypeDef typeDef = propertyDef.DeclaringType;
|
||||||
|
TypeDefComputeCache cache = GetOrCreateTypeDefRenameComputeCache(typeDef);
|
||||||
|
return !cache.notObfuscatedProperties.Contains(propertyDef);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedRename(EventDef eventDef)
|
||||||
|
{
|
||||||
|
TypeDef typeDef = eventDef.DeclaringType;
|
||||||
|
TypeDefComputeCache cache = GetOrCreateTypeDefRenameComputeCache(typeDef);
|
||||||
|
return !cache.notObfuscatedEvents.Contains(eventDef);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedRename(ParamDef paramDef)
|
||||||
|
{
|
||||||
|
MethodDef methodDef = paramDef.DeclaringMethod;
|
||||||
|
TypeDef typeDef = methodDef.DeclaringType;
|
||||||
|
TypeDefComputeCache cache = GetOrCreateTypeDefRenameComputeCache(typeDef);
|
||||||
|
if (!cache.methods.TryGetValue(methodDef, out var methodCache))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return methodCache.obfuscateParam;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.SymbolObfus.Policies
|
||||||
|
{
|
||||||
|
public abstract class ObfuscationPolicyBase : IObfuscationPolicy
|
||||||
|
{
|
||||||
|
|
||||||
|
public virtual bool NeedRename(TypeDef typeDef)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool NeedRename(MethodDef methodDef)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool NeedRename(FieldDef fieldDef)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool NeedRename(PropertyDef propertyDef)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool NeedRename(EventDef eventDef)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool NeedRename(ParamDef paramDef)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.SymbolObfus.Policies
|
||||||
|
{
|
||||||
|
internal class SupportPassPolicy : ObfuscationPolicyBase
|
||||||
|
{
|
||||||
|
private readonly ConfigurablePassPolicy _policy;
|
||||||
|
|
||||||
|
|
||||||
|
private bool Support(ObfuscationPassType passType)
|
||||||
|
{
|
||||||
|
return passType.HasFlag(ObfuscationPassType.SymbolObfus);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SupportPassPolicy(ConfigurablePassPolicy policy)
|
||||||
|
{
|
||||||
|
_policy = policy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedRename(TypeDef typeDef)
|
||||||
|
{
|
||||||
|
return Support(_policy.GetTypeObfuscationPasses(typeDef));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedRename(MethodDef methodDef)
|
||||||
|
{
|
||||||
|
return Support(_policy.GetMethodObfuscationPasses(methodDef));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedRename(FieldDef fieldDef)
|
||||||
|
{
|
||||||
|
return Support(_policy.GetFieldObfuscationPasses(fieldDef));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedRename(PropertyDef propertyDef)
|
||||||
|
{
|
||||||
|
return Support(_policy.GetPropertyObfuscationPasses(propertyDef));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedRename(EventDef eventDef)
|
||||||
|
{
|
||||||
|
return Support(_policy.GetEventObfuscationPasses(eventDef));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using Obfuz.Utils;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.SymbolObfus.Policies
|
||||||
|
{
|
||||||
|
public class SystemRenamePolicy : ObfuscationPolicyBase
|
||||||
|
{
|
||||||
|
public override bool NeedRename(TypeDef typeDef)
|
||||||
|
{
|
||||||
|
string name = typeDef.Name;
|
||||||
|
if (name == "<Module>" || name == "ObfuzIgnoreAttribute")
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (MetaUtil.HasObfuzIgnoreAttribute(typeDef))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedRename(MethodDef methodDef)
|
||||||
|
{
|
||||||
|
if (methodDef.Name == ".ctor" || methodDef.Name == ".cctor")
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MetaUtil.HasObfuzIgnoreAttribute(methodDef) || MetaUtil.HasObfuzIgnoreAttribute(methodDef.DeclaringType))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedRename(FieldDef fieldDef)
|
||||||
|
{
|
||||||
|
if (MetaUtil.HasObfuzIgnoreAttribute(fieldDef) || MetaUtil.HasObfuzIgnoreAttribute(fieldDef.DeclaringType))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (fieldDef.DeclaringType.IsEnum && fieldDef.Name == "value__")
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedRename(PropertyDef propertyDef)
|
||||||
|
{
|
||||||
|
if (MetaUtil.HasObfuzIgnoreAttribute(propertyDef) || MetaUtil.HasObfuzIgnoreAttribute(propertyDef.DeclaringType))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedRename(EventDef eventDef)
|
||||||
|
{
|
||||||
|
if (MetaUtil.HasObfuzIgnoreAttribute(eventDef) || MetaUtil.HasObfuzIgnoreAttribute(eventDef.DeclaringType))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using Obfuz.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.SymbolObfus.Policies
|
||||||
|
{
|
||||||
|
|
||||||
|
public class UnityRenamePolicy : ObfuscationPolicyBase
|
||||||
|
{
|
||||||
|
private static HashSet<string> s_monoBehaviourEvents = new HashSet<string> {
|
||||||
|
"Awake",
|
||||||
|
"OnEnable",
|
||||||
|
"Start",
|
||||||
|
"FixedUpdate",
|
||||||
|
"Update",
|
||||||
|
"LateUpdate",
|
||||||
|
"OnDisable",
|
||||||
|
"OnDestroy",
|
||||||
|
"OnApplicationQuit",
|
||||||
|
"OnTriggerEnter",
|
||||||
|
"OnTriggerExit",
|
||||||
|
"OnTriggerStay",
|
||||||
|
"OnCollisionEnter",
|
||||||
|
"OnCollisionExit",
|
||||||
|
"OnCollisionStay",
|
||||||
|
"OnMouseDown",
|
||||||
|
"OnMouseUp",
|
||||||
|
"OnMouseEnter",
|
||||||
|
"OnMouseExit",
|
||||||
|
"OnMouseOver",
|
||||||
|
"OnMouseDrag",
|
||||||
|
"OnBecameVisible",
|
||||||
|
"OnBecameInvisible",
|
||||||
|
"OnGUI",
|
||||||
|
"OnPreRender",
|
||||||
|
"OnPostRender",
|
||||||
|
"OnRenderObject",
|
||||||
|
"OnDrawGizmos",
|
||||||
|
"OnDrawGizmosSelected",
|
||||||
|
"OnValidate",
|
||||||
|
"OnAnimatorIK",
|
||||||
|
"OnAnimatorMove",
|
||||||
|
"OnApplicationFocus",
|
||||||
|
"OnApplicationPause",
|
||||||
|
"OnAudioFilterRead",
|
||||||
|
"OnJointBreak",
|
||||||
|
"OnParticleCollision",
|
||||||
|
"OnTransformChildrenChanged",
|
||||||
|
"OnTransformParentChanged",
|
||||||
|
"OnRectTransformDimensionsChange",
|
||||||
|
"OnWillRenderObject"
|
||||||
|
};
|
||||||
|
public override bool NeedRename(TypeDef typeDef)
|
||||||
|
{
|
||||||
|
if (MetaUtil.IsScriptOrSerializableType(typeDef))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (typeDef.FullName.StartsWith("UnitySourceGeneratedAssemblyMonoScriptTypes_"))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedRename(MethodDef methodDef)
|
||||||
|
{
|
||||||
|
if (MetaUtil.IsInheritFromUnityObject(methodDef.DeclaringType))
|
||||||
|
{
|
||||||
|
return !s_monoBehaviourEvents.Contains(methodDef.Name);
|
||||||
|
}
|
||||||
|
if (methodDef.DeclaringType.FullName.StartsWith("UnitySourceGeneratedAssemblyMonoScriptTypes_"))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedRename(FieldDef fieldDef)
|
||||||
|
{
|
||||||
|
TypeDef typeDef = fieldDef.DeclaringType;
|
||||||
|
if (MetaUtil.IsScriptOrSerializableType(typeDef))
|
||||||
|
{
|
||||||
|
return !MetaUtil.IsSerializableField(fieldDef);
|
||||||
|
}
|
||||||
|
if (fieldDef.DeclaringType.FullName.StartsWith("UnitySourceGeneratedAssemblyMonoScriptTypes_"))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,739 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using Obfuz.Utils;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Xml;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.SymbolObfus
|
||||||
|
{
|
||||||
|
|
||||||
|
public class RenameRecordMap
|
||||||
|
{
|
||||||
|
private enum RenameStatus
|
||||||
|
{
|
||||||
|
NotRenamed,
|
||||||
|
Renamed,
|
||||||
|
}
|
||||||
|
|
||||||
|
private class RenameRecord
|
||||||
|
{
|
||||||
|
public RenameStatus status;
|
||||||
|
public string signature;
|
||||||
|
public string oldName;
|
||||||
|
public string newName;
|
||||||
|
public string oldStackTraceSignature; // only for MethodDef
|
||||||
|
public object renameMappingData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class RenameMappingField
|
||||||
|
{
|
||||||
|
public RenameStatus status;
|
||||||
|
public string signature;
|
||||||
|
public string newName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class RenameMappingMethod
|
||||||
|
{
|
||||||
|
public RenameStatus status;
|
||||||
|
public string signature;
|
||||||
|
public string newName;
|
||||||
|
|
||||||
|
public List<RenameMappingMethodParam> parameters = new List<RenameMappingMethodParam>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class RenameMappingMethodParam
|
||||||
|
{
|
||||||
|
public RenameStatus status;
|
||||||
|
public int index;
|
||||||
|
public string newName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class RenameMappingProperty
|
||||||
|
{
|
||||||
|
public RenameStatus status;
|
||||||
|
public string signature;
|
||||||
|
public string newName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class RenameMappingEvent
|
||||||
|
{
|
||||||
|
public RenameStatus status;
|
||||||
|
public string signature;
|
||||||
|
public string newName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class RenameMappingType
|
||||||
|
{
|
||||||
|
public RenameStatus status;
|
||||||
|
public string oldFullName;
|
||||||
|
public string newFullName;
|
||||||
|
|
||||||
|
public Dictionary<string, RenameMappingField> fields = new Dictionary<string, RenameMappingField>();
|
||||||
|
public Dictionary<string, RenameMappingMethod> methods = new Dictionary<string, RenameMappingMethod>();
|
||||||
|
public Dictionary<string, RenameMappingProperty> properties = new Dictionary<string, RenameMappingProperty>();
|
||||||
|
public Dictionary<string, RenameMappingEvent> events = new Dictionary<string, RenameMappingEvent>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class RenameMappingAssembly
|
||||||
|
{
|
||||||
|
public string assName;
|
||||||
|
|
||||||
|
public Dictionary<string, RenameMappingType> types = new Dictionary<string, RenameMappingType>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly string _mappingFile;
|
||||||
|
private readonly Dictionary<string, RenameMappingAssembly> _assemblies = new Dictionary<string, RenameMappingAssembly>();
|
||||||
|
|
||||||
|
|
||||||
|
private readonly Dictionary<ModuleDef, RenameRecord> _modRenames = new Dictionary<ModuleDef, RenameRecord>();
|
||||||
|
private readonly Dictionary<TypeDef, RenameRecord> _typeRenames = new Dictionary<TypeDef, RenameRecord>();
|
||||||
|
private readonly Dictionary<MethodDef, RenameRecord> _methodRenames = new Dictionary<MethodDef, RenameRecord>();
|
||||||
|
private readonly Dictionary<ParamDef, RenameRecord> _paramRenames = new Dictionary<ParamDef, RenameRecord>();
|
||||||
|
private readonly Dictionary<FieldDef, RenameRecord> _fieldRenames = new Dictionary<FieldDef, RenameRecord>();
|
||||||
|
private readonly Dictionary<PropertyDef, RenameRecord> _propertyRenames = new Dictionary<PropertyDef, RenameRecord>();
|
||||||
|
private readonly Dictionary<EventDef, RenameRecord> _eventRenames = new Dictionary<EventDef, RenameRecord>();
|
||||||
|
private readonly Dictionary<VirtualMethodGroup, RenameRecord> _virtualMethodGroups = new Dictionary<VirtualMethodGroup, RenameRecord>();
|
||||||
|
|
||||||
|
|
||||||
|
public RenameRecordMap(string mappingFile)
|
||||||
|
{
|
||||||
|
_mappingFile = mappingFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Init(List<ModuleDef> assemblies, INameMaker nameMaker)
|
||||||
|
{
|
||||||
|
LoadXmlMappingFile(_mappingFile);
|
||||||
|
foreach (ModuleDef mod in assemblies)
|
||||||
|
{
|
||||||
|
string name = mod.Assembly.Name;
|
||||||
|
|
||||||
|
RenameMappingAssembly rma = _assemblies.GetValueOrDefault(name);
|
||||||
|
|
||||||
|
_modRenames.Add(mod, new RenameRecord
|
||||||
|
{
|
||||||
|
status = RenameStatus.NotRenamed,
|
||||||
|
signature = name,
|
||||||
|
oldName = name,
|
||||||
|
newName = null,
|
||||||
|
renameMappingData = rma,
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach (TypeDef type in mod.GetTypes())
|
||||||
|
{
|
||||||
|
nameMaker.AddPreservedName(type, name);
|
||||||
|
nameMaker.AddPreservedNamespace(type, type.Namespace);
|
||||||
|
string fullTypeName = type.FullName;
|
||||||
|
RenameMappingType rmt = rma?.types.GetValueOrDefault(fullTypeName);
|
||||||
|
if (rmt != null)
|
||||||
|
{
|
||||||
|
var (newNamespace, newName) = MetaUtil.SplitNamespaceAndName(rmt.newFullName);
|
||||||
|
nameMaker.AddPreservedNamespace(type, newNamespace);
|
||||||
|
nameMaker.AddPreservedName(type, newName);
|
||||||
|
}
|
||||||
|
|
||||||
|
_typeRenames.Add(type, new RenameRecord
|
||||||
|
{
|
||||||
|
status = RenameStatus.NotRenamed,
|
||||||
|
signature = fullTypeName,
|
||||||
|
oldName = fullTypeName,
|
||||||
|
newName = null,
|
||||||
|
renameMappingData = rmt,
|
||||||
|
});
|
||||||
|
foreach (MethodDef method in type.Methods)
|
||||||
|
{
|
||||||
|
nameMaker.AddPreservedName(method, method.Name);
|
||||||
|
string methodSig = TypeSigUtil.ComputeMethodDefSignature(method);
|
||||||
|
nameMaker.AddPreservedName(method, method.Name);
|
||||||
|
|
||||||
|
RenameMappingMethod rmm = rmt?.methods.GetValueOrDefault(methodSig);
|
||||||
|
if (rmm != null)
|
||||||
|
{
|
||||||
|
nameMaker.AddPreservedName(method, rmm.newName);
|
||||||
|
}
|
||||||
|
_methodRenames.Add(method, new RenameRecord
|
||||||
|
{
|
||||||
|
status = RenameStatus.NotRenamed,
|
||||||
|
signature = methodSig,
|
||||||
|
oldName = method.Name,
|
||||||
|
newName = null,
|
||||||
|
renameMappingData = rmm,
|
||||||
|
oldStackTraceSignature = MetaUtil.CreateMethodDefIl2CppStackTraceSignature(method),
|
||||||
|
});
|
||||||
|
foreach (Parameter param in method.Parameters)
|
||||||
|
{
|
||||||
|
if (param.ParamDef != null)
|
||||||
|
{
|
||||||
|
_paramRenames.Add(param.ParamDef, new RenameRecord
|
||||||
|
{
|
||||||
|
status = RenameStatus.NotRenamed,
|
||||||
|
signature = param.Name,
|
||||||
|
oldName = param.Name,
|
||||||
|
newName = null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (FieldDef field in type.Fields)
|
||||||
|
{
|
||||||
|
nameMaker.AddPreservedName(field, field.Name);
|
||||||
|
string fieldSig = TypeSigUtil.ComputeFieldDefSignature(field);
|
||||||
|
RenameMappingField rmf = rmt?.fields.GetValueOrDefault(fieldSig);
|
||||||
|
if (rmf != null)
|
||||||
|
{
|
||||||
|
nameMaker.AddPreservedName(field, rmf.newName);
|
||||||
|
}
|
||||||
|
_fieldRenames.Add(field, new RenameRecord
|
||||||
|
{
|
||||||
|
status = RenameStatus.NotRenamed,
|
||||||
|
signature = fieldSig,
|
||||||
|
oldName = field.Name,
|
||||||
|
newName = null,
|
||||||
|
renameMappingData = rmf,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
foreach (PropertyDef property in type.Properties)
|
||||||
|
{
|
||||||
|
nameMaker.AddPreservedName(property, property.Name);
|
||||||
|
string propertySig = TypeSigUtil.ComputePropertyDefSignature(property);
|
||||||
|
RenameMappingProperty rmp = rmt?.properties.GetValueOrDefault(propertySig);
|
||||||
|
if (rmp != null)
|
||||||
|
{
|
||||||
|
nameMaker.AddPreservedName(property, rmp.newName);
|
||||||
|
}
|
||||||
|
_propertyRenames.Add(property, new RenameRecord
|
||||||
|
{
|
||||||
|
status = RenameStatus.NotRenamed,
|
||||||
|
signature = propertySig,
|
||||||
|
oldName = property.Name,
|
||||||
|
newName = null,
|
||||||
|
renameMappingData = rmp,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
foreach (EventDef eventDef in type.Events)
|
||||||
|
{
|
||||||
|
nameMaker.AddPreservedName(eventDef, eventDef.Name);
|
||||||
|
string eventSig = TypeSigUtil.ComputeEventDefSignature(eventDef);
|
||||||
|
RenameMappingEvent rme = rmt?.events.GetValueOrDefault(eventSig);
|
||||||
|
if (rme != null)
|
||||||
|
{
|
||||||
|
nameMaker.AddPreservedName(eventDef, rme.newName);
|
||||||
|
}
|
||||||
|
_eventRenames.Add(eventDef, new RenameRecord
|
||||||
|
{
|
||||||
|
status = RenameStatus.NotRenamed,
|
||||||
|
signature = eventSig,
|
||||||
|
oldName = eventDef.Name,
|
||||||
|
newName = null,
|
||||||
|
renameMappingData = rme,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadXmlMappingFile(string mappingFile)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(mappingFile) || !File.Exists(mappingFile))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
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'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var assemblyName = ele.Attributes["name"].Value;
|
||||||
|
var rma = new RenameMappingAssembly
|
||||||
|
{
|
||||||
|
assName = assemblyName,
|
||||||
|
};
|
||||||
|
foreach (XmlNode node in ele.ChildNodes)
|
||||||
|
{
|
||||||
|
if (!(node is XmlElement element))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (element.Name != "type")
|
||||||
|
{
|
||||||
|
throw new System.Exception($"Invalid node name: {element.Name}. Expected 'type'.");
|
||||||
|
}
|
||||||
|
LoadTypeMapping(element, rma);
|
||||||
|
}
|
||||||
|
_assemblies.Add(assemblyName, rma);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadTypeMapping(XmlElement ele, RenameMappingAssembly ass)
|
||||||
|
{
|
||||||
|
var typeName = ele.Attributes["fullName"].Value;
|
||||||
|
var newTypeName = ele.Attributes["newFullName"].Value;
|
||||||
|
var rmt = new RenameMappingType
|
||||||
|
{
|
||||||
|
oldFullName = typeName,
|
||||||
|
newFullName = newTypeName,
|
||||||
|
status = (RenameStatus)System.Enum.Parse(typeof(RenameStatus), ele.Attributes["status"].Value),
|
||||||
|
};
|
||||||
|
foreach (XmlNode node in ele.ChildNodes)
|
||||||
|
{
|
||||||
|
if (!(node is XmlElement c))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (node.Name)
|
||||||
|
{
|
||||||
|
case "field": LoadFieldMapping(c, rmt); break;
|
||||||
|
case "event": LoadEventMapping(c, rmt); break;
|
||||||
|
case "property": LoadPropertyMapping(c, rmt); break;
|
||||||
|
case "method": LoadMethodMapping(c, rmt); break;
|
||||||
|
default: throw new System.Exception($"Invalid node name:{node.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ass.types.Add(typeName, rmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadMethodMapping(XmlElement ele, RenameMappingType type)
|
||||||
|
{
|
||||||
|
string signature = ele.Attributes["signature"].Value;
|
||||||
|
string newName = ele.Attributes["newName"].Value;
|
||||||
|
var rmm = new RenameMappingMethod
|
||||||
|
{
|
||||||
|
signature = signature,
|
||||||
|
newName = newName,
|
||||||
|
status = RenameStatus.Renamed,
|
||||||
|
};
|
||||||
|
foreach (XmlNode node in ele.ChildNodes)
|
||||||
|
{
|
||||||
|
if (!(node is XmlElement c))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (node.Name)
|
||||||
|
{
|
||||||
|
case "param": LoadMethodParamMapping(c, rmm); break;
|
||||||
|
default: throw new System.Exception($"unknown node name:{node.Name}, expect 'param'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type.methods.Add(signature, rmm);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadMethodParamMapping(XmlElement ele, RenameMappingMethod method)
|
||||||
|
{
|
||||||
|
string index = ele.Attributes["index"].Value;
|
||||||
|
string newName = ele.Attributes["newName"].Value;
|
||||||
|
var rmp = new RenameMappingMethodParam
|
||||||
|
{
|
||||||
|
index = int.Parse(index),
|
||||||
|
newName = newName,
|
||||||
|
status = RenameStatus.Renamed,
|
||||||
|
};
|
||||||
|
method.parameters.Add(rmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadFieldMapping(XmlElement ele, RenameMappingType type)
|
||||||
|
{
|
||||||
|
string signature = ele.Attributes["signature"].Value;
|
||||||
|
string newName = ele.Attributes["newName"].Value;
|
||||||
|
var rmf = new RenameMappingField
|
||||||
|
{
|
||||||
|
signature = signature,
|
||||||
|
newName = newName,
|
||||||
|
status = RenameStatus.Renamed,
|
||||||
|
};
|
||||||
|
type.fields.Add(signature, rmf);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadPropertyMapping(XmlElement ele, RenameMappingType type)
|
||||||
|
{
|
||||||
|
string signature = ele.Attributes["signature"].Value;
|
||||||
|
string newName = ele.Attributes["newName"].Value;
|
||||||
|
var rmp = new RenameMappingProperty
|
||||||
|
{
|
||||||
|
signature = signature,
|
||||||
|
newName = newName,
|
||||||
|
status = RenameStatus.Renamed,
|
||||||
|
};
|
||||||
|
type.properties.Add(signature, rmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadEventMapping(XmlElement ele, RenameMappingType type)
|
||||||
|
{
|
||||||
|
string signature = ele.Attributes["signature"].Value;
|
||||||
|
string newName = ele.Attributes["newName"].Value;
|
||||||
|
var rme = new RenameMappingEvent
|
||||||
|
{
|
||||||
|
signature = signature,
|
||||||
|
newName = newName,
|
||||||
|
status = RenameStatus.Renamed,
|
||||||
|
};
|
||||||
|
type.events.Add(signature, rme);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteXmlMappingFile()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(_mappingFile))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var doc = new XmlDocument();
|
||||||
|
var root = doc.CreateElement("mapping");
|
||||||
|
doc.AppendChild(root);
|
||||||
|
foreach (var kvp in _modRenames)
|
||||||
|
{
|
||||||
|
ModuleDef mod = kvp.Key;
|
||||||
|
RenameRecord record = kvp.Value;
|
||||||
|
var assemblyNode = doc.CreateElement("assembly");
|
||||||
|
assemblyNode.SetAttribute("name", mod.Assembly.Name);
|
||||||
|
foreach (TypeDef type in mod.GetTypes())
|
||||||
|
{
|
||||||
|
WriteTypeMapping(assemblyNode, type);
|
||||||
|
}
|
||||||
|
root.AppendChild(assemblyNode);
|
||||||
|
}
|
||||||
|
foreach (RenameMappingAssembly ass in _assemblies.Values)
|
||||||
|
{
|
||||||
|
if (_modRenames.Keys.Any(m => m.Assembly.Name == ass.assName))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var assemblyNode = doc.CreateElement("assembly");
|
||||||
|
assemblyNode.SetAttribute("name", ass.assName);
|
||||||
|
foreach (var e in ass.types)
|
||||||
|
{
|
||||||
|
WriteTypeMapping(assemblyNode, e.Key, e.Value);
|
||||||
|
}
|
||||||
|
root.AppendChild(assemblyNode);
|
||||||
|
}
|
||||||
|
Directory.CreateDirectory(Path.GetDirectoryName(_mappingFile));
|
||||||
|
doc.Save(_mappingFile);
|
||||||
|
Debug.Log($"Mapping file saved to {Path.GetFullPath(_mappingFile)}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteTypeMapping(XmlElement assNode, TypeDef type)
|
||||||
|
{
|
||||||
|
_typeRenames.TryGetValue(type, out var record);
|
||||||
|
var typeNode = assNode.OwnerDocument.CreateElement("type");
|
||||||
|
typeNode.SetAttribute("fullName", record?.signature ?? type.FullName);
|
||||||
|
typeNode.SetAttribute("newFullName", record != null && record.status == RenameStatus.Renamed ? record.newName : "");
|
||||||
|
typeNode.SetAttribute("status", record != null ? record.status.ToString() : RenameStatus.NotRenamed.ToString());
|
||||||
|
|
||||||
|
foreach (FieldDef field in type.Fields)
|
||||||
|
{
|
||||||
|
WriteFieldMapping(typeNode, field);
|
||||||
|
}
|
||||||
|
foreach (PropertyDef property in type.Properties)
|
||||||
|
{
|
||||||
|
WritePropertyMapping(typeNode, property);
|
||||||
|
}
|
||||||
|
foreach (EventDef eventDef in type.Events)
|
||||||
|
{
|
||||||
|
WriteEventMapping(typeNode, eventDef);
|
||||||
|
}
|
||||||
|
foreach (MethodDef method in type.Methods)
|
||||||
|
{
|
||||||
|
WriteMethodMapping(typeNode, method);
|
||||||
|
}
|
||||||
|
if ((record != null && record.status == RenameStatus.Renamed) || typeNode.ChildNodes.Count > 0)
|
||||||
|
{
|
||||||
|
assNode.AppendChild(typeNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteTypeMapping(XmlElement assNode, string fullName, RenameMappingType type)
|
||||||
|
{
|
||||||
|
var typeNode = assNode.OwnerDocument.CreateElement("type");
|
||||||
|
typeNode.SetAttribute("fullName", fullName);
|
||||||
|
typeNode.SetAttribute("newFullName", type.status == RenameStatus.Renamed ? type.newFullName : "");
|
||||||
|
typeNode.SetAttribute("status", type.status.ToString());
|
||||||
|
|
||||||
|
foreach (var e in type.fields)
|
||||||
|
{
|
||||||
|
string signature = e.Key;
|
||||||
|
RenameMappingField field = e.Value;
|
||||||
|
WriteFieldMapping(typeNode, e.Key, e.Value);
|
||||||
|
}
|
||||||
|
foreach (var e in type.properties)
|
||||||
|
{
|
||||||
|
WritePropertyMapping(typeNode, e.Key, e.Value);
|
||||||
|
}
|
||||||
|
foreach (var e in type.events)
|
||||||
|
{
|
||||||
|
WriteEventMapping(typeNode, e.Key, e.Value);
|
||||||
|
}
|
||||||
|
foreach (var e in type.methods)
|
||||||
|
{
|
||||||
|
WriteMethodMapping(typeNode, e.Key, e.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
assNode.AppendChild(typeNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteFieldMapping(XmlElement typeEle, FieldDef field)
|
||||||
|
{
|
||||||
|
if (!_fieldRenames.TryGetValue(field, out var record) || record.status == RenameStatus.NotRenamed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var fieldNode = typeEle.OwnerDocument.CreateElement("field");
|
||||||
|
fieldNode.SetAttribute("signature", record?.signature);
|
||||||
|
fieldNode.SetAttribute("newName", record.newName);
|
||||||
|
//fieldNode.SetAttribute("status", record.status.ToString());
|
||||||
|
typeEle.AppendChild(fieldNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteFieldMapping(XmlElement typeEle, string signature, RenameMappingField field)
|
||||||
|
{
|
||||||
|
var fieldNode = typeEle.OwnerDocument.CreateElement("field");
|
||||||
|
fieldNode.SetAttribute("signature", signature);
|
||||||
|
fieldNode.SetAttribute("newName", field.newName);
|
||||||
|
//fieldNode.SetAttribute("status", record.status.ToString());
|
||||||
|
typeEle.AppendChild(fieldNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WritePropertyMapping(XmlElement typeEle, PropertyDef property)
|
||||||
|
{
|
||||||
|
if (!_propertyRenames.TryGetValue(property, out var record) || record.status == RenameStatus.NotRenamed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var propertyNode = typeEle.OwnerDocument.CreateElement("property");
|
||||||
|
propertyNode.SetAttribute("signature", record.signature);
|
||||||
|
propertyNode.SetAttribute("newName", record.newName);
|
||||||
|
//propertyNode.SetAttribute("status", record.status.ToString());
|
||||||
|
typeEle.AppendChild(propertyNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WritePropertyMapping(XmlElement typeEle, string signature, RenameMappingProperty property)
|
||||||
|
{
|
||||||
|
var propertyNode = typeEle.OwnerDocument.CreateElement("property");
|
||||||
|
propertyNode.SetAttribute("signature", signature);
|
||||||
|
propertyNode.SetAttribute("newName", property.newName);
|
||||||
|
//propertyNode.SetAttribute("status", record.status.ToString());
|
||||||
|
typeEle.AppendChild(propertyNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteEventMapping(XmlElement typeEle, EventDef eventDef)
|
||||||
|
{
|
||||||
|
if (!_eventRenames.TryGetValue(eventDef, out var record) || record.status == RenameStatus.NotRenamed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var eventNode = typeEle.OwnerDocument.CreateElement("event");
|
||||||
|
eventNode.SetAttribute("signature", record.signature);
|
||||||
|
eventNode.SetAttribute("newName", record.newName);
|
||||||
|
typeEle.AppendChild(eventNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteEventMapping(XmlElement typeEle, string signature, RenameMappingEvent eventDef)
|
||||||
|
{
|
||||||
|
var eventNode = typeEle.OwnerDocument.CreateElement("event");
|
||||||
|
eventNode.SetAttribute("signature", signature);
|
||||||
|
eventNode.SetAttribute("newName", eventDef.newName);
|
||||||
|
typeEle.AppendChild(eventNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteMethodMapping(XmlElement typeEle, MethodDef method)
|
||||||
|
{
|
||||||
|
if (!_methodRenames.TryGetValue(method, out var record) || record.status == RenameStatus.NotRenamed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var methodNode = typeEle.OwnerDocument.CreateElement("method");
|
||||||
|
methodNode.SetAttribute("signature", record.signature);
|
||||||
|
methodNode.SetAttribute("newName", record.newName);
|
||||||
|
methodNode.SetAttribute("oldStackTraceSignature", record.oldStackTraceSignature);
|
||||||
|
methodNode.SetAttribute("newStackTraceSignature", MetaUtil.CreateMethodDefIl2CppStackTraceSignature(method));
|
||||||
|
//methodNode.SetAttribute("status", record != null ? record.status.ToString() : RenameStatus.NotRenamed.ToString());
|
||||||
|
foreach (Parameter param in method.Parameters)
|
||||||
|
{
|
||||||
|
if (param.ParamDef != null)
|
||||||
|
{
|
||||||
|
WriteMethodParamMapping(methodNode, param.ParamDef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
typeEle.AppendChild(methodNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteMethodMapping(XmlElement typeEle, string signature, RenameMappingMethod method)
|
||||||
|
{
|
||||||
|
var methodNode = typeEle.OwnerDocument.CreateElement("method");
|
||||||
|
methodNode.SetAttribute("signature", signature);
|
||||||
|
methodNode.SetAttribute("newName", method.newName);
|
||||||
|
//methodNode.SetAttribute("status", record != null ? record.status.ToString() : RenameStatus.NotRenamed.ToString());
|
||||||
|
foreach (RenameMappingMethodParam param in method.parameters)
|
||||||
|
{
|
||||||
|
WriteMethodParamMapping(methodNode, param);
|
||||||
|
}
|
||||||
|
typeEle.AppendChild(methodNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteMethodParamMapping(XmlElement methodEle, ParamDef param)
|
||||||
|
{
|
||||||
|
if (!_paramRenames.TryGetValue(param, out var record) || record.status == RenameStatus.NotRenamed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var paramNode = methodEle.OwnerDocument.CreateElement("param");
|
||||||
|
paramNode.SetAttribute("index", param.Sequence.ToString());
|
||||||
|
paramNode.SetAttribute("newName", record.newName);
|
||||||
|
//paramNode.SetAttribute("status", record.status.ToString());
|
||||||
|
methodEle.AppendChild(paramNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteMethodParamMapping(XmlElement methodEle, RenameMappingMethodParam param)
|
||||||
|
{
|
||||||
|
var paramNode = methodEle.OwnerDocument.CreateElement("param");
|
||||||
|
paramNode.SetAttribute("index", param.index.ToString());
|
||||||
|
paramNode.SetAttribute("newName", param.newName);
|
||||||
|
//paramNode.SetAttribute("status", record.status.ToString());
|
||||||
|
methodEle.AppendChild(paramNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddRename(ModuleDef mod, string newName)
|
||||||
|
{
|
||||||
|
RenameRecord record = _modRenames[mod];
|
||||||
|
record.status = RenameStatus.Renamed;
|
||||||
|
record.newName = newName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddRename(TypeDef type, string newName)
|
||||||
|
{
|
||||||
|
RenameRecord record = _typeRenames[type];
|
||||||
|
record.status = RenameStatus.Renamed;
|
||||||
|
record.newName = newName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddRename(MethodDef method, string newName)
|
||||||
|
{
|
||||||
|
RenameRecord record = _methodRenames[method];
|
||||||
|
record.status = RenameStatus.Renamed;
|
||||||
|
record.newName = newName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddRename(ParamDef paramDef, string newName)
|
||||||
|
{
|
||||||
|
RenameRecord record = _paramRenames[paramDef];
|
||||||
|
record.status = RenameStatus.Renamed;
|
||||||
|
record.newName = newName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InitAndAddRename(VirtualMethodGroup methodGroup, string newName)
|
||||||
|
{
|
||||||
|
RenameRecord methodRecord = _methodRenames[methodGroup.methods[0]];
|
||||||
|
_virtualMethodGroups.Add(methodGroup, new RenameRecord
|
||||||
|
{
|
||||||
|
status = RenameStatus.Renamed,
|
||||||
|
signature = methodRecord.signature,
|
||||||
|
oldName = methodRecord.oldName,
|
||||||
|
newName = newName,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddRename(FieldDef field, string newName)
|
||||||
|
{
|
||||||
|
RenameRecord record = _fieldRenames[field];
|
||||||
|
record.status = RenameStatus.Renamed;
|
||||||
|
record.newName = newName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddRename(PropertyDef property, string newName)
|
||||||
|
{
|
||||||
|
RenameRecord record = _propertyRenames[property];
|
||||||
|
record.status = RenameStatus.Renamed;
|
||||||
|
record.newName = newName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddRename(EventDef eventDef, string newName)
|
||||||
|
{
|
||||||
|
RenameRecord record = _eventRenames[eventDef];
|
||||||
|
record.status = RenameStatus.Renamed;
|
||||||
|
record.newName = newName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetExistRenameMapping(TypeDef type, out string newNamespace, out string newName)
|
||||||
|
{
|
||||||
|
if (_typeRenames.TryGetValue(type, out var record) && record.renameMappingData != null)
|
||||||
|
{
|
||||||
|
var rmt = (RenameMappingType)record.renameMappingData;
|
||||||
|
(newNamespace, newName) = MetaUtil.SplitNamespaceAndName(rmt.newFullName);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
newNamespace = null;
|
||||||
|
newName = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetExistRenameMapping(MethodDef method, out string newName)
|
||||||
|
{
|
||||||
|
if (_methodRenames.TryGetValue(method, out var record) && record.renameMappingData != null)
|
||||||
|
{
|
||||||
|
newName = ((RenameMappingMethod)record.renameMappingData).newName;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
newName = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetExistRenameMapping(FieldDef field, out string newName)
|
||||||
|
{
|
||||||
|
if (_fieldRenames.TryGetValue(field, out var record) && record.renameMappingData != null)
|
||||||
|
{
|
||||||
|
newName = ((RenameMappingField)record.renameMappingData).newName;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
newName = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetExistRenameMapping(PropertyDef property, out string newName)
|
||||||
|
{
|
||||||
|
if (_propertyRenames.TryGetValue(property, out var record) && record.renameMappingData != null)
|
||||||
|
{
|
||||||
|
newName = ((RenameMappingProperty)record.renameMappingData).newName;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
newName = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetExistRenameMapping(EventDef eventDef, out string newName)
|
||||||
|
{
|
||||||
|
if (_eventRenames.TryGetValue(eventDef, out var record) && record.renameMappingData != null)
|
||||||
|
{
|
||||||
|
newName = ((RenameMappingEvent)record.renameMappingData).newName;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
newName = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetRename(VirtualMethodGroup group, out string newName)
|
||||||
|
{
|
||||||
|
if (_virtualMethodGroups.TryGetValue(group, out var record))
|
||||||
|
{
|
||||||
|
newName = record.newName;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
newName = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
using Obfuz.Settings;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.SymbolObfus
|
||||||
|
{
|
||||||
|
public class SymbolObfusPass : ObfuscationPassBase
|
||||||
|
{
|
||||||
|
private SymbolRename _symbolRename;
|
||||||
|
|
||||||
|
public override ObfuscationPassType Type => ObfuscationPassType.SymbolObfus;
|
||||||
|
|
||||||
|
public SymbolObfusPass(SymbolObfuscationSettings settings)
|
||||||
|
{
|
||||||
|
_symbolRename = new SymbolRename(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Start()
|
||||||
|
{
|
||||||
|
_symbolRename.Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Stop()
|
||||||
|
{
|
||||||
|
_symbolRename.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Process()
|
||||||
|
{
|
||||||
|
_symbolRename.Process();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,774 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using Obfuz.ObfusPasses.SymbolObfus;
|
||||||
|
using Obfuz.ObfusPasses.SymbolObfus.NameMakers;
|
||||||
|
using Obfuz.ObfusPasses.SymbolObfus.Policies;
|
||||||
|
using Obfuz.Settings;
|
||||||
|
using Obfuz.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data.OleDb;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using UnityEditor.SceneManagement;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Assertions;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.SymbolObfus
|
||||||
|
{
|
||||||
|
public class SymbolRename
|
||||||
|
{
|
||||||
|
class AssemblyReferenceInfo
|
||||||
|
{
|
||||||
|
public string name;
|
||||||
|
|
||||||
|
public bool needObfuscated;
|
||||||
|
|
||||||
|
public ModuleDef module;
|
||||||
|
|
||||||
|
public List<AssemblyReferenceInfo> referenceMeAssemblies;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly bool _useConsistentNamespaceObfuscation;
|
||||||
|
private readonly List<string> _obfuscationRuleFiles;
|
||||||
|
private readonly string _mappingXmlPath;
|
||||||
|
|
||||||
|
private AssemblyCache _assemblyCache;
|
||||||
|
|
||||||
|
private List<ModuleDef> _toObfuscatedModules;
|
||||||
|
private List<ModuleDef> _obfuscatedAndNotObfuscatedModules;
|
||||||
|
private HashSet<ModuleDef> _toObfuscatedModuleSet;
|
||||||
|
private IObfuscationPolicy _renamePolicy;
|
||||||
|
private INameMaker _nameMaker;
|
||||||
|
private readonly Dictionary<ModuleDef, List<CustomAttributeInfo>> _customAttributeArgumentsWithTypeByMods = new Dictionary<ModuleDef, List<CustomAttributeInfo>>();
|
||||||
|
private readonly RenameRecordMap _renameRecordMap;
|
||||||
|
private readonly VirtualMethodGroupCalculator _virtualMethodGroupCalculator;
|
||||||
|
|
||||||
|
class CustomAttributeInfo
|
||||||
|
{
|
||||||
|
public CustomAttributeCollection customAttributes;
|
||||||
|
public int index;
|
||||||
|
public List<CAArgument> arguments;
|
||||||
|
public List<CANamedArgument> namedArguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SymbolRename(SymbolObfuscationSettings settings)
|
||||||
|
{
|
||||||
|
_useConsistentNamespaceObfuscation = settings.useConsistentNamespaceObfuscation;
|
||||||
|
_mappingXmlPath = settings.symbolMappingFile;
|
||||||
|
_obfuscationRuleFiles = settings.ruleFiles.ToList();
|
||||||
|
_renameRecordMap = new RenameRecordMap(settings.debug ? null : settings.symbolMappingFile);
|
||||||
|
_virtualMethodGroupCalculator = new VirtualMethodGroupCalculator();
|
||||||
|
_nameMaker = settings.debug ? NameMakerFactory.CreateDebugNameMaker() : NameMakerFactory.CreateNameMakerBaseASCIICharSet(settings.obfuscatedNamePrefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Init()
|
||||||
|
{
|
||||||
|
var ctx = ObfuscationPassContext.Current;
|
||||||
|
_assemblyCache = ctx.assemblyCache;
|
||||||
|
_toObfuscatedModules = ctx.modulesToObfuscate;
|
||||||
|
_obfuscatedAndNotObfuscatedModules = ctx.allObfuscationRelativeModules;
|
||||||
|
_toObfuscatedModuleSet = new HashSet<ModuleDef>(ctx.modulesToObfuscate);
|
||||||
|
var obfuscateRuleConfig = new ConfigurableRenamePolicy(ctx.assembliesToObfuscate, _obfuscationRuleFiles);
|
||||||
|
_renamePolicy = new CacheRenamePolicy(new CombineRenamePolicy(new SupportPassPolicy(ctx.passPolicy), new SystemRenamePolicy(), new UnityRenamePolicy(), obfuscateRuleConfig));
|
||||||
|
BuildCustomAttributeArguments();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CollectCArgumentWithTypeOf(IHasCustomAttribute meta, List<CustomAttributeInfo> customAttributes)
|
||||||
|
{
|
||||||
|
int index = 0;
|
||||||
|
foreach (CustomAttribute ca in meta.CustomAttributes)
|
||||||
|
{
|
||||||
|
List<CAArgument> arguments = null;
|
||||||
|
if (ca.ConstructorArguments.Any(a => MetaUtil.MayRenameCustomDataType(a.Type.ElementType)))
|
||||||
|
{
|
||||||
|
arguments = ca.ConstructorArguments.ToList();
|
||||||
|
}
|
||||||
|
List<CANamedArgument> namedArguments = null;
|
||||||
|
if (ca.NamedArguments.Any(a => MetaUtil.MayRenameCustomDataType(a.Type.ElementType)))
|
||||||
|
{
|
||||||
|
namedArguments = ca.NamedArguments.ToList();
|
||||||
|
}
|
||||||
|
if (arguments != null | namedArguments != null)
|
||||||
|
{
|
||||||
|
customAttributes.Add(new CustomAttributeInfo
|
||||||
|
{
|
||||||
|
customAttributes = meta.CustomAttributes,
|
||||||
|
index = index,
|
||||||
|
arguments = arguments,
|
||||||
|
namedArguments = namedArguments
|
||||||
|
});
|
||||||
|
}
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BuildCustomAttributeArguments()
|
||||||
|
{
|
||||||
|
foreach (ModuleDef mod in _obfuscatedAndNotObfuscatedModules)
|
||||||
|
{
|
||||||
|
var customAttributes = new List<CustomAttributeInfo>();
|
||||||
|
CollectCArgumentWithTypeOf(mod, customAttributes);
|
||||||
|
foreach (TypeDef type in mod.GetTypes())
|
||||||
|
{
|
||||||
|
CollectCArgumentWithTypeOf(type, customAttributes);
|
||||||
|
foreach (FieldDef field in type.Fields)
|
||||||
|
{
|
||||||
|
CollectCArgumentWithTypeOf(field, customAttributes);
|
||||||
|
}
|
||||||
|
foreach (MethodDef method in type.Methods)
|
||||||
|
{
|
||||||
|
CollectCArgumentWithTypeOf(method, customAttributes);
|
||||||
|
foreach (Parameter param in method.Parameters)
|
||||||
|
{
|
||||||
|
if (param.ParamDef != null)
|
||||||
|
{
|
||||||
|
CollectCArgumentWithTypeOf(param.ParamDef, customAttributes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (PropertyDef property in type.Properties)
|
||||||
|
{
|
||||||
|
CollectCArgumentWithTypeOf(property, customAttributes);
|
||||||
|
}
|
||||||
|
foreach (EventDef eventDef in type.Events)
|
||||||
|
{
|
||||||
|
CollectCArgumentWithTypeOf (eventDef, customAttributes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_customAttributeArgumentsWithTypeByMods.Add(mod, customAttributes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Process()
|
||||||
|
{
|
||||||
|
_renameRecordMap.Init(_toObfuscatedModules, _nameMaker);
|
||||||
|
|
||||||
|
RenameTypes();
|
||||||
|
RenameFields();
|
||||||
|
RenameMethods();
|
||||||
|
RenameProperties();
|
||||||
|
RenameEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
class RefTypeDefMetas
|
||||||
|
{
|
||||||
|
public readonly List<TypeRef> typeRefs = new List<TypeRef>();
|
||||||
|
|
||||||
|
public readonly List<CustomAttribute> customAttributes = new List<CustomAttribute>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BuildRefTypeDefMetasMap(Dictionary<TypeDef, RefTypeDefMetas> refTypeDefMetasMap)
|
||||||
|
{
|
||||||
|
foreach (ModuleDef mod in _obfuscatedAndNotObfuscatedModules)
|
||||||
|
{
|
||||||
|
foreach (TypeRef typeRef in mod.GetTypeRefs())
|
||||||
|
{
|
||||||
|
if (typeRef.DefinitionAssembly.IsCorLib())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
TypeDef typeDef = typeRef.ResolveThrow();
|
||||||
|
if (!refTypeDefMetasMap.TryGetValue(typeDef, out var typeDefMetas))
|
||||||
|
{
|
||||||
|
typeDefMetas = new RefTypeDefMetas();
|
||||||
|
refTypeDefMetasMap.Add(typeDef, typeDefMetas);
|
||||||
|
}
|
||||||
|
typeDefMetas.typeRefs.Add(typeRef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (CustomAttributeInfo cai in _customAttributeArgumentsWithTypeByMods.Values.SelectMany(cas => cas))
|
||||||
|
{
|
||||||
|
CustomAttribute ca = cai.customAttributes[cai.index];
|
||||||
|
TypeDef typeDef = MetaUtil.GetTypeDefOrGenericTypeBaseThrowException(ca.Constructor.DeclaringType);
|
||||||
|
if (!refTypeDefMetasMap.TryGetValue(typeDef, out var typeDefMetas))
|
||||||
|
{
|
||||||
|
typeDefMetas = new RefTypeDefMetas();
|
||||||
|
refTypeDefMetasMap.Add(typeDef, typeDefMetas);
|
||||||
|
}
|
||||||
|
typeDefMetas.customAttributes.Add(ca);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RetargetTypeRefInCustomAttributes()
|
||||||
|
{
|
||||||
|
foreach (CustomAttributeInfo cai in _customAttributeArgumentsWithTypeByMods.Values.SelectMany(cas => cas))
|
||||||
|
{
|
||||||
|
CustomAttribute ca = cai.customAttributes[cai.index];
|
||||||
|
bool anyChange = false;
|
||||||
|
if (cai.arguments != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < cai.arguments.Count; i++)
|
||||||
|
{
|
||||||
|
CAArgument oldArg = cai.arguments[i];
|
||||||
|
if (MetaUtil.TryRetargetTypeRefInArgument(oldArg, out CAArgument newArg))
|
||||||
|
{
|
||||||
|
anyChange = true;
|
||||||
|
cai.arguments[i] = newArg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cai.namedArguments != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < cai.namedArguments.Count; i++)
|
||||||
|
{
|
||||||
|
if (MetaUtil.TryRetargetTypeRefInNamedArgument(cai.namedArguments[i]))
|
||||||
|
{
|
||||||
|
anyChange = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (anyChange)
|
||||||
|
{
|
||||||
|
cai.customAttributes[cai.index] = new CustomAttribute(ca.Constructor,
|
||||||
|
cai.arguments != null ? cai.arguments : ca.ConstructorArguments,
|
||||||
|
cai.namedArguments != null ? cai.namedArguments : ca.NamedArguments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Dictionary<TypeDef, RefTypeDefMetas> _refTypeRefMetasMap = new Dictionary<TypeDef, RefTypeDefMetas>();
|
||||||
|
|
||||||
|
private void RenameTypes()
|
||||||
|
{
|
||||||
|
Debug.Log("RenameTypes begin");
|
||||||
|
|
||||||
|
RetargetTypeRefInCustomAttributes();
|
||||||
|
|
||||||
|
BuildRefTypeDefMetasMap(_refTypeRefMetasMap);
|
||||||
|
_assemblyCache.EnableTypeDefCache = false;
|
||||||
|
|
||||||
|
foreach (ModuleDef mod in _toObfuscatedModules)
|
||||||
|
{
|
||||||
|
foreach (TypeDef type in mod.GetTypes())
|
||||||
|
{
|
||||||
|
if (_renamePolicy.NeedRename(type))
|
||||||
|
{
|
||||||
|
Rename(type, _refTypeRefMetasMap.GetValueOrDefault(type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// clean cache
|
||||||
|
_assemblyCache.EnableTypeDefCache = true;
|
||||||
|
Debug.Log("Rename Types end");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class RefFieldMetas
|
||||||
|
{
|
||||||
|
public readonly List<MemberRef> fieldRefs = new List<MemberRef>();
|
||||||
|
public readonly List<CustomAttribute> customAttributes = new List<CustomAttribute>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void BuildHierarchyFields(TypeDef type, List<FieldDef> fields)
|
||||||
|
{
|
||||||
|
while (type != null)
|
||||||
|
{
|
||||||
|
fields.AddRange(type.Fields);
|
||||||
|
type = MetaUtil.GetBaseTypeDef(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<MemberRef> WalkMemberRefs(ModuleDef mod)
|
||||||
|
{
|
||||||
|
foreach (TypeDef type in mod.GetTypes())
|
||||||
|
{
|
||||||
|
foreach (MethodDef method in type.Methods)
|
||||||
|
{
|
||||||
|
if (!method.HasBody)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
foreach (var instr in method.Body.Instructions)
|
||||||
|
{
|
||||||
|
if (instr.Operand is MemberRef memberRef)
|
||||||
|
{
|
||||||
|
yield return memberRef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BuildRefFieldMetasMap(Dictionary<FieldDef, RefFieldMetas> refFieldMetasMap)
|
||||||
|
{
|
||||||
|
foreach (ModuleDef mod in _obfuscatedAndNotObfuscatedModules)
|
||||||
|
{
|
||||||
|
foreach (MemberRef memberRef in WalkMemberRefs(mod))
|
||||||
|
{
|
||||||
|
if (!memberRef.IsFieldRef)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
IMemberRefParent parent = memberRef.Class;
|
||||||
|
TypeDef parentTypeDef = MetaUtil.GetMemberRefTypeDefParentOrNull(parent);
|
||||||
|
if (parentTypeDef == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
foreach (FieldDef field in parentTypeDef.Fields)
|
||||||
|
{
|
||||||
|
if (field.Name == memberRef.Name && TypeEqualityComparer.Instance.Equals(field.FieldSig.Type, memberRef.FieldSig.Type))
|
||||||
|
{
|
||||||
|
if (!refFieldMetasMap.TryGetValue(field, out var fieldMetas))
|
||||||
|
{
|
||||||
|
fieldMetas = new RefFieldMetas();
|
||||||
|
refFieldMetasMap.Add(field, fieldMetas);
|
||||||
|
}
|
||||||
|
fieldMetas.fieldRefs.Add(memberRef);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var e in _refTypeRefMetasMap)
|
||||||
|
{
|
||||||
|
TypeDef typeDef = e.Key;
|
||||||
|
var hierarchyFields = new List<FieldDef>();
|
||||||
|
BuildHierarchyFields(typeDef, hierarchyFields);
|
||||||
|
RefTypeDefMetas typeDefMetas = e.Value;
|
||||||
|
foreach (CustomAttribute ca in typeDefMetas.customAttributes)
|
||||||
|
{
|
||||||
|
foreach (var arg in ca.NamedArguments)
|
||||||
|
{
|
||||||
|
if (arg.IsProperty)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
foreach (FieldDef field in hierarchyFields)
|
||||||
|
{
|
||||||
|
// FIXME. field of Generic Base Type may not be same
|
||||||
|
if (field.Name == arg.Name && TypeEqualityComparer.Instance.Equals(field.FieldType, arg.Type))
|
||||||
|
{
|
||||||
|
if (!refFieldMetasMap.TryGetValue(field, out var fieldMetas))
|
||||||
|
{
|
||||||
|
fieldMetas = new RefFieldMetas();
|
||||||
|
refFieldMetasMap.Add(field, fieldMetas);
|
||||||
|
}
|
||||||
|
fieldMetas.customAttributes.Add(ca);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RenameFields()
|
||||||
|
{
|
||||||
|
Debug.Log("Rename fields begin");
|
||||||
|
var refFieldMetasMap = new Dictionary<FieldDef, RefFieldMetas>();
|
||||||
|
BuildRefFieldMetasMap(refFieldMetasMap);
|
||||||
|
|
||||||
|
foreach (ModuleDef mod in _toObfuscatedModules)
|
||||||
|
{
|
||||||
|
foreach (TypeDef type in mod.GetTypes())
|
||||||
|
{
|
||||||
|
foreach (FieldDef field in type.Fields)
|
||||||
|
{
|
||||||
|
if (_renamePolicy.NeedRename(field))
|
||||||
|
{
|
||||||
|
Rename(field, refFieldMetasMap.GetValueOrDefault(field));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Debug.Log("Rename fields end");
|
||||||
|
}
|
||||||
|
|
||||||
|
class RefMethodMetas
|
||||||
|
{
|
||||||
|
public readonly List<MemberRef> memberRefs = new List<MemberRef>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BuildRefMethodMetasMap(Dictionary<MethodDef, RefMethodMetas> refMethodMetasMap)
|
||||||
|
{
|
||||||
|
foreach (ModuleDef mod in _obfuscatedAndNotObfuscatedModules)
|
||||||
|
{
|
||||||
|
foreach (MemberRef memberRef in WalkMemberRefs(mod))
|
||||||
|
{
|
||||||
|
if (!memberRef.IsMethodRef)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
IMemberRefParent parent = memberRef.Class;
|
||||||
|
TypeDef parentTypeDef = MetaUtil.GetMemberRefTypeDefParentOrNull(parent);
|
||||||
|
if (parentTypeDef == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
foreach (MethodDef method in parentTypeDef.Methods)
|
||||||
|
{
|
||||||
|
if (method.Name == memberRef.Name && new SigComparer(default).Equals(method.MethodSig, memberRef.MethodSig))
|
||||||
|
{
|
||||||
|
if (!refMethodMetasMap.TryGetValue(method, out var refMethodMetas))
|
||||||
|
{
|
||||||
|
refMethodMetas = new RefMethodMetas();
|
||||||
|
refMethodMetasMap.Add(method, refMethodMetas);
|
||||||
|
}
|
||||||
|
refMethodMetas.memberRefs.Add(memberRef);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RenameMethods()
|
||||||
|
{
|
||||||
|
Debug.Log("Rename methods begin");
|
||||||
|
Debug.Log("Rename not virtual methods begin");
|
||||||
|
var virtualMethods = new List<MethodDef>();
|
||||||
|
var refMethodMetasMap = new Dictionary<MethodDef, RefMethodMetas>();
|
||||||
|
BuildRefMethodMetasMap(refMethodMetasMap);
|
||||||
|
foreach (ModuleDef mod in _toObfuscatedModules)
|
||||||
|
{
|
||||||
|
foreach (TypeDef type in mod.GetTypes())
|
||||||
|
{
|
||||||
|
foreach (MethodDef method in type.Methods)
|
||||||
|
{
|
||||||
|
if (method.IsVirtual)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (_renamePolicy.NeedRename(method))
|
||||||
|
{
|
||||||
|
Rename(method, refMethodMetasMap.GetValueOrDefault(method));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (ModuleDef mod in _obfuscatedAndNotObfuscatedModules)
|
||||||
|
{
|
||||||
|
foreach (TypeDef type in mod.GetTypes())
|
||||||
|
{
|
||||||
|
_virtualMethodGroupCalculator.CalculateType(type);
|
||||||
|
foreach (MethodDef method in type.Methods)
|
||||||
|
{
|
||||||
|
if (method.IsVirtual)
|
||||||
|
{
|
||||||
|
virtualMethods.Add(method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Log("Rename not virtual methods end");
|
||||||
|
|
||||||
|
|
||||||
|
Debug.Log("Rename virtual methods begin");
|
||||||
|
var visitedVirtualMethods = new HashSet<MethodDef>();
|
||||||
|
var groupNeedRenames = new Dictionary<VirtualMethodGroup, bool>();
|
||||||
|
foreach (var method in virtualMethods)
|
||||||
|
{
|
||||||
|
if (!visitedVirtualMethods.Add(method))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
VirtualMethodGroup group = _virtualMethodGroupCalculator.GetMethodGroup(method);
|
||||||
|
if (!groupNeedRenames.TryGetValue(group, out var needRename))
|
||||||
|
{
|
||||||
|
needRename = group.methods.All(m => _toObfuscatedModuleSet.Contains(m.DeclaringType.Module) && _renamePolicy.NeedRename(m));
|
||||||
|
groupNeedRenames.Add(group, needRename);
|
||||||
|
if (needRename)
|
||||||
|
{
|
||||||
|
_renameRecordMap.InitAndAddRename(group, _renameRecordMap.TryGetExistRenameMapping(method, out var nn) ? nn : _nameMaker.GetNewName(method, method.Name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!needRename)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (_renameRecordMap.TryGetRename(group, out var newName))
|
||||||
|
{
|
||||||
|
Rename(method, refMethodMetasMap.GetValueOrDefault(method), newName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception($"group:{group} method:{method} not found in rename record map");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Debug.Log("Rename virtual methods end");
|
||||||
|
Debug.Log("Rename methods end");
|
||||||
|
}
|
||||||
|
|
||||||
|
class RefPropertyMetas
|
||||||
|
{
|
||||||
|
public List<CustomAttribute> customAttributes = new List<CustomAttribute>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BuildHierarchyProperties(TypeDef type, List<PropertyDef> properties)
|
||||||
|
{
|
||||||
|
while (type != null)
|
||||||
|
{
|
||||||
|
properties.AddRange(type.Properties);
|
||||||
|
type = MetaUtil.GetBaseTypeDef(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BuildRefPropertyMetasMap(Dictionary<PropertyDef, RefPropertyMetas> refPropertyMetasMap)
|
||||||
|
{
|
||||||
|
foreach (var e in _refTypeRefMetasMap)
|
||||||
|
{
|
||||||
|
TypeDef typeDef = e.Key;
|
||||||
|
var hierarchyProperties = new List<PropertyDef>();
|
||||||
|
BuildHierarchyProperties(typeDef, hierarchyProperties);
|
||||||
|
RefTypeDefMetas typeDefMetas = e.Value;
|
||||||
|
foreach (CustomAttribute ca in typeDefMetas.customAttributes)
|
||||||
|
{
|
||||||
|
foreach (var arg in ca.NamedArguments)
|
||||||
|
{
|
||||||
|
if (arg.IsField)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
foreach (PropertyDef field in hierarchyProperties)
|
||||||
|
{
|
||||||
|
// FIXME. field of Generic Base Type may not be same
|
||||||
|
if (field.Name == arg.Name && TypeEqualityComparer.Instance.Equals(arg.Type, field.PropertySig.RetType))
|
||||||
|
{
|
||||||
|
if (!refPropertyMetasMap.TryGetValue(field, out var fieldMetas))
|
||||||
|
{
|
||||||
|
fieldMetas = new RefPropertyMetas();
|
||||||
|
refPropertyMetasMap.Add(field, fieldMetas);
|
||||||
|
}
|
||||||
|
fieldMetas.customAttributes.Add(ca);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RenameProperties()
|
||||||
|
{
|
||||||
|
Debug.Log("Rename properties begin");
|
||||||
|
var refPropertyMetasMap = new Dictionary<PropertyDef, RefPropertyMetas>();
|
||||||
|
BuildRefPropertyMetasMap(refPropertyMetasMap);
|
||||||
|
foreach (ModuleDef mod in _toObfuscatedModules)
|
||||||
|
{
|
||||||
|
foreach (TypeDef type in mod.GetTypes())
|
||||||
|
{
|
||||||
|
foreach (PropertyDef property in type.Properties)
|
||||||
|
{
|
||||||
|
if (_renamePolicy.NeedRename(property))
|
||||||
|
{
|
||||||
|
Rename(property, refPropertyMetasMap.GetValueOrDefault(property));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Debug.Log("Rename properties end");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RenameEvents()
|
||||||
|
{
|
||||||
|
Debug.Log("Rename events begin");
|
||||||
|
foreach (ModuleDef mod in _toObfuscatedModules)
|
||||||
|
{
|
||||||
|
foreach (TypeDef type in mod.GetTypes())
|
||||||
|
{
|
||||||
|
foreach (EventDef eventDef in type.Events)
|
||||||
|
{
|
||||||
|
if (_renamePolicy.NeedRename(eventDef))
|
||||||
|
{
|
||||||
|
Rename(eventDef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Debug.Log("Rename events begin");
|
||||||
|
}
|
||||||
|
|
||||||
|
//private void Rename(ModuleDef mod)
|
||||||
|
//{
|
||||||
|
// string oldName = mod.Assembly.Name;
|
||||||
|
// string newName = _renameRecordMap.TryGetExistRenameMapping(mod, out var n) ? n : _nameMaker.GetNewName(mod, oldName);
|
||||||
|
// _renameRecordMap.AddRename(mod, newName);
|
||||||
|
// mod.Assembly.Name = newName;
|
||||||
|
// mod.Name = $"{newName}.dll";
|
||||||
|
// //Debug.Log($"rename module. oldName:{oldName} newName:{newName}");
|
||||||
|
// foreach (AssemblyReferenceInfo ass in GetReferenceMeAssemblies(mod))
|
||||||
|
// {
|
||||||
|
// foreach (AssemblyRef assRef in ass.module.GetAssemblyRefs())
|
||||||
|
// {
|
||||||
|
// if (assRef.Name == oldName)
|
||||||
|
// {
|
||||||
|
// _renameRecordMap.AddRename(mod, newName);
|
||||||
|
// assRef.Name = newName;
|
||||||
|
// // Debug.Log($"rename assembly:{ass.name} ref oldName:{oldName} newName:{newName}");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
private void Rename(TypeDef type, RefTypeDefMetas refTypeDefMeta)
|
||||||
|
{
|
||||||
|
string moduleName = MetaUtil.GetModuleNameWithoutExt(type.Module.Name);
|
||||||
|
string oldFullName = type.FullName;
|
||||||
|
string oldNamespace = type.Namespace;
|
||||||
|
|
||||||
|
string oldName = type.Name;
|
||||||
|
|
||||||
|
string newNamespace;
|
||||||
|
string newName;
|
||||||
|
if (_renameRecordMap.TryGetExistRenameMapping(type, out var nns, out var nn))
|
||||||
|
{
|
||||||
|
newNamespace = nns;
|
||||||
|
newName = nn;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newNamespace = _nameMaker.GetNewNamespace(type, oldNamespace, _useConsistentNamespaceObfuscation);
|
||||||
|
newName = _nameMaker.GetNewName(type, oldName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (refTypeDefMeta != null)
|
||||||
|
{
|
||||||
|
foreach (TypeRef typeRef in refTypeDefMeta.typeRefs)
|
||||||
|
{
|
||||||
|
Assert.AreEqual(typeRef.FullName, oldFullName);
|
||||||
|
Assert.IsTrue(typeRef.DefinitionAssembly.Name == moduleName);
|
||||||
|
if (!string.IsNullOrEmpty(oldNamespace))
|
||||||
|
{
|
||||||
|
typeRef.Namespace = newNamespace;
|
||||||
|
}
|
||||||
|
typeRef.Name = newName;
|
||||||
|
//Debug.Log($"rename assembly:{typeRef.Module.Name} reference {oldFullName} => {typeRef.FullName}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type.Name = newName;
|
||||||
|
type.Namespace = newNamespace;
|
||||||
|
string newFullName = type.FullName;
|
||||||
|
_renameRecordMap.AddRename(type, newFullName);
|
||||||
|
//Debug.Log($"rename typedef. assembly:{type.Module.Name} oldName:{oldFullName} => newName:{newFullName}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Rename(FieldDef field, RefFieldMetas fieldMetas)
|
||||||
|
{
|
||||||
|
string oldName = field.Name;
|
||||||
|
string newName = _renameRecordMap.TryGetExistRenameMapping(field, out var nn) ? nn : _nameMaker.GetNewName(field, oldName);
|
||||||
|
if (fieldMetas != null)
|
||||||
|
{
|
||||||
|
foreach (var memberRef in fieldMetas.fieldRefs)
|
||||||
|
{
|
||||||
|
memberRef.Name = newName;
|
||||||
|
//Debug.Log($"rename assembly:{memberRef.Module.Name} reference {field.FullName} => {memberRef.FullName}");
|
||||||
|
}
|
||||||
|
foreach (var ca in fieldMetas.customAttributes)
|
||||||
|
{
|
||||||
|
foreach (var arg in ca.NamedArguments)
|
||||||
|
{
|
||||||
|
if (arg.Name == oldName)
|
||||||
|
{
|
||||||
|
arg.Name = newName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Debug.Log($"rename field. {field} => {newName}");
|
||||||
|
_renameRecordMap.AddRename(field, newName);
|
||||||
|
field.Name = newName;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Rename(MethodDef method, RefMethodMetas refMethodMetas)
|
||||||
|
{
|
||||||
|
string oldName = method.Name;
|
||||||
|
string newName = _renameRecordMap.TryGetExistRenameMapping(method, out var nn) ? nn : _nameMaker.GetNewName(method, oldName);
|
||||||
|
Rename(method, refMethodMetas, newName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Rename(MethodDef method, RefMethodMetas refMethodMetas, string newName)
|
||||||
|
{
|
||||||
|
ModuleDefMD mod = (ModuleDefMD)method.DeclaringType.Module;
|
||||||
|
RenameMethodParams(method);
|
||||||
|
RenameMethodBody(method);
|
||||||
|
if (refMethodMetas != null)
|
||||||
|
{
|
||||||
|
foreach (MemberRef memberRef in refMethodMetas.memberRefs)
|
||||||
|
{
|
||||||
|
string oldMethodFullName = memberRef.ToString();
|
||||||
|
memberRef.Name = newName;
|
||||||
|
//Debug.Log($"rename assembly:{memberRef.Module.Name} method:{oldMethodFullName} => {memberRef}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_renameRecordMap.AddRename(method, newName);
|
||||||
|
method.Name = newName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RenameMethodBody(MethodDef method)
|
||||||
|
{
|
||||||
|
if (method.Body == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RenameMethodParams(MethodDef method)
|
||||||
|
{
|
||||||
|
foreach (Parameter param in method.Parameters)
|
||||||
|
{
|
||||||
|
if (param.ParamDef != null)
|
||||||
|
{
|
||||||
|
Rename(param.ParamDef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Rename(ParamDef param)
|
||||||
|
{
|
||||||
|
if (_renamePolicy.NeedRename(param))
|
||||||
|
{
|
||||||
|
string newName = _nameMaker.GetNewName(param, param.Name);
|
||||||
|
_renameRecordMap.AddRename(param, newName);
|
||||||
|
param.Name = newName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Rename(EventDef eventDef)
|
||||||
|
{
|
||||||
|
string oldName = eventDef.Name;
|
||||||
|
string newName = _renameRecordMap.TryGetExistRenameMapping(eventDef, out var nn) ? nn : _nameMaker.GetNewName(eventDef, eventDef.Name);
|
||||||
|
_renameRecordMap.AddRename(eventDef, newName);
|
||||||
|
eventDef.Name = newName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Rename(PropertyDef property, RefPropertyMetas refPropertyMetas)
|
||||||
|
{
|
||||||
|
string oldName = property.Name;
|
||||||
|
string newName = _renameRecordMap.TryGetExistRenameMapping(property, out var nn) ? nn : _nameMaker.GetNewName(property, oldName);
|
||||||
|
|
||||||
|
if (refPropertyMetas != null)
|
||||||
|
{
|
||||||
|
foreach (var ca in refPropertyMetas.customAttributes)
|
||||||
|
{
|
||||||
|
foreach (var arg in ca.NamedArguments)
|
||||||
|
{
|
||||||
|
if (arg.Name == oldName)
|
||||||
|
{
|
||||||
|
arg.Name = newName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_renameRecordMap.AddRename(property, newName);
|
||||||
|
property.Name = newName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Save()
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(Path.GetDirectoryName(_mappingXmlPath));
|
||||||
|
_renameRecordMap.WriteXmlMappingFile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,100 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using Obfuz.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.SymbolObfus
|
||||||
|
{
|
||||||
|
|
||||||
|
public class VirtualMethodGroup
|
||||||
|
{
|
||||||
|
public List<MethodDef> methods;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class VirtualMethodGroupCalculator
|
||||||
|
{
|
||||||
|
|
||||||
|
private class TypeFlatMethods
|
||||||
|
{
|
||||||
|
public HashSet<MethodDef> flatMethods = new HashSet<MethodDef>();
|
||||||
|
|
||||||
|
|
||||||
|
public bool TryFindMatchVirtualMethod(MethodDef method, out MethodDef matchMethodDef)
|
||||||
|
{
|
||||||
|
foreach (var parentOrInterfaceMethod in flatMethods)
|
||||||
|
{
|
||||||
|
if (parentOrInterfaceMethod.Name == method.Name && parentOrInterfaceMethod.GetParamCount() == method.GetParamCount())
|
||||||
|
{
|
||||||
|
matchMethodDef = parentOrInterfaceMethod;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
matchMethodDef = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private readonly Dictionary<MethodDef, VirtualMethodGroup> _methodGroups = new Dictionary<MethodDef, VirtualMethodGroup>();
|
||||||
|
private readonly Dictionary<TypeDef, TypeFlatMethods> _visitedTypes = new Dictionary<TypeDef, TypeFlatMethods>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public VirtualMethodGroup GetMethodGroup(MethodDef methodDef)
|
||||||
|
{
|
||||||
|
if (_methodGroups.TryGetValue(methodDef, out var group))
|
||||||
|
{
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CalculateType(TypeDef typeDef)
|
||||||
|
{
|
||||||
|
if (_visitedTypes.ContainsKey(typeDef))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var typeMethods = new TypeFlatMethods();
|
||||||
|
|
||||||
|
if (typeDef.BaseType != null)
|
||||||
|
{
|
||||||
|
TypeDef baseTypeDef = MetaUtil.GetTypeDefOrGenericTypeBaseThrowException(typeDef.BaseType);
|
||||||
|
CalculateType(baseTypeDef);
|
||||||
|
typeMethods.flatMethods.AddRange(_visitedTypes[baseTypeDef].flatMethods);
|
||||||
|
foreach (var intfType in typeDef.Interfaces)
|
||||||
|
{
|
||||||
|
TypeDef intfTypeDef = MetaUtil.GetTypeDefOrGenericTypeBaseThrowException(intfType.Interface);
|
||||||
|
CalculateType(intfTypeDef);
|
||||||
|
typeMethods.flatMethods.AddRange(_visitedTypes[intfTypeDef].flatMethods);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var method in typeDef.Methods)
|
||||||
|
{
|
||||||
|
if (!method.IsVirtual)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (typeMethods.TryFindMatchVirtualMethod(method, out var matchMethodDef))
|
||||||
|
{
|
||||||
|
var group = _methodGroups[matchMethodDef];
|
||||||
|
group.methods.Add(method);
|
||||||
|
_methodGroups.Add(method, group);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_methodGroups.Add(method, new VirtualMethodGroup() { methods = new List<MethodDef> { method } });
|
||||||
|
}
|
||||||
|
if (method.IsNewSlot)
|
||||||
|
{
|
||||||
|
typeMethods.flatMethods.Add(method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_visitedTypes.Add(typeDef, typeMethods);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using Obfuz.Editor;
|
||||||
|
using Obfuz.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz
|
||||||
|
{
|
||||||
|
public class ObfuscationMethodWhitelist
|
||||||
|
{
|
||||||
|
private bool ShouldBeIgnoredByCustomAttribute(IHasCustomAttribute obj)
|
||||||
|
{
|
||||||
|
return MetaUtil.HasObfuzIgnoreAttribute(obj) || MetaUtil.HasCompilerGeneratedAttribute(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsInWhiteList(ModuleDef module)
|
||||||
|
{
|
||||||
|
string modName = module.Assembly.Name;
|
||||||
|
if (modName == "Obfuz.Runtime")
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (ShouldBeIgnoredByCustomAttribute(module))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsInWhiteList(MethodDef method)
|
||||||
|
{
|
||||||
|
if (IsInWhiteList(method.DeclaringType))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (method.Name.StartsWith(ConstValues.ObfuzInternalSymbolNamePrefix))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (ShouldBeIgnoredByCustomAttribute(method))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsInWhiteList(TypeDef type)
|
||||||
|
{
|
||||||
|
if (type.Name.StartsWith(ConstValues.ObfuzInternalSymbolNamePrefix))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (IsInWhiteList(type.Module))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (ShouldBeIgnoredByCustomAttribute(type))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (type.FullName == "Obfuz.EncryptionVM.GeneratedEncryptionVirtualMachine")
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using Obfuz.Data;
|
||||||
|
using Obfuz.Emit;
|
||||||
|
using Obfuz.ObfusPasses;
|
||||||
|
using Obfuz.ObfusPasses.SymbolObfus;
|
||||||
|
using Obfuz.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz
|
||||||
|
{
|
||||||
|
public delegate IRandom RandomCreator(int seed);
|
||||||
|
|
||||||
|
public class EncryptionScopeInfo
|
||||||
|
{
|
||||||
|
public readonly IEncryptor encryptor;
|
||||||
|
public readonly RandomCreator localRandomCreator;
|
||||||
|
|
||||||
|
public EncryptionScopeInfo(IEncryptor encryptor, RandomCreator localRandomCreator)
|
||||||
|
{
|
||||||
|
this.encryptor = encryptor;
|
||||||
|
this.localRandomCreator = localRandomCreator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EncryptionScopeProvider
|
||||||
|
{
|
||||||
|
private readonly EncryptionScopeInfo _defaultStaticScope;
|
||||||
|
private readonly EncryptionScopeInfo _defaultDynamicScope;
|
||||||
|
private readonly HashSet<string> _dynamicSecretAssemblyNames;
|
||||||
|
|
||||||
|
public EncryptionScopeProvider(EncryptionScopeInfo defaultStaticScope, EncryptionScopeInfo defaultDynamicScope, HashSet<string> dynamicSecretAssemblyNames)
|
||||||
|
{
|
||||||
|
_defaultStaticScope = defaultStaticScope;
|
||||||
|
_defaultDynamicScope = defaultDynamicScope;
|
||||||
|
_dynamicSecretAssemblyNames = dynamicSecretAssemblyNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EncryptionScopeInfo GetScope(ModuleDef module)
|
||||||
|
{
|
||||||
|
if (_dynamicSecretAssemblyNames.Contains(module.Assembly.Name))
|
||||||
|
{
|
||||||
|
return _defaultDynamicScope;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return _defaultStaticScope;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsDynamicSecretAssembly(ModuleDef module)
|
||||||
|
{
|
||||||
|
return _dynamicSecretAssemblyNames.Contains(module.Assembly.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ObfuscationPassContext
|
||||||
|
{
|
||||||
|
public static ObfuscationPassContext Current { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public GroupByModuleEntityManager moduleEntityManager;
|
||||||
|
|
||||||
|
public AssemblyCache assemblyCache;
|
||||||
|
|
||||||
|
public List<ModuleDef> modulesToObfuscate;
|
||||||
|
public List<ModuleDef> allObfuscationRelativeModules;
|
||||||
|
|
||||||
|
public List<string> assembliesToObfuscate;
|
||||||
|
public List<string> nonObfuscatedButReferencingObfuscatedAssemblies;
|
||||||
|
|
||||||
|
public string obfuscatedAssemblyOutputPath;
|
||||||
|
|
||||||
|
public EncryptionScopeProvider encryptionScopeProvider;
|
||||||
|
public ConstFieldAllocator constFieldAllocator;
|
||||||
|
public RvaDataAllocator rvaDataAllocator;
|
||||||
|
public ObfuscationMethodWhitelist whiteList;
|
||||||
|
public ConfigurablePassPolicy passPolicy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,337 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using Obfuz.Data;
|
||||||
|
using Obfuz.Emit;
|
||||||
|
using Obfuz.EncryptionVM;
|
||||||
|
using Obfuz.ObfusPasses;
|
||||||
|
using Obfuz.ObfusPasses.CleanUp;
|
||||||
|
using Obfuz.ObfusPasses.SymbolObfus;
|
||||||
|
using Obfuz.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Obfuz
|
||||||
|
{
|
||||||
|
|
||||||
|
public class Obfuscator
|
||||||
|
{
|
||||||
|
private readonly string _obfuscatedAssemblyOutputPath;
|
||||||
|
|
||||||
|
private readonly List<string> _assembliesToObfuscate;
|
||||||
|
private readonly List<string> _nonObfuscatedButReferencingObfuscatedAssemblies;
|
||||||
|
private readonly List<string> _assemblySearchPaths;
|
||||||
|
|
||||||
|
private readonly ConfigurablePassPolicy _passPolicy;
|
||||||
|
|
||||||
|
private readonly Pipeline _pipeline1 = new Pipeline();
|
||||||
|
private readonly Pipeline _pipeline2 = new Pipeline();
|
||||||
|
|
||||||
|
private readonly byte[] _defaultStaticByteSecretKey;
|
||||||
|
private readonly byte[] _defaultDynamicByteSecret;
|
||||||
|
private readonly HashSet<string> _assembliesUsingDynamicSecretKeys;
|
||||||
|
|
||||||
|
private readonly int _randomSeed;
|
||||||
|
private readonly string _encryptionVmGenerationSecretKey;
|
||||||
|
private readonly int _encryptionVmOpCodeCount;
|
||||||
|
private readonly string _encryptionVmCodeFile;
|
||||||
|
|
||||||
|
private ObfuscationPassContext _ctx;
|
||||||
|
|
||||||
|
public Obfuscator(ObfuscatorBuilder builder)
|
||||||
|
{
|
||||||
|
_defaultStaticByteSecretKey = KeyGenerator.GenerateKey(builder.DefaultStaticSecretKey, VirtualMachine.SecretKeyLength);
|
||||||
|
_defaultDynamicByteSecret = KeyGenerator.GenerateKey(builder.DefaultDynamicSecretKey, VirtualMachine.SecretKeyLength);
|
||||||
|
_assembliesUsingDynamicSecretKeys = new HashSet<string>(builder.AssembliesUsingDynamicSecretKeys);
|
||||||
|
|
||||||
|
|
||||||
|
_randomSeed = builder.RandomSeed;
|
||||||
|
_encryptionVmGenerationSecretKey = builder.EncryptionVmGenerationSecretKey;
|
||||||
|
_encryptionVmOpCodeCount = builder.EncryptionVmOpCodeCount;
|
||||||
|
_encryptionVmCodeFile = builder.EncryptionVmCodeFile;
|
||||||
|
|
||||||
|
_assembliesToObfuscate = builder.AssembliesToObfuscate;
|
||||||
|
_nonObfuscatedButReferencingObfuscatedAssemblies = builder.NonObfuscatedButReferencingObfuscatedAssemblies;
|
||||||
|
_obfuscatedAssemblyOutputPath = builder.ObfuscatedAssemblyOutputPath;
|
||||||
|
_assemblySearchPaths = builder.AssemblySearchPaths;
|
||||||
|
|
||||||
|
_passPolicy = new ConfigurablePassPolicy(_assembliesToObfuscate, builder.EnableObfuscationPasses, builder.ObfuscationPassRuleConfigFiles);
|
||||||
|
|
||||||
|
foreach (var pass in builder.ObfuscationPasses)
|
||||||
|
{
|
||||||
|
if (pass is SymbolObfusPass symbolObfusPass)
|
||||||
|
{
|
||||||
|
_pipeline2.AddPass(pass);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_pipeline1.AddPass(pass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_pipeline1.AddPass(new CleanUpInstructionPass());
|
||||||
|
_pipeline2.AddPass(new RemoveObfuzAttributesPass());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Run()
|
||||||
|
{
|
||||||
|
FileUtil.RecreateDir(_obfuscatedAssemblyOutputPath);
|
||||||
|
RunPipeline(_pipeline1);
|
||||||
|
_assemblySearchPaths.Insert(0, _obfuscatedAssemblyOutputPath);
|
||||||
|
RunPipeline(_pipeline2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RunPipeline(Pipeline pipeline)
|
||||||
|
{
|
||||||
|
if (pipeline.Empty)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
OnPreObfuscation(pipeline);
|
||||||
|
DoObfuscation(pipeline);
|
||||||
|
OnPostObfuscation(pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEncryptor CreateEncryptionVirtualMachine(byte[] secretKey)
|
||||||
|
{
|
||||||
|
var vmCreator = new VirtualMachineCreator(_encryptionVmGenerationSecretKey);
|
||||||
|
var vm = vmCreator.CreateVirtualMachine(_encryptionVmOpCodeCount);
|
||||||
|
var vmGenerator = new VirtualMachineCodeGenerator(vm);
|
||||||
|
|
||||||
|
if (!File.Exists(_encryptionVmCodeFile))
|
||||||
|
{
|
||||||
|
throw new Exception($"EncryptionVm CodeFile:`{_encryptionVmCodeFile}` not exists! Please run `Obfuz/GenerateVm` to generate it!");
|
||||||
|
}
|
||||||
|
if (!vmGenerator.ValidateMatch(_encryptionVmCodeFile))
|
||||||
|
{
|
||||||
|
throw new Exception($"EncryptionVm CodeFile:`{_encryptionVmCodeFile}` not match with encryptionVM settings! Please run `Obfuz/GenerateVm` to update it!");
|
||||||
|
}
|
||||||
|
var vms = new VirtualMachineSimulator(vm, secretKey);
|
||||||
|
|
||||||
|
var generatedVmTypes = AppDomain.CurrentDomain.GetAssemblies()
|
||||||
|
.Select(assembly => assembly.GetType("Obfuz.EncryptionVM.GeneratedEncryptionVirtualMachine"))
|
||||||
|
.Where(type => type != null)
|
||||||
|
.ToList();
|
||||||
|
if (generatedVmTypes.Count == 0)
|
||||||
|
{
|
||||||
|
throw new Exception($"class Obfuz.EncryptionVM.GeneratedEncryptionVirtualMachine not found in any assembly! Please run `Obfuz/GenerateVm` to generate it!");
|
||||||
|
}
|
||||||
|
if (generatedVmTypes.Count > 1)
|
||||||
|
{
|
||||||
|
throw new Exception($"class Obfuz.EncryptionVM.GeneratedEncryptionVirtualMachine found in multiple assemblies! Please retain only one!");
|
||||||
|
}
|
||||||
|
|
||||||
|
var gvmInstance = (IEncryptor)Activator.CreateInstance(generatedVmTypes[0], new object[] { secretKey } );
|
||||||
|
|
||||||
|
VerifyVm(vm, vms, gvmInstance);
|
||||||
|
|
||||||
|
return vms;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void VerifyVm(VirtualMachine vm, VirtualMachineSimulator vms, IEncryptor gvm)
|
||||||
|
{
|
||||||
|
int testInt = 11223344;
|
||||||
|
long testLong = 1122334455667788L;
|
||||||
|
float testFloat = 1234f;
|
||||||
|
double testDouble = 1122334455.0;
|
||||||
|
string testString = "hello,world";
|
||||||
|
for (int i = 0; i < vm.opCodes.Length; i++)
|
||||||
|
{
|
||||||
|
int ops = i * vm.opCodes.Length + i;
|
||||||
|
//int salt = i;
|
||||||
|
//int ops = -1135538782;
|
||||||
|
int salt = -879409147;
|
||||||
|
{
|
||||||
|
int encryptedIntOfVms = vms.Encrypt(testInt, ops, salt);
|
||||||
|
int decryptedIntOfVms = vms.Decrypt(encryptedIntOfVms, ops, salt);
|
||||||
|
if (decryptedIntOfVms != testInt)
|
||||||
|
{
|
||||||
|
throw new Exception($"VirtualMachineSimulator decrypt failed! opCode:{i}, originalValue:{testInt} decryptedValue:{decryptedIntOfVms}");
|
||||||
|
}
|
||||||
|
int encryptedValueOfGvm = gvm.Encrypt(testInt, ops, salt);
|
||||||
|
int decryptedValueOfGvm = gvm.Decrypt(encryptedValueOfGvm, ops, salt);
|
||||||
|
if (encryptedValueOfGvm != encryptedIntOfVms)
|
||||||
|
{
|
||||||
|
throw new Exception($"encryptedValue not match! opCode:{i}, originalValue:{testInt} encryptedValue VirtualMachineSimulator:{encryptedIntOfVms} GeneratedEncryptionVirtualMachine:{encryptedValueOfGvm}");
|
||||||
|
}
|
||||||
|
if (decryptedValueOfGvm != testInt)
|
||||||
|
{
|
||||||
|
throw new Exception($"GeneratedEncryptionVirtualMachine decrypt failed! opCode:{i}, originalValue:{testInt} decryptedValue:{decryptedValueOfGvm}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
long encryptedLongOfVms = vms.Encrypt(testLong, ops, salt);
|
||||||
|
long decryptedLongOfVms = vms.Decrypt(encryptedLongOfVms, ops, salt);
|
||||||
|
if (decryptedLongOfVms != testLong)
|
||||||
|
{
|
||||||
|
throw new Exception($"VirtualMachineSimulator decrypt long failed! opCode:{i}, originalValue:{testLong} decryptedValue:{decryptedLongOfVms}");
|
||||||
|
}
|
||||||
|
long encryptedValueOfGvm = gvm.Encrypt(testLong, ops, salt);
|
||||||
|
long decryptedValueOfGvm = gvm.Decrypt(encryptedValueOfGvm, ops, salt);
|
||||||
|
if (encryptedValueOfGvm != encryptedLongOfVms)
|
||||||
|
{
|
||||||
|
throw new Exception($"encryptedValue not match! opCode:{i}, originalValue:{testLong} encryptedValue VirtualMachineSimulator:{encryptedLongOfVms} GeneratedEncryptionVirtualMachine:{encryptedValueOfGvm}");
|
||||||
|
}
|
||||||
|
if (decryptedValueOfGvm != testLong)
|
||||||
|
{
|
||||||
|
throw new Exception($"GeneratedEncryptionVirtualMachine decrypt long failed! opCode:{i}, originalValue:{testLong} decryptedValue:{decryptedValueOfGvm}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
float encryptedFloatOfVms = vms.Encrypt(testFloat, ops, salt);
|
||||||
|
float decryptedFloatOfVms = vms.Decrypt(encryptedFloatOfVms, ops, salt);
|
||||||
|
if (decryptedFloatOfVms != testFloat)
|
||||||
|
{
|
||||||
|
throw new Exception("encryptedFloat not match");
|
||||||
|
}
|
||||||
|
float encryptedValueOfGvm = gvm.Encrypt(testFloat, ops, salt);
|
||||||
|
float decryptedValueOfGvm = gvm.Decrypt(encryptedFloatOfVms, ops, salt);
|
||||||
|
if (encryptedFloatOfVms != encryptedValueOfGvm)
|
||||||
|
{
|
||||||
|
throw new Exception($"encryptedValue not match! opCode:{i}, originalValue:{testFloat} encryptedValue");
|
||||||
|
}
|
||||||
|
if (decryptedValueOfGvm != testFloat)
|
||||||
|
{
|
||||||
|
throw new Exception($"GeneratedEncryptionVirtualMachine decrypt float failed! opCode:{i}, originalValue:{testFloat}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
double encryptedFloatOfVms = vms.Encrypt(testDouble, ops, salt);
|
||||||
|
double decryptedFloatOfVms = vms.Decrypt(encryptedFloatOfVms, ops, salt);
|
||||||
|
if (decryptedFloatOfVms != testDouble)
|
||||||
|
{
|
||||||
|
throw new Exception("encryptedFloat not match");
|
||||||
|
}
|
||||||
|
double encryptedValueOfGvm = gvm.Encrypt(testDouble, ops, salt);
|
||||||
|
double decryptedValueOfGvm = gvm.Decrypt(encryptedFloatOfVms, ops, salt);
|
||||||
|
if (encryptedFloatOfVms != encryptedValueOfGvm)
|
||||||
|
{
|
||||||
|
throw new Exception($"encryptedValue not match! opCode:{i}, originalValue:{testDouble} encryptedValue");
|
||||||
|
}
|
||||||
|
if (decryptedValueOfGvm != testDouble)
|
||||||
|
{
|
||||||
|
throw new Exception($"GeneratedEncryptionVirtualMachine decrypt float failed! opCode:{i}, originalValue:{testDouble}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
byte[] encryptedStrOfVms = vms.Encrypt(testString, ops, salt);
|
||||||
|
string decryptedStrOfVms = vms.DecryptString(encryptedStrOfVms, 0, encryptedStrOfVms.Length, ops, salt);
|
||||||
|
if (decryptedStrOfVms != testString)
|
||||||
|
{
|
||||||
|
throw new Exception($"VirtualMachineSimulator decrypt string failed! opCode:{i}, originalValue:{testString} decryptedValue:{decryptedStrOfVms}");
|
||||||
|
}
|
||||||
|
byte[] encryptedStrOfGvm = gvm.Encrypt(testString, ops, salt);
|
||||||
|
string decryptedStrOfGvm = gvm.DecryptString(encryptedStrOfGvm, 0, encryptedStrOfGvm.Length, ops, salt);
|
||||||
|
if (!encryptedStrOfGvm.SequenceEqual(encryptedStrOfVms))
|
||||||
|
{
|
||||||
|
throw new Exception($"encryptedValue not match! opCode:{i}, originalValue:{testString} encryptedValue VirtualMachineSimulator:{encryptedStrOfVms} GeneratedEncryptionVirtualMachine:{encryptedStrOfGvm}");
|
||||||
|
}
|
||||||
|
if (decryptedStrOfGvm != testString)
|
||||||
|
{
|
||||||
|
throw new Exception($"GeneratedEncryptionVirtualMachine decrypt string failed! opCode:{i}, originalValue:{testString} decryptedValue:{decryptedStrOfGvm}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private EncryptionScopeInfo CreateEncryptionScope(byte[] byteSecret)
|
||||||
|
{
|
||||||
|
int[] intSecretKey = KeyGenerator.ConvertToIntKey(byteSecret);
|
||||||
|
IEncryptor encryption = CreateEncryptionVirtualMachine(byteSecret);
|
||||||
|
RandomCreator localRandomCreator = (seed) => new RandomWithKey(intSecretKey, _randomSeed ^ seed);
|
||||||
|
return new EncryptionScopeInfo(encryption, localRandomCreator);
|
||||||
|
}
|
||||||
|
|
||||||
|
private EncryptionScopeProvider CreateEncryptionScopeProvider()
|
||||||
|
{
|
||||||
|
var defaultStaticScope = CreateEncryptionScope(_defaultStaticByteSecretKey);
|
||||||
|
var defaultDynamicScope = CreateEncryptionScope(_defaultDynamicByteSecret);
|
||||||
|
foreach (string dynamicAssName in _assembliesUsingDynamicSecretKeys)
|
||||||
|
{
|
||||||
|
if (!_assembliesToObfuscate.Contains(dynamicAssName))
|
||||||
|
{
|
||||||
|
throw new Exception($"Dynamic secret assembly `{dynamicAssName}` should be in the toObfuscatedAssemblyNames list!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new EncryptionScopeProvider(defaultStaticScope, defaultDynamicScope, _assembliesUsingDynamicSecretKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPreObfuscation(Pipeline pipeline)
|
||||||
|
{
|
||||||
|
AssemblyCache assemblyCache = new AssemblyCache(new PathAssemblyResolver(_assemblySearchPaths.ToArray()));
|
||||||
|
List<ModuleDef> modulesToObfuscate = new List<ModuleDef>();
|
||||||
|
List<ModuleDef> allObfuscationRelativeModules = new List<ModuleDef>();
|
||||||
|
LoadAssemblies(assemblyCache, modulesToObfuscate, allObfuscationRelativeModules);
|
||||||
|
|
||||||
|
EncryptionScopeProvider encryptionScopeProvider = CreateEncryptionScopeProvider();
|
||||||
|
var moduleEntityManager = new GroupByModuleEntityManager();
|
||||||
|
var rvaDataAllocator = new RvaDataAllocator(encryptionScopeProvider, moduleEntityManager);
|
||||||
|
var constFieldAllocator = new ConstFieldAllocator(encryptionScopeProvider, rvaDataAllocator, moduleEntityManager);
|
||||||
|
_ctx = new ObfuscationPassContext
|
||||||
|
{
|
||||||
|
assemblyCache = assemblyCache,
|
||||||
|
modulesToObfuscate = modulesToObfuscate,
|
||||||
|
allObfuscationRelativeModules = allObfuscationRelativeModules,
|
||||||
|
assembliesToObfuscate = _assembliesToObfuscate,
|
||||||
|
nonObfuscatedButReferencingObfuscatedAssemblies = _nonObfuscatedButReferencingObfuscatedAssemblies,
|
||||||
|
obfuscatedAssemblyOutputPath = _obfuscatedAssemblyOutputPath,
|
||||||
|
moduleEntityManager = moduleEntityManager,
|
||||||
|
|
||||||
|
encryptionScopeProvider = encryptionScopeProvider,
|
||||||
|
|
||||||
|
rvaDataAllocator = rvaDataAllocator,
|
||||||
|
constFieldAllocator = constFieldAllocator,
|
||||||
|
whiteList = new ObfuscationMethodWhitelist(),
|
||||||
|
passPolicy = _passPolicy,
|
||||||
|
};
|
||||||
|
ObfuscationPassContext.Current = _ctx;
|
||||||
|
pipeline.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadAssemblies(AssemblyCache assemblyCache, List<ModuleDef> modulesToObfuscate, List<ModuleDef> allObfuscationRelativeModules)
|
||||||
|
{
|
||||||
|
foreach (string assName in _assembliesToObfuscate.Concat(_nonObfuscatedButReferencingObfuscatedAssemblies))
|
||||||
|
{
|
||||||
|
ModuleDefMD mod = assemblyCache.TryLoadModule(assName);
|
||||||
|
if (mod == null)
|
||||||
|
{
|
||||||
|
Debug.Log($"assembly: {assName} not found! ignore.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (_assembliesToObfuscate.Contains(assName))
|
||||||
|
{
|
||||||
|
modulesToObfuscate.Add(mod);
|
||||||
|
}
|
||||||
|
allObfuscationRelativeModules.Add(mod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteAssemblies()
|
||||||
|
{
|
||||||
|
foreach (ModuleDef mod in _ctx.allObfuscationRelativeModules)
|
||||||
|
{
|
||||||
|
string assNameWithExt = mod.Name;
|
||||||
|
string outputFile = $"{_obfuscatedAssemblyOutputPath}/{assNameWithExt}";
|
||||||
|
mod.Write(outputFile);
|
||||||
|
Debug.Log($"save module. name:{mod.Assembly.Name} output:{outputFile}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DoObfuscation(Pipeline pipeline)
|
||||||
|
{
|
||||||
|
pipeline.Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPostObfuscation(Pipeline pipeline)
|
||||||
|
{
|
||||||
|
pipeline.Stop();
|
||||||
|
|
||||||
|
_ctx.constFieldAllocator.Done();
|
||||||
|
_ctx.rvaDataAllocator.Done();
|
||||||
|
WriteAssemblies();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,216 @@
|
||||||
|
using Obfuz.EncryptionVM;
|
||||||
|
using Obfuz.ObfusPasses;
|
||||||
|
using Obfuz.ObfusPasses.CallObfus;
|
||||||
|
using Obfuz.ObfusPasses.ConstEncrypt;
|
||||||
|
using Obfuz.ObfusPasses.ExprObfus;
|
||||||
|
using Obfuz.ObfusPasses.FieldEncrypt;
|
||||||
|
using Obfuz.ObfusPasses.SymbolObfus;
|
||||||
|
using Obfuz.Settings;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using UnityEditor;
|
||||||
|
|
||||||
|
namespace Obfuz
|
||||||
|
{
|
||||||
|
public class ObfuscatorBuilder
|
||||||
|
{
|
||||||
|
private string _defaultStaticSecretKey;
|
||||||
|
private string _defaultStaticSecretKeyOutputPath;
|
||||||
|
private string _defaultDynamicSecretKey;
|
||||||
|
private string _defaultDynamicSecretKeyOutputPath;
|
||||||
|
private List<string> _assembliesUsingDynamicSecretKeys = new List<string>();
|
||||||
|
|
||||||
|
private int _randomSeed;
|
||||||
|
private string _encryptionVmGenerationSecretKey;
|
||||||
|
private int _encryptionVmOpCodeCount;
|
||||||
|
private string _encryptionVmCodeFile;
|
||||||
|
|
||||||
|
private List<string> _assembliesToObfuscate = new List<string>();
|
||||||
|
private List<string> _nonObfuscatedButReferencingObfuscatedAssemblies = new List<string>();
|
||||||
|
private List<string> _assemblySearchPaths = new List<string>();
|
||||||
|
|
||||||
|
private string _obfuscatedAssemblyOutputPath;
|
||||||
|
private List<string> _obfuscationPassRuleConfigFiles;
|
||||||
|
|
||||||
|
private ObfuscationPassType _enabledObfuscationPasses;
|
||||||
|
private List<IObfuscationPass> _obfuscationPasses = new List<IObfuscationPass>();
|
||||||
|
|
||||||
|
public string DefaultStaticSecretKey
|
||||||
|
{
|
||||||
|
get => _defaultStaticSecretKey;
|
||||||
|
set => _defaultStaticSecretKey = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string DefaultStaticSecretKeyOutputPath
|
||||||
|
{
|
||||||
|
get => _defaultStaticSecretKeyOutputPath;
|
||||||
|
set => _defaultStaticSecretKeyOutputPath = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string DefaultDynamicSecretKey
|
||||||
|
{
|
||||||
|
get => _defaultDynamicSecretKey;
|
||||||
|
set => _defaultDynamicSecretKey = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string DefaultDynamicSecretKeyOutputPath
|
||||||
|
{
|
||||||
|
get => _defaultDynamicSecretKeyOutputPath;
|
||||||
|
set => _defaultDynamicSecretKeyOutputPath = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<string> AssembliesUsingDynamicSecretKeys
|
||||||
|
{
|
||||||
|
get => _assembliesUsingDynamicSecretKeys;
|
||||||
|
set => _assembliesUsingDynamicSecretKeys = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int RandomSeed
|
||||||
|
{
|
||||||
|
get => _randomSeed;
|
||||||
|
set => _randomSeed = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string EncryptionVmGenerationSecretKey
|
||||||
|
{
|
||||||
|
get => _encryptionVmGenerationSecretKey;
|
||||||
|
set => _encryptionVmGenerationSecretKey = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int EncryptionVmOpCodeCount
|
||||||
|
{
|
||||||
|
get => _encryptionVmOpCodeCount;
|
||||||
|
set => _encryptionVmOpCodeCount = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string EncryptionVmCodeFile
|
||||||
|
{
|
||||||
|
get => _encryptionVmCodeFile;
|
||||||
|
set => _encryptionVmCodeFile = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<string> AssembliesToObfuscate
|
||||||
|
{
|
||||||
|
get => _assembliesToObfuscate;
|
||||||
|
set => _assembliesToObfuscate = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<string> NonObfuscatedButReferencingObfuscatedAssemblies
|
||||||
|
{
|
||||||
|
get => _nonObfuscatedButReferencingObfuscatedAssemblies;
|
||||||
|
set => _nonObfuscatedButReferencingObfuscatedAssemblies = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<string> AssemblySearchPaths
|
||||||
|
{
|
||||||
|
get => _assemblySearchPaths;
|
||||||
|
set => _assemblySearchPaths = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ObfuscatedAssemblyOutputPath
|
||||||
|
{
|
||||||
|
get => _obfuscatedAssemblyOutputPath;
|
||||||
|
set => _obfuscatedAssemblyOutputPath = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObfuscationPassType EnableObfuscationPasses
|
||||||
|
{
|
||||||
|
get => _enabledObfuscationPasses;
|
||||||
|
set => _enabledObfuscationPasses = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<string> ObfuscationPassRuleConfigFiles
|
||||||
|
{
|
||||||
|
get => _obfuscationPassRuleConfigFiles;
|
||||||
|
set => _obfuscationPassRuleConfigFiles = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<IObfuscationPass> ObfuscationPasses
|
||||||
|
{
|
||||||
|
get => _obfuscationPasses;
|
||||||
|
set => _obfuscationPasses = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InsertTopPriorityAssemblySearchPaths(List<string> assemblySearchPaths)
|
||||||
|
{
|
||||||
|
_assemblySearchPaths.InsertRange(0, assemblySearchPaths);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObfuscatorBuilder AddPass(IObfuscationPass pass)
|
||||||
|
{
|
||||||
|
_obfuscationPasses.Add(pass);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Obfuscator Build()
|
||||||
|
{
|
||||||
|
return new Obfuscator(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<string> BuildUnityAssemblySearchPaths()
|
||||||
|
{
|
||||||
|
string applicationContentsPath = EditorApplication.applicationContentsPath;
|
||||||
|
return new List<string>
|
||||||
|
{
|
||||||
|
#if UNITY_2021_1_OR_NEWER
|
||||||
|
Path.Combine(applicationContentsPath, "UnityReferenceAssemblies/unity-4.8-api/Facades"),
|
||||||
|
Path.Combine(applicationContentsPath, "UnityReferenceAssemblies/unity-4.8-api"),
|
||||||
|
#elif UNITY_2020 || UNITY_2019
|
||||||
|
Path.Combine(applicationContentsPath, "MonoBleedingEdge/lib/mono/4.7.1-api/Facades"),
|
||||||
|
Path.Combine(applicationContentsPath, "MonoBleedingEdge/lib/mono/4.7.1-api"),
|
||||||
|
#else
|
||||||
|
#error "Unsupported Unity version"
|
||||||
|
#endif
|
||||||
|
Path.Combine(applicationContentsPath, "Managed/UnityEngine"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ObfuscatorBuilder FromObfuzSettings(ObfuzSettings settings, BuildTarget target, bool searchPathIncludeUnityEditorInstallLocation)
|
||||||
|
{
|
||||||
|
List<string> searchPaths = searchPathIncludeUnityEditorInstallLocation ?
|
||||||
|
BuildUnityAssemblySearchPaths().Concat(settings.assemblySettings.additionalAssemblySearchPaths).ToList()
|
||||||
|
: settings.assemblySettings.additionalAssemblySearchPaths.ToList();
|
||||||
|
var builder = new ObfuscatorBuilder
|
||||||
|
{
|
||||||
|
_defaultStaticSecretKey = settings.secretSettings.defaultStaticSecretKey,
|
||||||
|
_defaultStaticSecretKeyOutputPath = settings.secretSettings.DefaultStaticSecretKeyOutputPath,
|
||||||
|
_defaultDynamicSecretKey = settings.secretSettings.defaultDynamicSecretKey,
|
||||||
|
_defaultDynamicSecretKeyOutputPath = settings.secretSettings.DefaultDynamicSecretKeyOutputPath,
|
||||||
|
_assembliesUsingDynamicSecretKeys = settings.secretSettings.assembliesUsingDynamicSecretKeys.ToList(),
|
||||||
|
_randomSeed = settings.secretSettings.randomSeed,
|
||||||
|
_encryptionVmGenerationSecretKey = settings.encryptionVMSettings.codeGenerationSecretKey,
|
||||||
|
_encryptionVmOpCodeCount = settings.encryptionVMSettings.encryptionOpCodeCount,
|
||||||
|
_encryptionVmCodeFile = settings.encryptionVMSettings.codeOutputPath,
|
||||||
|
_assembliesToObfuscate = settings.assemblySettings.assembliesToObfuscate.ToList(),
|
||||||
|
_nonObfuscatedButReferencingObfuscatedAssemblies = settings.assemblySettings.nonObfuscatedButReferencingObfuscatedAssemblies.ToList(),
|
||||||
|
_assemblySearchPaths = searchPaths,
|
||||||
|
_obfuscatedAssemblyOutputPath = settings.GetObfuscatedAssemblyOutputPath(target),
|
||||||
|
_enabledObfuscationPasses = settings.obfuscationPassSettings.enabledPasses,
|
||||||
|
_obfuscationPassRuleConfigFiles = settings.obfuscationPassSettings.ruleFiles.ToList(),
|
||||||
|
};
|
||||||
|
ObfuscationPassType obfuscationPasses = settings.obfuscationPassSettings.enabledPasses;
|
||||||
|
if (obfuscationPasses.HasFlag(ObfuscationPassType.ConstEncrypt))
|
||||||
|
{
|
||||||
|
builder.AddPass(new ConstEncryptPass(settings.constEncryptSettings));
|
||||||
|
}
|
||||||
|
if (obfuscationPasses.HasFlag(ObfuscationPassType.FieldEncrypt))
|
||||||
|
{
|
||||||
|
builder.AddPass(new FieldEncryptPass(settings.fieldEncryptSettings));
|
||||||
|
}
|
||||||
|
if (obfuscationPasses.HasFlag(ObfuscationPassType.CallObfus))
|
||||||
|
{
|
||||||
|
builder.AddPass(new CallObfusPass(settings.callObfusSettings));
|
||||||
|
}
|
||||||
|
if (obfuscationPasses.HasFlag(ObfuscationPassType.ExprObfus))
|
||||||
|
{
|
||||||
|
builder.AddPass(new ExprObfusPass());
|
||||||
|
}
|
||||||
|
if (obfuscationPasses.HasFlag(ObfuscationPassType.SymbolObfus))
|
||||||
|
{
|
||||||
|
builder.AddPass(new SymbolObfusPass(settings.symbolObfusSettings));
|
||||||
|
}
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"name": "Obfuz.Editor",
|
||||||
|
"rootNamespace": "",
|
||||||
|
"references": [
|
||||||
|
"GUID:4140bd2e2764f1f47ab93125ecb61942"
|
||||||
|
],
|
||||||
|
"includePlatforms": [
|
||||||
|
"Editor"
|
||||||
|
],
|
||||||
|
"excludePlatforms": [],
|
||||||
|
"allowUnsafeCode": true,
|
||||||
|
"overrideReferences": false,
|
||||||
|
"precompiledReferences": [],
|
||||||
|
"autoReferenced": true,
|
||||||
|
"defineConstraints": [],
|
||||||
|
"versionDefines": [],
|
||||||
|
"noEngineReferences": false
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
using Obfuz.ObfusPasses;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Obfuz
|
||||||
|
{
|
||||||
|
public class Pipeline
|
||||||
|
{
|
||||||
|
private readonly List<IObfuscationPass> _passes = new List<IObfuscationPass>();
|
||||||
|
|
||||||
|
public bool Empty => _passes.Count == 0;
|
||||||
|
|
||||||
|
public Pipeline AddPass(IObfuscationPass pass)
|
||||||
|
{
|
||||||
|
_passes.Add(pass);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
foreach (var pass in _passes)
|
||||||
|
{
|
||||||
|
pass.Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
|
||||||
|
foreach (var pass in _passes)
|
||||||
|
{
|
||||||
|
pass.Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Run()
|
||||||
|
{
|
||||||
|
foreach (var pass in _passes)
|
||||||
|
{
|
||||||
|
pass.Process();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Obfuz.Settings
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
public class AssemblySettings
|
||||||
|
{
|
||||||
|
|
||||||
|
[Tooltip("name of assemblies to obfuscate")]
|
||||||
|
public string[] assembliesToObfuscate;
|
||||||
|
|
||||||
|
[Tooltip("name of assemblies not obfuscated but reference assemblies to obfuscated ")]
|
||||||
|
public string[] nonObfuscatedButReferencingObfuscatedAssemblies;
|
||||||
|
|
||||||
|
[Tooltip("additional assembly search paths")]
|
||||||
|
public string[] additionalAssemblySearchPaths;
|
||||||
|
|
||||||
|
public string[] GetObfuscationRelativeAssemblyNames()
|
||||||
|
{
|
||||||
|
return assembliesToObfuscate
|
||||||
|
.Concat(nonObfuscatedButReferencingObfuscatedAssemblies)
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Obfuz.Settings
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
public class CallObfuscationSettings
|
||||||
|
{
|
||||||
|
[Tooltip("The obfuscation level for the obfuscation. Higher levels provide more security but may impact performance.")]
|
||||||
|
[Range(1, 4)]
|
||||||
|
public int obfuscationLevel = 1;
|
||||||
|
|
||||||
|
[Tooltip("rule config xml files")]
|
||||||
|
public string[] ruleFiles;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Obfuz.Settings
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
public class ConstEncryptionSettings
|
||||||
|
{
|
||||||
|
[Tooltip("The encryption level for the obfuscation. Higher levels provide more security but may impact performance.")]
|
||||||
|
[Range(1, 4)]
|
||||||
|
public int encryptionLevel = 1;
|
||||||
|
|
||||||
|
[Tooltip("config xml files")]
|
||||||
|
public string[] ruleFiles;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Obfuz.Settings
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
public class EncryptionVMSettings
|
||||||
|
{
|
||||||
|
[Tooltip("secret key for generating encryption virtual machine source code")]
|
||||||
|
public string codeGenerationSecretKey = "Obfuz";
|
||||||
|
|
||||||
|
[Tooltip("encryption OpCode count, should be power of 2 and >= 64")]
|
||||||
|
public int encryptionOpCodeCount = 256;
|
||||||
|
|
||||||
|
[Tooltip("encryption virtual machine source code output path")]
|
||||||
|
public string codeOutputPath = "Assets/Obfuz/GeneratedEncryptionVirtualMachine.cs";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Obfuz.Settings
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
public class FieldEncryptionSettings
|
||||||
|
{
|
||||||
|
[Tooltip("The encryption level for the obfuscation. Higher levels provide more security but may impact performance.")]
|
||||||
|
[Range(1, 4)]
|
||||||
|
public int encryptionLevel = 1;
|
||||||
|
|
||||||
|
[Tooltip("rule config xml files")]
|
||||||
|
public string[] ruleFiles;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
using Obfuz.ObfusPasses;
|
||||||
|
using System;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Obfuz.Settings
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
public class ObfuscationPassSettings
|
||||||
|
{
|
||||||
|
[Tooltip("enable obfuscation pass")]
|
||||||
|
public ObfuscationPassType enabledPasses = ObfuscationPassType.All;
|
||||||
|
|
||||||
|
[Tooltip("rule config xml files")]
|
||||||
|
public string[] ruleFiles;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.Remoting.Messaging;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditorInternal;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Obfuz.Settings
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
public class ObfuzSettings : ScriptableObject
|
||||||
|
{
|
||||||
|
[Tooltip("enable Obfuz")]
|
||||||
|
public bool enable = true;
|
||||||
|
|
||||||
|
[Tooltip("assembly settings")]
|
||||||
|
public AssemblySettings assemblySettings;
|
||||||
|
|
||||||
|
[Tooltip("obfuscation pass settings")]
|
||||||
|
public ObfuscationPassSettings obfuscationPassSettings;
|
||||||
|
|
||||||
|
[Tooltip("secret settings")]
|
||||||
|
public SecretSettings secretSettings;
|
||||||
|
|
||||||
|
[Tooltip("encryption virtual machine settings")]
|
||||||
|
public EncryptionVMSettings encryptionVMSettings;
|
||||||
|
|
||||||
|
[Tooltip("symbol obfuscation settings")]
|
||||||
|
public SymbolObfuscationSettings symbolObfusSettings;
|
||||||
|
|
||||||
|
[Tooltip("const encryption settings")]
|
||||||
|
public ConstEncryptionSettings constEncryptSettings;
|
||||||
|
|
||||||
|
[Tooltip("field encryption settings")]
|
||||||
|
public FieldEncryptionSettings fieldEncryptSettings;
|
||||||
|
|
||||||
|
[Tooltip("call obfuscation settings")]
|
||||||
|
public CallObfuscationSettings callObfusSettings;
|
||||||
|
|
||||||
|
public string ObfuzRootDir => $"Library/Obfuz";
|
||||||
|
|
||||||
|
public string GetObfuscatedAssemblyOutputPath(BuildTarget target)
|
||||||
|
{
|
||||||
|
return $"{ObfuzRootDir}/{target}/ObfuscatedAssemblies";
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetOriginalAssemblyBackupDir(BuildTarget target)
|
||||||
|
{
|
||||||
|
return $"{ObfuzRootDir}/{target}/OriginalAssemblies";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ObfuzSettings s_Instance;
|
||||||
|
|
||||||
|
public static ObfuzSettings Instance
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!s_Instance)
|
||||||
|
{
|
||||||
|
LoadOrCreate();
|
||||||
|
}
|
||||||
|
return s_Instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static string SettingsPath => "ProjectSettings/Obfuz.asset";
|
||||||
|
|
||||||
|
private static ObfuzSettings LoadOrCreate()
|
||||||
|
{
|
||||||
|
string filePath = SettingsPath;
|
||||||
|
var arr = InternalEditorUtility.LoadSerializedFileAndForget(filePath);
|
||||||
|
//Debug.Log($"typeof arr:{arr?.GetType()} arr[0]:{(arr != null && arr.Length > 0 ? arr[0].GetType(): null)}");
|
||||||
|
|
||||||
|
s_Instance = arr != null && arr.Length > 0 ? (ObfuzSettings)arr[0] : (s_Instance ?? CreateInstance<ObfuzSettings>());
|
||||||
|
return s_Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Save()
|
||||||
|
{
|
||||||
|
if (!s_Instance)
|
||||||
|
{
|
||||||
|
Debug.LogError("Cannot save ScriptableSingleton: no instance!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string filePath = SettingsPath;
|
||||||
|
string directoryName = Path.GetDirectoryName(filePath);
|
||||||
|
Directory.CreateDirectory(directoryName);
|
||||||
|
UnityEngine.Object[] obj = new ObfuzSettings[1] { s_Instance };
|
||||||
|
InternalEditorUtility.SaveToSerializedFileAndForget(obj, filePath, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditor.Presets;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UIElements;
|
||||||
|
|
||||||
|
namespace Obfuz.Settings
|
||||||
|
{
|
||||||
|
public class ObfuzSettingsProvider : SettingsProvider
|
||||||
|
{
|
||||||
|
|
||||||
|
private static ObfuzSettingsProvider s_provider;
|
||||||
|
|
||||||
|
[SettingsProvider]
|
||||||
|
public static SettingsProvider CreateMyCustomSettingsProvider()
|
||||||
|
{
|
||||||
|
if (s_provider == null)
|
||||||
|
{
|
||||||
|
s_provider = new ObfuzSettingsProvider();
|
||||||
|
using (var so = new SerializedObject(ObfuzSettings.Instance))
|
||||||
|
{
|
||||||
|
s_provider.keywords = GetSearchKeywordsFromSerializedObject(so);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s_provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private SerializedObject _serializedObject;
|
||||||
|
private SerializedProperty _enable;
|
||||||
|
private SerializedProperty _assemblySettings;
|
||||||
|
private SerializedProperty _obfuscationPassSettings;
|
||||||
|
private SerializedProperty _secretSettings;
|
||||||
|
private SerializedProperty _encryptionVMSettings;
|
||||||
|
|
||||||
|
private SerializedProperty _symbolObfusSettings;
|
||||||
|
private SerializedProperty _constEncryptSettings;
|
||||||
|
private SerializedProperty _fieldEncryptSettings;
|
||||||
|
private SerializedProperty _callObfusSettings;
|
||||||
|
|
||||||
|
public ObfuzSettingsProvider() : base("Project/Obfuz", SettingsScope.Project)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnActivate(string searchContext, VisualElement rootElement)
|
||||||
|
{
|
||||||
|
InitGUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnDeactivate()
|
||||||
|
{
|
||||||
|
base.OnDeactivate();
|
||||||
|
ObfuzSettings.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitGUI()
|
||||||
|
{
|
||||||
|
var setting = ObfuzSettings.Instance;
|
||||||
|
_serializedObject?.Dispose();
|
||||||
|
_serializedObject = new SerializedObject(setting);
|
||||||
|
_enable = _serializedObject.FindProperty("enable");
|
||||||
|
_assemblySettings = _serializedObject.FindProperty("assemblySettings");
|
||||||
|
_obfuscationPassSettings = _serializedObject.FindProperty("obfuscationPassSettings");
|
||||||
|
_secretSettings = _serializedObject.FindProperty("secretSettings");
|
||||||
|
|
||||||
|
_encryptionVMSettings = _serializedObject.FindProperty("encryptionVMSettings");
|
||||||
|
|
||||||
|
_symbolObfusSettings = _serializedObject.FindProperty("symbolObfusSettings");
|
||||||
|
_constEncryptSettings = _serializedObject.FindProperty("constEncryptSettings");
|
||||||
|
_fieldEncryptSettings = _serializedObject.FindProperty("fieldEncryptSettings");
|
||||||
|
_callObfusSettings = _serializedObject.FindProperty("callObfusSettings");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnGUI(string searchContext)
|
||||||
|
{
|
||||||
|
if (_serializedObject == null||!_serializedObject.targetObject)
|
||||||
|
{
|
||||||
|
InitGUI();
|
||||||
|
}
|
||||||
|
_serializedObject.Update();
|
||||||
|
EditorGUI.BeginChangeCheck();
|
||||||
|
|
||||||
|
EditorGUILayout.PropertyField(_enable);
|
||||||
|
EditorGUILayout.PropertyField(_assemblySettings);
|
||||||
|
EditorGUILayout.PropertyField(_obfuscationPassSettings);
|
||||||
|
EditorGUILayout.PropertyField(_secretSettings);
|
||||||
|
|
||||||
|
EditorGUILayout.PropertyField(_encryptionVMSettings);
|
||||||
|
|
||||||
|
EditorGUILayout.PropertyField(_symbolObfusSettings);
|
||||||
|
EditorGUILayout.PropertyField(_constEncryptSettings);
|
||||||
|
EditorGUILayout.PropertyField(_fieldEncryptSettings);
|
||||||
|
EditorGUILayout.PropertyField(_callObfusSettings);
|
||||||
|
|
||||||
|
|
||||||
|
if (EditorGUI.EndChangeCheck())
|
||||||
|
{
|
||||||
|
_serializedObject.ApplyModifiedProperties();
|
||||||
|
ObfuzSettings.Save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Obfuz.Settings
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
public class SecretSettings
|
||||||
|
{
|
||||||
|
|
||||||
|
[Tooltip("default static secret key")]
|
||||||
|
public string defaultStaticSecretKey = "Code Philosophy-Static";
|
||||||
|
|
||||||
|
[Tooltip("default dynamic secret key")]
|
||||||
|
public string defaultDynamicSecretKey = "Code Philosophy-Dynamic";
|
||||||
|
|
||||||
|
[Tooltip("secret key output path")]
|
||||||
|
public string secretKeyOutputPath = $"Assets/Resources/Obfuz";
|
||||||
|
|
||||||
|
[Tooltip("random seed")]
|
||||||
|
public int randomSeed = 0;
|
||||||
|
|
||||||
|
[Tooltip("name of assemblies those use dynamic secret key")]
|
||||||
|
public string[] assembliesUsingDynamicSecretKeys;
|
||||||
|
|
||||||
|
public string DefaultStaticSecretKeyOutputPath => Path.Combine(secretKeyOutputPath, "defaultStaticSecret.bytes");
|
||||||
|
|
||||||
|
public string DefaultDynamicSecretKeyOutputPath => Path.Combine(secretKeyOutputPath, "defaultDynamicSecret.bytes");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Obfuz.Settings
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
public class SymbolObfuscationSettings
|
||||||
|
{
|
||||||
|
public bool debug;
|
||||||
|
|
||||||
|
[Tooltip("prefix for obfuscated name to avoid name confliction with original name")]
|
||||||
|
public string obfuscatedNamePrefix = "$";
|
||||||
|
|
||||||
|
[Tooltip("obfuscate same namespace to one name")]
|
||||||
|
public bool useConsistentNamespaceObfuscation = true;
|
||||||
|
|
||||||
|
[Tooltip("symbol mapping file path")]
|
||||||
|
public string symbolMappingFile = "Assets/Obfuz/SymbolObfus/symbol-mapping.xml";
|
||||||
|
|
||||||
|
[Tooltip("rule files")]
|
||||||
|
public string[] ruleFiles;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Obfuz.Unity
|
||||||
|
{
|
||||||
|
public class ObfuscationBeginEventArgs
|
||||||
|
{
|
||||||
|
public string scriptAssembliesPath;
|
||||||
|
public string obfuscatedScriptAssembliesPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
namespace Obfuz.Unity
|
||||||
|
{
|
||||||
|
public class ObfuscationEndEventArgs
|
||||||
|
{
|
||||||
|
public bool success;
|
||||||
|
public string originalScriptAssembliesPath;
|
||||||
|
public string obfuscatedScriptAssembliesPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,124 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEditor.Build;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditor.Build.Reporting;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEditor.Compilation;
|
||||||
|
using Obfuz.Utils;
|
||||||
|
using FileUtil = Obfuz.Utils.FileUtil;
|
||||||
|
using Obfuz.Settings;
|
||||||
|
|
||||||
|
namespace Obfuz.Unity
|
||||||
|
{
|
||||||
|
|
||||||
|
#if UNITY_2019_1_OR_NEWER
|
||||||
|
public class ObfuscationProcess : IPostBuildPlayerScriptDLLs
|
||||||
|
{
|
||||||
|
public int callbackOrder => 10000;
|
||||||
|
|
||||||
|
public static event Action<ObfuscationBeginEventArgs> OnObfuscationBegin;
|
||||||
|
|
||||||
|
public static event Action<ObfuscationEndEventArgs> OnObfuscationEnd;
|
||||||
|
|
||||||
|
public void OnPostBuildPlayerScriptDLLs(BuildReport report)
|
||||||
|
{
|
||||||
|
#if !UNITY_2022_1_OR_NEWER
|
||||||
|
RunObfuscate(report.files);
|
||||||
|
#else
|
||||||
|
RunObfuscate(report.GetFiles());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void BackupOriginalDlls(string srcDir, string dstDir, HashSet<string> dllNames)
|
||||||
|
{
|
||||||
|
FileUtil.RecreateDir(dstDir);
|
||||||
|
foreach (string dllName in dllNames)
|
||||||
|
{
|
||||||
|
string srcFile = Path.Combine(srcDir, dllName);
|
||||||
|
string dstFile = Path.Combine(dstDir, dllName);
|
||||||
|
if (File.Exists(srcFile))
|
||||||
|
{
|
||||||
|
File.Copy(srcFile, dstFile, true);
|
||||||
|
Debug.Log($"BackupOriginalDll {srcFile} -> {dstFile}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RunObfuscate(BuildFile[] files)
|
||||||
|
{
|
||||||
|
ObfuzSettings settings = ObfuzSettings.Instance;
|
||||||
|
if (!settings.enable)
|
||||||
|
{
|
||||||
|
Debug.Log("Obfuscation is disabled.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Log("Obfuscation begin...");
|
||||||
|
var buildTarget = EditorUserBuildSettings.activeBuildTarget;
|
||||||
|
|
||||||
|
var obfuscationRelativeAssemblyNames = new HashSet<string>(settings.assemblySettings.GetObfuscationRelativeAssemblyNames());
|
||||||
|
string stagingAreaTempManagedDllDir = Path.GetDirectoryName(files.First(file => file.path.EndsWith(".dll")).path);
|
||||||
|
string backupPlayerScriptAssembliesPath = settings.GetOriginalAssemblyBackupDir(buildTarget);
|
||||||
|
BackupOriginalDlls(stagingAreaTempManagedDllDir, backupPlayerScriptAssembliesPath, obfuscationRelativeAssemblyNames);
|
||||||
|
|
||||||
|
string applicationContentsPath = EditorApplication.applicationContentsPath;
|
||||||
|
|
||||||
|
var obfuscatorBuilder = ObfuscatorBuilder.FromObfuzSettings(settings, buildTarget, false);
|
||||||
|
|
||||||
|
var assemblySearchDirs = new List<string>
|
||||||
|
{
|
||||||
|
stagingAreaTempManagedDllDir,
|
||||||
|
};
|
||||||
|
obfuscatorBuilder.InsertTopPriorityAssemblySearchPaths(assemblySearchDirs);
|
||||||
|
|
||||||
|
|
||||||
|
OnObfuscationBegin?.Invoke(new ObfuscationBeginEventArgs
|
||||||
|
{
|
||||||
|
scriptAssembliesPath = stagingAreaTempManagedDllDir,
|
||||||
|
obfuscatedScriptAssembliesPath = obfuscatorBuilder.ObfuscatedAssemblyOutputPath,
|
||||||
|
});
|
||||||
|
bool succ = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Obfuscator obfuz = obfuscatorBuilder.Build();
|
||||||
|
obfuz.Run();
|
||||||
|
|
||||||
|
foreach (var dllName in obfuscationRelativeAssemblyNames)
|
||||||
|
{
|
||||||
|
string src = $"{obfuscatorBuilder.ObfuscatedAssemblyOutputPath}/{dllName}.dll";
|
||||||
|
string dst = $"{stagingAreaTempManagedDllDir}/{dllName}.dll";
|
||||||
|
|
||||||
|
if (!File.Exists(src))
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"obfuscation assembly not found! skip copy. path:{src}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
File.Copy(src, dst, true);
|
||||||
|
Debug.Log($"obfuscate dll:{dst}");
|
||||||
|
}
|
||||||
|
succ = true;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
succ = false;
|
||||||
|
Debug.LogException(e);
|
||||||
|
Debug.LogError($"Obfuscation failed.");
|
||||||
|
}
|
||||||
|
OnObfuscationEnd?.Invoke(new ObfuscationEndEventArgs
|
||||||
|
{
|
||||||
|
success = succ,
|
||||||
|
originalScriptAssembliesPath = backupPlayerScriptAssembliesPath,
|
||||||
|
obfuscatedScriptAssembliesPath = stagingAreaTempManagedDllDir,
|
||||||
|
});
|
||||||
|
|
||||||
|
Debug.Log("Obfuscation end.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
using Obfuz.EncryptionVM;
|
||||||
|
using Obfuz.Settings;
|
||||||
|
using Obfuz.Utils;
|
||||||
|
using System.IO;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
using FileUtil = Obfuz.Utils.FileUtil;
|
||||||
|
|
||||||
|
namespace Obfuz.Unity
|
||||||
|
{
|
||||||
|
public static class ObfuzMenu
|
||||||
|
{
|
||||||
|
|
||||||
|
[MenuItem("Obfuz/Settings...", priority = 1)]
|
||||||
|
public static void OpenSettings() => SettingsService.OpenProjectSettings("Project/Obfuz");
|
||||||
|
|
||||||
|
[MenuItem("Obfuz/GenerateVM", priority = 62)]
|
||||||
|
public static void GenerateEncryptionVM()
|
||||||
|
{
|
||||||
|
EncryptionVMSettings settings = ObfuzSettings.Instance.encryptionVMSettings;
|
||||||
|
var generator = new VirtualMachineCodeGenerator(settings.codeGenerationSecretKey, settings.encryptionOpCodeCount);
|
||||||
|
generator.Generate(settings.codeOutputPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MenuItem("Obfuz/SaveSecretFile", priority = 63)]
|
||||||
|
public static void SaveSecretFile()
|
||||||
|
{
|
||||||
|
SecretSettings settings = ObfuzSettings.Instance.secretSettings;
|
||||||
|
|
||||||
|
var staticSecretBytes = KeyGenerator.GenerateKey(settings.defaultStaticSecretKey, VirtualMachine.SecretKeyLength);
|
||||||
|
SaveKey(staticSecretBytes, settings.DefaultStaticSecretKeyOutputPath);
|
||||||
|
Debug.Log($"Save static secret key to {settings.DefaultStaticSecretKeyOutputPath}");
|
||||||
|
var dynamicSecretBytes = KeyGenerator.GenerateKey(settings.defaultDynamicSecretKey, VirtualMachine.SecretKeyLength);
|
||||||
|
SaveKey(dynamicSecretBytes, settings.DefaultDynamicSecretKeyOutputPath);
|
||||||
|
Debug.Log($"Save dynamic secret key to {settings.DefaultDynamicSecretKeyOutputPath}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SaveKey(byte[] secret, string secretOutputPath)
|
||||||
|
{
|
||||||
|
FileUtil.CreateParentDir(secretOutputPath);
|
||||||
|
File.WriteAllBytes(secretOutputPath, secret);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MenuItem("Obfuz/Documents/Quick Start")]
|
||||||
|
public static void OpenQuickStart() => Application.OpenURL("https://obfuz.doc.code-philosophy.com/docs/beginner/quickstart");
|
||||||
|
|
||||||
|
[MenuItem("Obfuz/Documents/FAQ")]
|
||||||
|
public static void OpenFAQ() => Application.OpenURL("https://obfuz.doc.code-philosophy.com/docs/help/faq");
|
||||||
|
|
||||||
|
[MenuItem("Obfuz/Documents/Common Errors")]
|
||||||
|
public static void OpenCommonErrors() => Application.OpenURL("https://obfuz.doc.code-philosophy.com/docs/help/commonerrors");
|
||||||
|
|
||||||
|
[MenuItem("Obfuz/Documents/Bug Report")]
|
||||||
|
public static void OpenBugReport() => Application.OpenURL("https://obfuz.doc.code-philosophy.com/docs/help/issue");
|
||||||
|
|
||||||
|
[MenuItem("Obfuz/Documents/GitHub")]
|
||||||
|
public static void OpenGitHub() => Application.OpenURL("https://github.com/focus-creative-games/obfuz");
|
||||||
|
|
||||||
|
[MenuItem("Obfuz/Documents/About")]
|
||||||
|
public static void OpenAbout() => Application.OpenURL("https://obfuz.doc.code-philosophy.com/docs/intro");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.Utils
|
||||||
|
{
|
||||||
|
public class AssemblyCache
|
||||||
|
{
|
||||||
|
private readonly IAssemblyResolver _assemblyPathResolver;
|
||||||
|
private readonly ModuleContext _modCtx;
|
||||||
|
private readonly AssemblyResolver _asmResolver;
|
||||||
|
private bool _enableTypeDefCache;
|
||||||
|
|
||||||
|
|
||||||
|
public ModuleContext ModCtx => _modCtx;
|
||||||
|
|
||||||
|
public Dictionary<string, ModuleDefMD> LoadedModules { get; } = new Dictionary<string, ModuleDefMD>();
|
||||||
|
|
||||||
|
public AssemblyCache(IAssemblyResolver assemblyResolver)
|
||||||
|
{
|
||||||
|
_enableTypeDefCache = true;
|
||||||
|
_assemblyPathResolver = assemblyResolver;
|
||||||
|
_modCtx = ModuleDef.CreateModuleContext();
|
||||||
|
_asmResolver = (AssemblyResolver)_modCtx.AssemblyResolver;
|
||||||
|
_asmResolver.EnableTypeDefCache = _enableTypeDefCache;
|
||||||
|
_asmResolver.UseGAC = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EnableTypeDefCache
|
||||||
|
{
|
||||||
|
get => _enableTypeDefCache;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_enableTypeDefCache = value;
|
||||||
|
_asmResolver.EnableTypeDefCache = value;
|
||||||
|
foreach (var mod in LoadedModules.Values)
|
||||||
|
{
|
||||||
|
mod.EnableTypeDefFindCache = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public ModuleDefMD TryLoadModule(string moduleName)
|
||||||
|
{
|
||||||
|
string dllPath = _assemblyPathResolver.ResolveAssembly(moduleName);
|
||||||
|
if (string.IsNullOrEmpty(dllPath))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return LoadModule(moduleName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ModuleDefMD LoadModule(string moduleName)
|
||||||
|
{
|
||||||
|
// Debug.Log($"load module:{moduleName}");
|
||||||
|
if (LoadedModules.TryGetValue(moduleName, out var mod))
|
||||||
|
{
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
string assemblyPath = _assemblyPathResolver.ResolveAssembly(moduleName);
|
||||||
|
if (string.IsNullOrEmpty(assemblyPath))
|
||||||
|
{
|
||||||
|
throw new FileNotFoundException($"Assembly {moduleName} not found");
|
||||||
|
}
|
||||||
|
mod = DoLoadModule(assemblyPath);
|
||||||
|
LoadedModules.Add(moduleName, mod);
|
||||||
|
|
||||||
|
|
||||||
|
foreach (var refAsm in mod.GetAssemblyRefs())
|
||||||
|
{
|
||||||
|
LoadModule(refAsm.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ModuleDefMD DoLoadModule(string dllPath)
|
||||||
|
{
|
||||||
|
//Debug.Log($"do load module:{dllPath}");
|
||||||
|
ModuleDefMD mod = ModuleDefMD.Load(File.ReadAllBytes(dllPath), _modCtx);
|
||||||
|
mod.EnableTypeDefFindCache = _enableTypeDefCache;
|
||||||
|
_asmResolver.AddToCache(mod);
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.Utils
|
||||||
|
{
|
||||||
|
public abstract class AssemblyResolverBase : IAssemblyResolver
|
||||||
|
{
|
||||||
|
public abstract string ResolveAssembly(string assemblyName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.Utils
|
||||||
|
{
|
||||||
|
public static class CollectionExtensions
|
||||||
|
{
|
||||||
|
public static void AddRange<T>(this HashSet<T> values, IEnumerable<T> newValues)
|
||||||
|
{
|
||||||
|
foreach (var value in newValues)
|
||||||
|
{
|
||||||
|
values.Add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static V GetValueOrDefault<K, V>(this Dictionary<K, V> dic, K key)
|
||||||
|
{
|
||||||
|
return dic.TryGetValue(key, out V v) ? v : default(V);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue