diff --git a/.idea/.idea.BitMono/.idea/.gitignore b/.idea/.idea.BitMono/.idea/.gitignore new file mode 100644 index 00000000..332a1db9 --- /dev/null +++ b/.idea/.idea.BitMono/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/.idea.BitMono.iml +/projectSettingsUpdater.xml +/modules.xml +/contentModel.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/.idea.BitMono/.idea/codeStyles/codeStyleConfig.xml b/.idea/.idea.BitMono/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 00000000..a55e7a17 --- /dev/null +++ b/.idea/.idea.BitMono/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.BitMono/.idea/indexLayout.xml b/.idea/.idea.BitMono/.idea/indexLayout.xml new file mode 100644 index 00000000..7b08163c --- /dev/null +++ b/.idea/.idea.BitMono/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.BitMono/.idea/inspectionProfiles/Project_Default.xml b/.idea/.idea.BitMono/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 00000000..7e296f57 --- /dev/null +++ b/.idea/.idea.BitMono/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.BitMono/.idea/jsonSchemas.xml b/.idea/.idea.BitMono/.idea/jsonSchemas.xml new file mode 100644 index 00000000..75e77fa6 --- /dev/null +++ b/.idea/.idea.BitMono/.idea/jsonSchemas.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.BitMono/.idea/vcs.xml b/.idea/.idea.BitMono/.idea/vcs.xml new file mode 100644 index 00000000..35eb1ddf --- /dev/null +++ b/.idea/.idea.BitMono/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/BitMono.sln b/BitMono.sln index 40a70311..8d05fe4c 100644 --- a/BitMono.sln +++ b/BitMono.sln @@ -41,6 +41,22 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BitMono.Utilities", "src\Bi EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BitMono.GUI.Utilities", "src\BitMono.GUI.Utilities\BitMono.GUI.Utilities.csproj", "{452E19E6-E967-47BC-8F0D-04FD372BBC79}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{1EF50257-AFD3-48A3-9E22-03BDC25550A7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BitMono.Core.Tests", "test\BitMono.Core.Tests\BitMono.Core.Tests.csproj", "{A48CF019-9079-4CC1-8DC6-8EB6252B2071}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BitMono.Benchmarks", "test\BitMono.Benchmarks\BitMono.Benchmarks.csproj", "{3BF83671-AB38-4B91-82F2-40EA193E10DA}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestBinaries", "TestBinaries", "{EB40D287-0103-4693-8C26-7C3BC7C203B5}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DotNet", "DotNet", "{A431DCB4-6EF9-4BEF-8902-FA704D62624E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BitMono.Core.TestCases.CustomAttributes", "test\TestBinaries\DotNet\BitMono.Core.TestCases.CustomAttributes\BitMono.Core.TestCases.CustomAttributes.csproj", "{1D6B1BA7-496F-4F91-A115-EF5E5DC6E6C2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BitMono.Core.TestCases.Methods", "test\TestBinaries\DotNet\BitMono.Core.TestCases.Methods\BitMono.Core.TestCases.Methods.csproj", "{4166AC73-6969-406A-ADD0-67CB70A76D9C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BitMono.Core.TestCases.Types", "test\TestBinaries\DotNet\BitMono.Core.TestCases.Types\BitMono.Core.TestCases.Types.csproj", "{5DC793B1-F82B-4BC7-99C9-FE8C1545E1F7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -101,6 +117,26 @@ Global {452E19E6-E967-47BC-8F0D-04FD372BBC79}.Debug|Any CPU.Build.0 = Debug|Any CPU {452E19E6-E967-47BC-8F0D-04FD372BBC79}.Release|Any CPU.ActiveCfg = Release|Any CPU {452E19E6-E967-47BC-8F0D-04FD372BBC79}.Release|Any CPU.Build.0 = Release|Any CPU + {A48CF019-9079-4CC1-8DC6-8EB6252B2071}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A48CF019-9079-4CC1-8DC6-8EB6252B2071}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A48CF019-9079-4CC1-8DC6-8EB6252B2071}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A48CF019-9079-4CC1-8DC6-8EB6252B2071}.Release|Any CPU.Build.0 = Release|Any CPU + {3BF83671-AB38-4B91-82F2-40EA193E10DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3BF83671-AB38-4B91-82F2-40EA193E10DA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3BF83671-AB38-4B91-82F2-40EA193E10DA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3BF83671-AB38-4B91-82F2-40EA193E10DA}.Release|Any CPU.Build.0 = Release|Any CPU + {1D6B1BA7-496F-4F91-A115-EF5E5DC6E6C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1D6B1BA7-496F-4F91-A115-EF5E5DC6E6C2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1D6B1BA7-496F-4F91-A115-EF5E5DC6E6C2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1D6B1BA7-496F-4F91-A115-EF5E5DC6E6C2}.Release|Any CPU.Build.0 = Release|Any CPU + {4166AC73-6969-406A-ADD0-67CB70A76D9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4166AC73-6969-406A-ADD0-67CB70A76D9C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4166AC73-6969-406A-ADD0-67CB70A76D9C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4166AC73-6969-406A-ADD0-67CB70A76D9C}.Release|Any CPU.Build.0 = Release|Any CPU + {5DC793B1-F82B-4BC7-99C9-FE8C1545E1F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5DC793B1-F82B-4BC7-99C9-FE8C1545E1F7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5DC793B1-F82B-4BC7-99C9-FE8C1545E1F7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5DC793B1-F82B-4BC7-99C9-FE8C1545E1F7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -119,6 +155,13 @@ Global {40615C80-C80C-4C95-ABC3-3291C32197D8} = {D87066C4-1144-4BD8-96E9-9F4676001397} {34C08A60-E141-4FAD-975F-F447317CDA79} = {D87066C4-1144-4BD8-96E9-9F4676001397} {452E19E6-E967-47BC-8F0D-04FD372BBC79} = {D87066C4-1144-4BD8-96E9-9F4676001397} + {A48CF019-9079-4CC1-8DC6-8EB6252B2071} = {1EF50257-AFD3-48A3-9E22-03BDC25550A7} + {3BF83671-AB38-4B91-82F2-40EA193E10DA} = {1EF50257-AFD3-48A3-9E22-03BDC25550A7} + {EB40D287-0103-4693-8C26-7C3BC7C203B5} = {1EF50257-AFD3-48A3-9E22-03BDC25550A7} + {A431DCB4-6EF9-4BEF-8902-FA704D62624E} = {EB40D287-0103-4693-8C26-7C3BC7C203B5} + {1D6B1BA7-496F-4F91-A115-EF5E5DC6E6C2} = {A431DCB4-6EF9-4BEF-8902-FA704D62624E} + {4166AC73-6969-406A-ADD0-67CB70A76D9C} = {A431DCB4-6EF9-4BEF-8902-FA704D62624E} + {5DC793B1-F82B-4BC7-99C9-FE8C1545E1F7} = {A431DCB4-6EF9-4BEF-8902-FA704D62624E} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {7DA0BB43-C1D4-4688-BE43-A9ED2D6F78EE} diff --git a/CHANGELOG.md b/CHANGELOG.md index cc9c86ee..3393771e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ | Versions: | | - | +| [v0.7.0-alpha](#v070-alpha16) | | [v0.6.0-alpha](#v060-alpha15) | | [v0.4.4-alpha](#v044-alpha13) | | [v0.4.3-alpha](#v043-alpha12) | @@ -17,6 +18,23 @@ | [v0.1.0](#v010) | --- +### v0.7.0-alpha-16: +#### Added: +* Unit Tests +* Benchmarks +* Support of ObfuscateAssemblyAttribute +* New properties in obfuscation.json +* Ignore members with specific attribute, eg, [SerializeField], it can be edited in criticals.json + +#### Changed: +* Obfuscation process +* ObfuscationAttribute support +* Moved from .NET Framework 461 to .NET Framework 462 + +#### Fixed: +* [SerializableAttribute] support +* [MethodImpl(MethodImplOptions.NoInlining)] support + ### v0.6.0-alpha.15: #### Added: * New protection AntiDecompiler diff --git a/README.md b/README.md index 89c20e33..aa036073 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,13 @@

## BitMono -[![Build status](https://ci.appveyor.com/api/projects/status/8jh35hfno6riq25j?svg=true)](https://ci.appveyor.com/project/sunnamed434/bitmono) -[![Join the chat at https://gitter.im/BitMonoSpeech/community](https://badges.gitter.im/BitMonoSpeech/community.svg)](https://gitter.im/BitMonoSpeech/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Build status][image_build]][build] +[![Test status][image_test]][test] +[![Codefactor][image_codefactor]][codefactor] +[![Gitter Chat][image_gitter]][gitter] +[![MIT License][image_license]][license] -BitMono is an free open-source C# obfuscator which in mostly cases works **only** with Mono - well known as fork of .NET Framework but with custom bugs or Unity. Which uses its own fork of **[dnlib](https://github.com/sunnamed434/dnlib)** for assembly manipulation. If you have any questions/issues please let me know **[there](https://github.com/sunnamed434/BitMono/issues)**. You can install lastest version of BitMono **[here](https://github.com/sunnamed434/BitMono/releases)**. +BitMono is an free open-source C# obfuscator that in most cases works **only** with Mono - well known as a fork of .NET framework but for Unity, you can still use this for a whole .NET, but be careful that something working not as intentional, etc. Which uses **[AsmResolver][asmresolver]** for assembly manipulation. If you have any questions/issues please let me know **[there][bitmono_issues]**. You can install the latest version of BitMono **[here][bitmono_releases]**.

## Documentation -Open **[wiki](https://github.com/sunnamed434/BitMono/wiki)** to read protections functionnality and more. +Open the **[wiki][bitmono_wiki]** to read protection, functionality and more. -## How your app will look since BitMono obfuscation - just in a few-words -* Seems to C++ application but this is actual C# application +## How your app will look since BitMono obfuscation - just in a few words +* Looks like C++ application but is an actual C# application * Crash of decompilers when analyzing types * Broken decompilers * Broken IL Code @@ -42,11 +45,10 @@ Open **[wiki](https://github.com/sunnamed434/BitMono/wiki)** to read protections ## Obfuscation Features * StringsEncryption -* **[BitDotNet](https://github.com/0x59R11/BitDotNet)** (based and improved on existing protection) -* **[BitMethodDotnet](https://github.com/sunnamed434/BitMethodDotnet)** (based and improved on existing protection) -* **[DotNetHook](https://github.com/Elliesaur/DotNetHook)** (based on existing protection) +* **[BitDotNet][bitdotnet_source]** (based and improved on existing protection) +* **[BitMethodDotnet][bitmethoddotnet_source]** (based and improved on existing protection) +* **[DotNetHook][dotnethook_source]** (based on existing protection) * Call to calli -* FieldsHiding (Deprecated) * ObjectReturnType * NoNamespaces * FullRenamer @@ -57,18 +59,55 @@ Open **[wiki](https://github.com/sunnamed434/BitMono/wiki)** to read protections ## Usage `BitMono.CLI /drag-and-drop or use BitMono.GUI (GUI Windows only)` -Always drop dependencies in `libs` directory in the same path where is obfuscation `file` located +Always drop dependencies in `libs` directory in the same path where `file` for obfuscation is located -Credits -------- -**[0x59R11](https://github.com/0x59R11)** for his acquaintance in big part of **[BitDotNet](https://github.com/0x59R11/BitDotNet)** that breaks files for mono executables! - -**[Gazzi](https://github.com/GazziFX)** for his help that [me](https://github.com/sunnamed434) asked a lot! - -**[Elliesaur](https://github.com/Elliesaur)** for his acquaintance in **[DotNetHook](https://github.com/Elliesaur/DotNetHook)** that hooks methods. -**[Weka](https://github.com/sasharumega)** for his advices, help and motivation. +### Detailed build status +Branch | AppVeyor +------------- | ------------- +main | [![Build status][image_appveyor_main_badge]][appveyor_main_build] +dev | [![Build status][image_appveyor_dev_badge]][appveyor_dev_build] -**[ConfuserEx and their Forks](https://github.com/yck1509/ConfuserEx)** for most things that I watched for the architecture of BitMono and the obfuscator engine as an application and solving plenty of User solutions which I would be knew in the very long future after much fail usage of BitMono and reports by other Users. Day-by-day I'm looking for something interesting there to improve myself in knowledge and BitMono also. - -**[Kao and his blogs](https://lifeinhex.com/)** thanks a lot of these blogs. \ No newline at end of file +Credits +------- +**[0x59R11][author_0x59r11]** for his acquaintance in big part of **[BitDotNet][bitdotnet_source]** that breaks files for mono executables! + +**[Gazzi][author_gazzi]** for his help that [me][author_sunnamed434] asked a lot! + +**[Elliesaur][author_ellisaur]** for his acquaintance in **[DotNetHook][dotnethook_source]** that hooks methods. + +**[Weka][author_weka]** for his advices, help and motivation. + +**[ConfuserEx and their Forks][confuserex_source]** for most things that I watched for the architecture of BitMono and the obfuscator engine as an application and solving plenty of User solutions which I would be knew in the very long future after much fail usage of BitMono and reports by other Users. Day-by-day I'm looking for something interesting there to improve myself in knowledge and BitMono also. + +**[Kao and his blogs][author_kao_blog]** thanks a lot of these blogs. + +[build]: https://ci.appveyor.com/project/sunnamed434/bitmono +[test]: https://ci.appveyor.com/project/sunnamed434/bitmono/branch/main/tests +[codefactor]: https://www.codefactor.io/repository/github/sunnamed434/bitmono/overview/main +[gitter]: https://gitter.im/BitMonoSpeech/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge +[license]: https://github.com/sunnamed434/BitMono/blob/main/LICENSE +[asmresolver]: https://github.com/Washi1337/AsmResolver +[bitmono_issues]: https://github.com/sunnamed434/BitMono/issues +[bitmono_releases]: https://github.com/sunnamed434/BitMono/releases +[bitmono_wiki]: https://github.com/sunnamed434/BitMono/wiki +[bitdotnet_source]: https://github.com/0x59R11/BitDotNet +[bitmethoddotnet_source]: https://github.com/sunnamed434/BitMethodDotnet +[dotnethook_source]: https://github.com/Elliesaur/DotNetHook +[confuserex_source]: https://github.com/yck1509/ConfuserEx +[author_0x59r11]: https://github.com/0x59R11 +[author_gazzi]: https://github.com/GazziFX +[author_ellisaur]: https://github.com/Elliesaur +[author_weka]: https://github.com/sasharumega +[author_kao_blog]: https://lifeinhex.com/ +[author_sunnamed434]: https://github.com/sunnamed434 +[appveyor_main_build]: https://ci.appveyor.com/project/sunnamed434/bitmono/branch/main +[appveyor_dev_build]: https://ci.appveyor.com/project/sunnamed434/bitmono/branch/dev + +[image_build]: https://ci.appveyor.com/api/projects/status/8jh35hfno6riq25j?svg=true&style=plastic +[image_test]: https://img.shields.io/appveyor/tests/sunnamed434/bitmono/main?style=plastic +[image_codefactor]: https://www.codefactor.io/repository/github/sunnamed434/bitmono/badge/main +[image_gitter]: https://badges.gitter.im/BitMonoSpeech/community.svg?style=plastic +[image_license]: https://img.shields.io/github/license/sunnamed434/bitmono +[image_appveyor_main_badge]: https://ci.appveyor.com/api/projects/status/8jh35hfno6riq25j/branch/main?svg=true +[image_appveyor_dev_badge]: https://ci.appveyor.com/api/projects/status/b9rm3l7kduryjgcj/branch/dev?svg=true \ No newline at end of file diff --git a/src/BitMono.API/BitMono.API.csproj b/src/BitMono.API/BitMono.API.csproj index 3bfa22e5..e83d7cc3 100644 --- a/src/BitMono.API/BitMono.API.csproj +++ b/src/BitMono.API/BitMono.API.csproj @@ -1,7 +1,7 @@  - netstandard2.0;net461 + netstandard2.0;net462 10.0 @@ -21,6 +21,15 @@ none + + false + none + + + + none + + @@ -32,7 +41,7 @@ - + diff --git a/src/BitMono.API/Configuration/IBitMonoAppSettingsConfiguration.cs b/src/BitMono.API/Configuration/IBitMonoAppSettingsConfiguration.cs deleted file mode 100644 index c3b063bb..00000000 --- a/src/BitMono.API/Configuration/IBitMonoAppSettingsConfiguration.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace BitMono.API.Configuration; - -public interface IBitMonoAppSettingsConfiguration : IConfigurationAccessor -{ -} \ No newline at end of file diff --git a/src/BitMono.API/GlobalUsings.cs b/src/BitMono.API/GlobalUsings.cs index 20e43aa6..a0db9312 100644 --- a/src/BitMono.API/GlobalUsings.cs +++ b/src/BitMono.API/GlobalUsings.cs @@ -1,7 +1,6 @@ global using AsmResolver.DotNet; global using AsmResolver.DotNet.Builder; global using AsmResolver.DotNet.Serialized; -global using AsmResolver.PE.File.Headers; global using Autofac.Extensions.DependencyInjection; global using BitMono.API.Protecting.Contexts; global using Microsoft.Extensions.Configuration; diff --git a/src/BitMono.API/Protecting/Resolvers/CustomAttributeResolve.cs b/src/BitMono.API/Protecting/Resolvers/CustomAttributeResolve.cs index b7336c57..8579bdc1 100644 --- a/src/BitMono.API/Protecting/Resolvers/CustomAttributeResolve.cs +++ b/src/BitMono.API/Protecting/Resolvers/CustomAttributeResolve.cs @@ -2,6 +2,9 @@ public class CustomAttributeResolve { - public CustomAttribute CustomAttribute { get; set; } - public object Value { get; set; } + [AllowNull] + public Dictionary NamedValues { get; set; } + [AllowNull] + public List FixedValues { get; set; } + public CustomAttribute Attribute { get; set; } } \ No newline at end of file diff --git a/src/BitMono.API/Protecting/Resolvers/IAttemptAttributeResolver.cs b/src/BitMono.API/Protecting/Resolvers/IAttemptAttributeResolver.cs deleted file mode 100644 index 15e7cb8c..00000000 --- a/src/BitMono.API/Protecting/Resolvers/IAttemptAttributeResolver.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace BitMono.API.Protecting.Resolvers; - -public interface IAttemptAttributeResolver -{ - bool TryResolve(IHasCustomAttribute from, string @namespace, string name, out Dictionary keyValuePairs); -} \ No newline at end of file diff --git a/src/BitMono.API/Protecting/Resolvers/IAttributeResolver.cs b/src/BitMono.API/Protecting/Resolvers/IAttributeResolver.cs index 7e64e9c2..f637a05a 100644 --- a/src/BitMono.API/Protecting/Resolvers/IAttributeResolver.cs +++ b/src/BitMono.API/Protecting/Resolvers/IAttributeResolver.cs @@ -1,9 +1,10 @@ namespace BitMono.API.Protecting.Resolvers; -public interface IAttributeResolver +public interface IAttributeResolver + where TModel : class { - bool Resolve(string feature, IHasCustomAttribute from, out CustomAttributeResolve attributeResolve); - bool Resolve(string feature, IHasCustomAttribute from); + bool Resolve(string featureName, IHasCustomAttribute from, out TModel model); + bool Resolve(string featureName, IHasCustomAttribute from); bool Resolve(IHasCustomAttribute from); bool Resolve(Type featureType, IHasCustomAttribute from); bool Resolve(IHasCustomAttribute from) where TFeature : IProtection; diff --git a/src/BitMono.API/Protecting/Resolvers/ICustomAttributeResolver.cs b/src/BitMono.API/Protecting/Resolvers/ICustomAttributeResolver.cs deleted file mode 100644 index 007c871e..00000000 --- a/src/BitMono.API/Protecting/Resolvers/ICustomAttributeResolver.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace BitMono.API.Protecting.Resolvers; - -public interface ICustomAttributeResolver -{ - Dictionary Resolve(IHasCustomAttribute from, string @namespace, string name); -} \ No newline at end of file diff --git a/src/BitMono.API/Protecting/Resolvers/IModuleFileResolver.cs b/src/BitMono.API/Protecting/Resolvers/IModuleFileResolver.cs deleted file mode 100644 index 94e1d009..00000000 --- a/src/BitMono.API/Protecting/Resolvers/IModuleFileResolver.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace BitMono.API.Protecting.Resolvers; - -public interface IModuleFileResolver -{ - public Task ResolveAsync(); -} \ No newline at end of file diff --git a/src/BitMono.CLI/BitMono.CLI.csproj b/src/BitMono.CLI/BitMono.CLI.csproj index a8c434cd..56359c9b 100644 --- a/src/BitMono.CLI/BitMono.CLI.csproj +++ b/src/BitMono.CLI/BitMono.CLI.csproj @@ -2,13 +2,14 @@ Exe - net461 + net462 10.0 BitMonoLogo.ico none + false @@ -21,7 +22,7 @@ - + diff --git a/src/BitMono.CLI/GlobalUsings.cs b/src/BitMono.CLI/GlobalUsings.cs index 01593b22..0b2e6123 100644 --- a/src/BitMono.CLI/GlobalUsings.cs +++ b/src/BitMono.CLI/GlobalUsings.cs @@ -1,17 +1,12 @@ global using Autofac; -global using BitMono.API.Configuration; global using BitMono.API.Protecting; global using BitMono.API.Protecting.Resolvers; -global using BitMono.CLI; global using BitMono.CLI.Modules; -global using BitMono.Core.Extensions; global using BitMono.Core.Protecting.Resolvers; global using BitMono.Host; global using BitMono.Host.Modules; global using BitMono.Obfuscation; global using BitMono.Obfuscation.API; -global using BitMono.Shared.Models; -global using Microsoft.Extensions.Configuration; global using NullGuard; global using Serilog; global using System; @@ -22,4 +17,6 @@ global using System.Reflection; global using System.Threading; global using System.Threading.Tasks; +global using BitMono.Shared.Models; +global using Microsoft.Extensions.Options; global using ILogger = Serilog.ILogger; \ No newline at end of file diff --git a/src/BitMono.CLI/Models/NeededForObfuscation.cs b/src/BitMono.CLI/Models/NeededForObfuscation.cs deleted file mode 100644 index 52d31e54..00000000 --- a/src/BitMono.CLI/Models/NeededForObfuscation.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace BitMono.CLI; - -internal class NeededForObfuscation -{ - public string FileName { get; set; } - public string FileBaseDirectory { get; set; } - public string DependenciesDirectoryPath { get; set; } -} \ No newline at end of file diff --git a/src/BitMono.CLI/Modules/CLIBitMonoModuleFileResolver.cs b/src/BitMono.CLI/Modules/CLIBitMonoModuleFileResolver.cs index 950abbe9..ceb99c98 100644 --- a/src/BitMono.CLI/Modules/CLIBitMonoModuleFileResolver.cs +++ b/src/BitMono.CLI/Modules/CLIBitMonoModuleFileResolver.cs @@ -1,22 +1,15 @@ namespace BitMono.CLI.Modules; -internal class CLIBitMonoModuleFileResolver : IModuleFileResolver +internal class CLIBitMonoModuleFileResolver { - private readonly string[] m_Args; - - public CLIBitMonoModuleFileResolver(string[] args) - { - m_Args = args; - } - [return: AllowNull] - public Task ResolveAsync() + public string Resolve(string[] args) { string file = null; - if (m_Args?.Any() == true) + if (args?.Any() == true) { - file = m_Args[0]; + file = args[0]; } - return Task.FromResult(file); + return file; } } \ No newline at end of file diff --git a/src/BitMono.CLI/Modules/CLIObfuscationNeedsFactory.cs b/src/BitMono.CLI/Modules/CLIObfuscationNeedsFactory.cs new file mode 100644 index 00000000..91eb8499 --- /dev/null +++ b/src/BitMono.CLI/Modules/CLIObfuscationNeedsFactory.cs @@ -0,0 +1,96 @@ +namespace BitMono.CLI.Modules; + +public class CLIObfuscationNeedsFactory : IObfuscationNeedsFactory +{ + private readonly string[] m_Args; + + public CLIObfuscationNeedsFactory(string[] args) + { + m_Args = args; + } + + public ObfuscationNeeds Create() + { + var fileName = new CLIBitMonoModuleFileResolver().Resolve(m_Args); + var specifyingFile = true; + while (specifyingFile) + { + try + { + Console.WriteLine("Please, specify file or drag-and-drop in BitMono CLI"); + fileName = Console.ReadLine(); + if (string.IsNullOrWhiteSpace(fileName) == false) + { + if (File.Exists(fileName)) + { + specifyingFile = false; + Console.WriteLine("File succesfully specified: {0}", fileName); + } + else + { + Console.WriteLine("File cannot be found, please, try again!"); + } + } + else + { + Console.WriteLine("Unable to specify empty null or whitespace file, please, try again!"); + } + } + catch (Exception ex) + { + Console.WriteLine("Something went wrong while specifying the file: " + ex.ToString()); + } + } + + var fileBaseDirectory = Path.GetDirectoryName(fileName); + var dependenciesDirectoryName = Path.Combine(fileBaseDirectory, "libs"); + if (Directory.Exists(dependenciesDirectoryName) == false) + { + var specifyingDependencies = true; + while (specifyingDependencies) + { + try + { + Console.WriteLine("Please, specify dependencies (libs) path: "); + dependenciesDirectoryName = Console.ReadLine(); + if (string.IsNullOrWhiteSpace(dependenciesDirectoryName) == false) + { + if (Directory.Exists(dependenciesDirectoryName)) + { + Console.WriteLine("Dependencies (libs) succesfully specified: {0}!", dependenciesDirectoryName); + specifyingDependencies = false; + } + else + { + Console.WriteLine("Libs directory doesn't exist, please, try again!"); + } + } + else + { + Console.WriteLine("Unable to specify empty null or whitespace dependencies (libs), please, try again!"); + } + } + catch (Exception ex) + { + Console.WriteLine("Something went wrong while specifying the dependencies (libs) path: " + ex.ToString()); + } + } + } + else + { + Console.WriteLine("Dependencies (libs) directory was automatically found in: {0}!", dependenciesDirectoryName); + } + + var outputDirectoryName = Path.Combine(fileBaseDirectory, "output"); + Directory.CreateDirectory(outputDirectoryName); + Directory.CreateDirectory(dependenciesDirectoryName); + + return new ObfuscationNeeds + { + FileName = fileName, + FileBaseDirectory = fileBaseDirectory, + DependenciesDirectoryName = dependenciesDirectoryName, + OutputDirectoryName = outputDirectoryName + }; + } +} \ No newline at end of file diff --git a/src/BitMono.CLI/Program.cs b/src/BitMono.CLI/Program.cs index cacd4094..0147d8a5 100644 --- a/src/BitMono.CLI/Program.cs +++ b/src/BitMono.CLI/Program.cs @@ -1,147 +1,61 @@ -public class Program +namespace BitMono.CLI; + +internal class Program { private static async Task Main(string[] args) { try { const string ProtectionsFileName = nameof(BitMono) + "." + nameof(BitMono.Protections) + ".dll"; - - var neededForObfuscation = await specifyNeededForObfuscationAsync(args); - + + var needs = new CLIObfuscationNeedsFactory(args).Create(); Console.Clear(); - Console.WriteLine("File: {0}", neededForObfuscation.FileName); - Console.WriteLine("Dependencies (libs): {0}", neededForObfuscation.DependenciesDirectoryPath); + Console.WriteLine("File: {0}", needs.FileName); + Console.WriteLine("Dependencies (libs): {0}", needs.DependenciesDirectoryName); Console.WriteLine("Everything is seems to be good, starting obfuscation.."); var domainBaseDirectory = AppDomain.CurrentDomain.BaseDirectory; var protectionsFile = Path.Combine(domainBaseDirectory, ProtectionsFileName); Assembly.LoadFrom(protectionsFile); - - var outputDirectoryName = Path.Combine(neededForObfuscation.FileBaseDirectory, "output"); - Directory.CreateDirectory(neededForObfuscation.DependenciesDirectoryPath); - Directory.CreateDirectory(outputDirectoryName); - - var serviceProvider = new BitMonoApplication().RegisterModule(new BitMonoModule(configureLogger => + + var serviceProvider = new BitMonoApplication().RegisterModule(new BitMonoModule(configureLogger: configureLogger => { configureLogger.WriteTo.Async(configure => configure.Console( outputTemplate: "[{Timestamp:yyyy-MM-dd HH:mm:ss} {Level:u3}][{SourceContext}] {Message:lj}{NewLine}{Exception}")); })).Build(); - var obfuscationConfiguration = serviceProvider.LifetimeScope.Resolve(); - var protectionsConfiguration = serviceProvider.LifetimeScope.Resolve(); - var appSettingsConfiguration = serviceProvider.LifetimeScope.Resolve(); + var obfuscation = serviceProvider.LifetimeScope.Resolve>().Value; + var protectionSettings = serviceProvider.LifetimeScope.Resolve>().Value; var obfuscationAttributeResolver = serviceProvider.LifetimeScope.Resolve(); + var obfuscateAssemblyAttributeResolver = serviceProvider.LifetimeScope.Resolve(); var membersResolver = serviceProvider.LifetimeScope.Resolve>().ToList(); var protections = serviceProvider.LifetimeScope.Resolve>().ToList(); - var protectionSettings = protectionsConfiguration.GetProtectionSettings(); var logger = serviceProvider.LifetimeScope.Resolve().ForContext(); - var moduleDefMDWriter = new CLIDataWriter(); - var dependenciesDataResolver = new DependenciesDataResolver(neededForObfuscation.DependenciesDirectoryPath); - var bitMonoContextFactory = new BitMonoContextFactory(dependenciesDataResolver, obfuscationConfiguration); - var bitMonoContext = bitMonoContextFactory.Create(outputDirectoryName, neededForObfuscation.FileName); var cancellationTokenSource = new CancellationTokenSource(); - var engine = new BitMonoEngine(moduleDefMDWriter, obfuscationAttributeResolver, obfuscationConfiguration, membersResolver, protections, protectionSettings, logger); - var succeed = await engine.StartAsync(bitMonoContext, bitMonoContext.FileName, cancellationTokenSource.Token); + var engine = new BitMonoEngine(obfuscationAttributeResolver, obfuscateAssemblyAttributeResolver, + obfuscation, protectionSettings.Protections, membersResolver, protections, logger); + var succeed = await engine.StartAsync(needs, cancellationTokenSource.Token); if (succeed == false) { - logger.Fatal("Engine has issues, unable to continue, stop!"); + logger.Fatal("Engine has fatal issues, unable to continue!"); Console.ReadLine(); return; } - if (obfuscationConfiguration.Configuration.GetValue(nameof(Obfuscation.OpenFileDestinationInFileExplorer))) + if (obfuscation.OpenFileDestinationInFileExplorer) { - Process.Start(bitMonoContext.OutputDirectoryName); + Process.Start(needs.OutputDirectoryName); } - new TipsNotifier(appSettingsConfiguration, logger).Notify(); await serviceProvider.DisposeAsync(); } catch (Exception ex) { - Console.WriteLine("Something went wrong! " + ex.ToString()); + Console.WriteLine("Something went wrong! " + ex); } + Console.WriteLine("Press any key to exit!"); Console.ReadLine(); } - private static async Task specifyNeededForObfuscationAsync(string[] args) - { - var fileName = await new CLIBitMonoModuleFileResolver(args).ResolveAsync(); - var specifyingFile = true; - while (specifyingFile) - { - try - { - Console.WriteLine("Please, specify file or drag-and-drop in BitMono CLI"); - fileName = Console.ReadLine(); - if (string.IsNullOrWhiteSpace(fileName) == false) - { - if (File.Exists(fileName)) - { - specifyingFile = false; - Console.WriteLine("File succesfully specified: {0}", fileName); - } - else - { - Console.WriteLine("File cannot be found, please, try again!"); - } - } - else - { - Console.WriteLine("Unable to specify empty null or whitespace file, please, try again!"); - } - } - catch (Exception ex) - { - Console.WriteLine("Something went wrong while specifying the file: " + ex.ToString()); - } - } - - var fileBaseDirectory = Path.GetDirectoryName(fileName); - var dependenciesDirectoryName = Path.Combine(fileBaseDirectory, "libs"); - if (Directory.Exists(dependenciesDirectoryName) == false) - { - var specifyingDependencies = true; - while (specifyingDependencies) - { - try - { - Console.WriteLine("Please, specify dependencies (libs) path: "); - dependenciesDirectoryName = Console.ReadLine(); - if (string.IsNullOrWhiteSpace(dependenciesDirectoryName) == false) - { - if (Directory.Exists(dependenciesDirectoryName)) - { - Console.WriteLine("Dependencies (libs) succesfully specified: {0}!", dependenciesDirectoryName); - specifyingDependencies = false; - } - else - { - Console.WriteLine("Libs directory doesn't exist, please, try again!"); - } - } - else - { - Console.WriteLine("Unable to specify empty null or whitespace dependencies (libs), please, try again!"); - } - } - catch (Exception ex) - { - Console.WriteLine("Something went wrong while specifying the dependencies (libs) path: " + ex.ToString()); - } - } - } - else - { - Console.WriteLine("Dependencies (libs) directory was automatically found in: {0}!", dependenciesDirectoryName); - } - - return new NeededForObfuscation - { - FileName = fileName, - FileBaseDirectory = fileBaseDirectory, - DependenciesDirectoryPath = dependenciesDirectoryName, - }; - } } \ No newline at end of file diff --git a/src/BitMono.Core/BitMono.Core.csproj b/src/BitMono.Core/BitMono.Core.csproj index a7d8b57e..bdfb009a 100644 --- a/src/BitMono.Core/BitMono.Core.csproj +++ b/src/BitMono.Core/BitMono.Core.csproj @@ -1,7 +1,7 @@  - netstandard2.0;net461 + netstandard2.0;net462 10.0 @@ -21,6 +21,15 @@ none + + false + none + + + + none + + @@ -31,9 +40,10 @@ - + - + + diff --git a/src/BitMono.Core/Extensions/ConfigurationExtensions.cs b/src/BitMono.Core/Extensions/ConfigurationExtensions.cs index 5999d12e..b54b6618 100644 --- a/src/BitMono.Core/Extensions/ConfigurationExtensions.cs +++ b/src/BitMono.Core/Extensions/ConfigurationExtensions.cs @@ -2,41 +2,57 @@ public static class ConfigurationExtensions { - public static List GetProtectionSettings(this IBitMonoProtectionsConfiguration source) + public static List GetProtectionSettings(this IBitMonoProtectionsConfiguration source) { return source.Configuration.GetProtectionSettings(); } - public static List GetProtectionSettings(this IConfiguration source) + public static List GetCriticalModelAttributes(this IConfiguration source) { - return source.GetSection("Protections").Get>(); + return source.GetSection(nameof(Criticals.CriticalModelAttributes)).Get>(); + } + public static List GetCriticalModelAttributes(this IBitMonoProtectionsConfiguration source) + { + return GetCriticalModelAttributes(source.Configuration); + } + public static List GetProtectionSettings(this IConfiguration source) + { + return source.GetSection("Protections").Get>(); + } + public static List GetCriticalAttributes(this IBitMonoCriticalsConfiguration source) + { + return GetCriticalAttributes(source.Configuration); + } + public static List GetCriticalAttributes(this IConfiguration source) + { + return source.GetSection(nameof(Criticals.CriticalAttributes)).Get>(); } public static List GetCriticalMethods(this IBitMonoCriticalsConfiguration source) { - return source.GetCriticalMethods(); + return GetCriticalMethods(source.Configuration); } public static List GetCriticalMethods(this IConfiguration source) { - return source.GetSection("CriticalMethods").Get>(); + return source.GetSection(nameof(Criticals.CriticalMethods)).Get>(); } public static string[] GetCriticalInterfaces(this IBitMonoCriticalsConfiguration source) { - return source.Configuration.GetSection("CriticalInterfaces").Get(); + return source.Configuration.GetSection(nameof(Criticals.CriticalInterfaces)).Get(); } public static string[] GetCriticalInterfaces(this IConfiguration source) { - return source.GetSection("CriticalInterfaces").Get(); + return source.GetSection(nameof(Criticals.CriticalInterfaces)).Get(); } public static string[] GetCriticalBaseTypes(this IBitMonoCriticalsConfiguration source) { - return source.Configuration.GetSection("CriticalBaseTypes").Get(); + return source.Configuration.GetSection(nameof(Criticals.CriticalBaseTypes)).Get(); } public static string[] GetCriticalBaseTypes(this IConfiguration source) { - return source.GetSection("CriticalBaseTypes").Get(); + return source.GetSection(nameof(Criticals.CriticalBaseTypes)).Get(); } public static string[] GetSpecificNamespaces(this IBitMonoObfuscationConfiguration source) { - return source.Configuration.GetSpecificNamespaces(); + return GetSpecificNamespaces(source.Configuration); } public static string[] GetSpecificNamespaces(this IConfiguration source) { @@ -44,13 +60,13 @@ public static string[] GetSpecificNamespaces(this IConfiguration source) } public static string[] GetRandomStrings(this IBitMonoObfuscationConfiguration source) { - return source.Configuration.GetRandomStrings(); + return GetRandomStrings(source.Configuration); } public static string[] GetRandomStrings(this IConfiguration source) { return source.GetSection(nameof(Obfuscation.RandomStrings)).Get(); } - public static bool AsProtection(this ProtectionSettings source, ICollection protections, out IProtection result) + public static bool AsProtection(this ProtectionSetting source, ICollection protections, out IProtection result) { foreach (var protection in protections) { diff --git a/src/BitMono.Core/Extensions/CustomAttributeResolveValueExtensions.cs b/src/BitMono.Core/Extensions/CustomAttributeResolveValueExtensions.cs deleted file mode 100644 index f84a77ab..00000000 --- a/src/BitMono.Core/Extensions/CustomAttributeResolveValueExtensions.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace BitMono.Core.Extensions; - -public static class CustomAttributeResolveValueExtensions -{ - public static bool TryGetValueOrDefault(this Dictionary source, string key, bool defaultValue = false) - { - var value = defaultValue; - if (source.TryGetValue(key, out CustomAttributeResolve attributeResolve)) - { - if (attributeResolve.Value is bool resolveValue) - { - value = resolveValue; - } - } - return value; - } -} \ No newline at end of file diff --git a/src/BitMono.Core/Extensions/KeyValuePairsExtensions.cs b/src/BitMono.Core/Extensions/KeyValuePairsExtensions.cs new file mode 100644 index 00000000..44159037 --- /dev/null +++ b/src/BitMono.Core/Extensions/KeyValuePairsExtensions.cs @@ -0,0 +1,34 @@ +namespace BitMono.Core.Extensions; + +public static class KeyValuePairsExtensions +{ + public static string GetValueOrDefault(this Dictionary source, string key, string defaultValue = "") + { + var value = defaultValue; + if (source.TryGetTypedValue(key, out string valueValue)) + { + value = valueValue; + } + return value; + } + public static bool GetValueOrDefault(this Dictionary source, string key, bool defaultValue = false) + { + var value = defaultValue; + if (source.TryGetTypedValue(key, out bool valueValue)) + { + value = valueValue; + } + return value; + } + public static bool TryGetTypedValue(this IDictionary source, TKey key, [AllowNull] out TActual value) + where TActual : TValue + { + if (source.TryGetValue(key, out TValue tempValue)) + { + value = (TActual)tempValue; + return true; + } + value = default; + return false; + } +} \ No newline at end of file diff --git a/src/BitMono.Core/Extensions/RuntimeUtilities.cs b/src/BitMono.Core/Extensions/RuntimeUtilities.cs index 4c7bb45b..950e47e5 100644 --- a/src/BitMono.Core/Extensions/RuntimeUtilities.cs +++ b/src/BitMono.Core/Extensions/RuntimeUtilities.cs @@ -21,7 +21,8 @@ public static EnvironmentRuntimeInformation GetFrameworkInformation() var displayName = monoType.GetMethod(KnownMonoRuntimes.GetDisplayName, BindingFlags.NonPublic | BindingFlags.Static); if (displayName != null) { - monoDisplayName = displayName.ToString(); + var displayNameDelegate = (Func)displayName.CreateDelegate(typeof(Func), displayName); + monoDisplayName = displayNameDelegate.Invoke(); } } return _lastRuntimeInformation = new EnvironmentRuntimeInformation diff --git a/src/BitMono.Core/Extensions/StopwatchUtitilies.cs b/src/BitMono.Core/Extensions/StopwatchUtitilies.cs new file mode 100644 index 00000000..3a4141c0 --- /dev/null +++ b/src/BitMono.Core/Extensions/StopwatchUtitilies.cs @@ -0,0 +1,13 @@ +namespace BitMono.Core.Extensions; + +public static class StopwatchUtilities +{ + private const long TicksPerMillisecond = 10000; + private const long TicksPerSecond = TicksPerMillisecond * 1000; + + public static TimeSpan GetElapsedTime(long startingTimestamp, long endingTimestamp) + { + var tickFrequency = (double)TicksPerSecond / Stopwatch.Frequency; + return new TimeSpan((long)((endingTimestamp - startingTimestamp) * tickFrequency)); + } +} \ No newline at end of file diff --git a/src/BitMono.Core/GlobalUsings.cs b/src/BitMono.Core/GlobalUsings.cs index 48ac5d18..91041509 100644 --- a/src/BitMono.Core/GlobalUsings.cs +++ b/src/BitMono.Core/GlobalUsings.cs @@ -14,18 +14,19 @@ global using BitMono.Core.Protecting.Analyzing; global using BitMono.Core.Protecting.Attributes; global using BitMono.Core.Protecting.Injection; +global using BitMono.Core.Protecting.Resolvers; global using BitMono.Shared.Models; global using BitMono.Utilities.Extensions.AsmResolver; global using Microsoft.Extensions.Configuration; -global using MoreLinq; -global using Newtonsoft.Json; global using NullGuard; global using System; global using System.Collections.Generic; +global using System.Diagnostics; global using System.Linq; global using System.Reflection; global using System.Runtime.CompilerServices; global using System.Threading.Tasks; -global using System.Xml.Serialization; +global using Microsoft.Extensions.Options; +global using Pocket.Extensions; global using FieldAttributes = AsmResolver.PE.DotNet.Metadata.Tables.Rows.FieldAttributes; global using TypeAttributes = AsmResolver.PE.DotNet.Metadata.Tables.Rows.TypeAttributes; \ No newline at end of file diff --git a/src/BitMono.Core/Protecting/Analyzing/CriticalBaseTypesCriticalAnalyzer.cs b/src/BitMono.Core/Protecting/Analyzing/CriticalBaseTypesCriticalAnalyzer.cs index d25d8f94..ea8770f7 100644 --- a/src/BitMono.Core/Protecting/Analyzing/CriticalBaseTypesCriticalAnalyzer.cs +++ b/src/BitMono.Core/Protecting/Analyzing/CriticalBaseTypesCriticalAnalyzer.cs @@ -2,23 +2,23 @@ public class CriticalBaseTypesCriticalAnalyzer : ICriticalAnalyzer { - private readonly IConfiguration m_Configuration; + private readonly Criticals m_Criticals; - public CriticalBaseTypesCriticalAnalyzer(IBitMonoCriticalsConfiguration configuration) + public CriticalBaseTypesCriticalAnalyzer(IOptions criticals) { - m_Configuration = configuration.Configuration; + m_Criticals = criticals.Value; } - public bool NotCriticalToMakeChanges(TypeDefinition typeDefinition) + public bool NotCriticalToMakeChanges(TypeDefinition type) { - if (m_Configuration.GetValue("UseCriticalBaseTypes") == false) + if (m_Criticals.UseCriticalBaseTypes == false) { return true; } - if (typeDefinition.HasBaseType()) + if (type.HasBaseType()) { - var criticalBaseTypes = m_Configuration.GetCriticalBaseTypes(); - if (criticalBaseTypes.FirstOrDefault(c => c.StartsWith(typeDefinition.BaseType.Name.Value.Split('`')[0])) != null) + var criticalBaseTypes = m_Criticals.CriticalBaseTypes; + if (criticalBaseTypes.FirstOrDefault(c => c.StartsWith(type.BaseType.Name.Value.Split('`')[0])) != null) { return false; } diff --git a/src/BitMono.Core/Protecting/Analyzing/CriticalInterfacesCriticalAnalyzer.cs b/src/BitMono.Core/Protecting/Analyzing/CriticalInterfacesCriticalAnalyzer.cs index d53183bb..d526662b 100644 --- a/src/BitMono.Core/Protecting/Analyzing/CriticalInterfacesCriticalAnalyzer.cs +++ b/src/BitMono.Core/Protecting/Analyzing/CriticalInterfacesCriticalAnalyzer.cs @@ -1,24 +1,22 @@ -using BitMono.Core.Extensions; - -namespace BitMono.Core.Protecting.Analyzing; +namespace BitMono.Core.Protecting.Analyzing; public class CriticalInterfacesCriticalAnalyzer : ICriticalAnalyzer { - private readonly IConfiguration m_Configuration; + private readonly Criticals m_Criticals; - public CriticalInterfacesCriticalAnalyzer(IBitMonoCriticalsConfiguration configuration) + public CriticalInterfacesCriticalAnalyzer(IOptions criticals) { - m_Configuration = configuration.Configuration; + m_Criticals = criticals.Value; } - public bool NotCriticalToMakeChanges(TypeDefinition typeDefinition) + public bool NotCriticalToMakeChanges(TypeDefinition type) { - if (m_Configuration.GetValue("UseCriticalInterfaces") == false) + if (m_Criticals.UseCriticalInterfaces == false) { return true; } - var criticalInterfaces = m_Configuration.GetCriticalInterfaces(); - if (typeDefinition.Interfaces.Any(i => criticalInterfaces.FirstOrDefault(c => c.Equals(i.Interface.Name)) != null)) + var criticalInterfaces = m_Criticals.CriticalInterfaces; + if (type.Interfaces.Any(i => criticalInterfaces.FirstOrDefault(c => c.Equals(i.Interface.Name)) != null)) { return false; } diff --git a/src/BitMono.Core/Protecting/Analyzing/CriticalMethodsCriticalAnalyzer.cs b/src/BitMono.Core/Protecting/Analyzing/CriticalMethodsCriticalAnalyzer.cs index 7083171d..2c9ae608 100644 --- a/src/BitMono.Core/Protecting/Analyzing/CriticalMethodsCriticalAnalyzer.cs +++ b/src/BitMono.Core/Protecting/Analyzing/CriticalMethodsCriticalAnalyzer.cs @@ -1,27 +1,25 @@ -using BitMono.Core.Extensions; - -namespace BitMono.Core.Protecting.Analyzing; +namespace BitMono.Core.Protecting.Analyzing; public class CriticalMethodsCriticalAnalyzer : ICriticalAnalyzer { - private readonly IConfiguration m_Configuration; + private readonly Criticals m_Criticals; - public CriticalMethodsCriticalAnalyzer(IBitMonoCriticalsConfiguration configuration) + public CriticalMethodsCriticalAnalyzer(IOptions criticals) { - m_Configuration = configuration.Configuration; + m_Criticals = criticals.Value; } public bool NotCriticalToMakeChanges(MethodDefinition method) { - if (m_Configuration.GetValue("UseCriticalMethods") == false) + if (m_Criticals.UseCriticalMethods == false) { return true; } - var criticalMethodNames = m_Configuration.GetCriticalMethods(); - if (criticalMethodNames.Any(c => c.Equals(method.Name)) == false) + var criticalMethodNames = m_Criticals.CriticalMethods; + if (criticalMethodNames.Any(c => c.Equals(method.Name))) { - return true; + return false; } - return false; + return true; } } \ No newline at end of file diff --git a/src/BitMono.Core/Protecting/Analyzing/ModelAttributeCriticalAnalyzer.cs b/src/BitMono.Core/Protecting/Analyzing/ModelAttributeCriticalAnalyzer.cs index b8056aa0..2c971fad 100644 --- a/src/BitMono.Core/Protecting/Analyzing/ModelAttributeCriticalAnalyzer.cs +++ b/src/BitMono.Core/Protecting/Analyzing/ModelAttributeCriticalAnalyzer.cs @@ -2,35 +2,28 @@ public class ModelAttributeCriticalAnalyzer : ICriticalAnalyzer { - private readonly IConfiguration m_Configuration; - private readonly IAttemptAttributeResolver m_AttemptAttributeResolver; - private readonly Dictionary m_Attributes = new Dictionary - { - { nameof(SerializableAttribute), typeof(SerializableAttribute).Namespace }, - { nameof(XmlAttributeAttribute), typeof(XmlAttributeAttribute).Namespace }, - { nameof(XmlArrayItemAttribute), typeof(XmlArrayItemAttribute).Namespace }, - { nameof(JsonPropertyAttribute), typeof(JsonPropertyAttribute).Namespace }, - }; + private readonly Criticals m_Criticals; + private readonly AttemptAttributeResolver m_AttemptAttributeResolver; - public ModelAttributeCriticalAnalyzer(IBitMonoObfuscationConfiguration configuration, IAttemptAttributeResolver attemptAttributeResolver) + public ModelAttributeCriticalAnalyzer(IOptions criticals, AttemptAttributeResolver attemptAttributeResolver) { - m_Configuration = configuration.Configuration; + m_Criticals = criticals.Value; m_AttemptAttributeResolver = attemptAttributeResolver; } public bool NotCriticalToMakeChanges(IHasCustomAttribute customAttribute) { - if (m_Configuration.GetValue(nameof(Shared.Models.Obfuscation.ModelAttributeObfuscationExclude)) == false) + if (m_Criticals.UseCriticalModelAttributes == false) { return true; } - foreach (var attribute in m_Attributes) + foreach (var attribute in m_Criticals.CriticalModelAttributes) { - if (m_AttemptAttributeResolver.TryResolve(customAttribute, attribute.Value, attribute.Key, out _)) + if (m_AttemptAttributeResolver.TryResolve(customAttribute, attribute.Namespace, attribute.Name)) { return false; } } - return false; + return true; } } \ No newline at end of file diff --git a/src/BitMono.Core/Protecting/Analyzing/SerializableBitCriticalAnalyzer.cs b/src/BitMono.Core/Protecting/Analyzing/SerializableBitCriticalAnalyzer.cs new file mode 100644 index 00000000..d35d4fd7 --- /dev/null +++ b/src/BitMono.Core/Protecting/Analyzing/SerializableBitCriticalAnalyzer.cs @@ -0,0 +1,24 @@ +namespace BitMono.Core.Protecting.Analyzing; + +public class SerializableBitCriticalAnalyzer : ICriticalAnalyzer +{ + private readonly Obfuscation m_Obfuscation; + + public SerializableBitCriticalAnalyzer(IOptions obfuscation) + { + m_Obfuscation = obfuscation.Value; + } + + public bool NotCriticalToMakeChanges(TypeDefinition type) + { + if (m_Obfuscation.SerializableBitObfuscationExclude == false) + { + return true; + } + if (type.IsSerializable) + { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/src/BitMono.Core/Protecting/Analyzing/SpecificNamespaceCriticalAnalyzer.cs b/src/BitMono.Core/Protecting/Analyzing/SpecificNamespaceCriticalAnalyzer.cs index 485fa716..038ac090 100644 --- a/src/BitMono.Core/Protecting/Analyzing/SpecificNamespaceCriticalAnalyzer.cs +++ b/src/BitMono.Core/Protecting/Analyzing/SpecificNamespaceCriticalAnalyzer.cs @@ -1,24 +1,21 @@ -using BitMono.Core.Extensions; - -namespace BitMono.Core.Protecting.Analyzing; +namespace BitMono.Core.Protecting.Analyzing; public class SpecificNamespaceCriticalAnalyzer : ICriticalAnalyzer { - private readonly IConfiguration m_Configuration; + private readonly Obfuscation m_Obfuscation; - public SpecificNamespaceCriticalAnalyzer(IBitMonoObfuscationConfiguration configuration) + public SpecificNamespaceCriticalAnalyzer(IOptions obfuscation) { - m_Configuration = configuration.Configuration; + m_Obfuscation = obfuscation.Value; } public bool NotCriticalToMakeChanges(IMetadataMember member) { - if (m_Configuration.GetValue(nameof(Obfuscation.SpecificNamespacesObfuscationOnly)) == false) + if (m_Obfuscation.SpecificNamespacesObfuscationOnly == false) { return true; } - - var specificNamespaces = m_Configuration.GetSpecificNamespaces(); + var specificNamespaces = m_Obfuscation.SpecificNamespaces; if (member is TypeDefinition type && type.HasNamespace()) { if (specificNamespaces.Any(s => s.Equals(type.Namespace.Value)) == false) diff --git a/src/BitMono.Core/Protecting/Injection/Modifies.cs b/src/BitMono.Core/Protecting/Injection/ModifyFlags.cs similarity index 89% rename from src/BitMono.Core/Protecting/Injection/Modifies.cs rename to src/BitMono.Core/Protecting/Injection/ModifyFlags.cs index 84c2d683..b9602684 100644 --- a/src/BitMono.Core/Protecting/Injection/Modifies.cs +++ b/src/BitMono.Core/Protecting/Injection/ModifyFlags.cs @@ -1,7 +1,7 @@ namespace BitMono.Core.Protecting.Injection; [Flags] -public enum Modifies +public enum ModifyFlags { Rename = 0x1, RemoveNamespace = 0x2, diff --git a/src/BitMono.Core/Protecting/Injection/ModifyInjectTypeClonerListener.cs b/src/BitMono.Core/Protecting/Injection/ModifyInjectTypeClonerListener.cs index c2a1572d..5487614f 100644 --- a/src/BitMono.Core/Protecting/Injection/ModifyInjectTypeClonerListener.cs +++ b/src/BitMono.Core/Protecting/Injection/ModifyInjectTypeClonerListener.cs @@ -2,26 +2,26 @@ public class ModifyInjectTypeClonerListener : InjectTypeClonerListener { - public ModifyInjectTypeClonerListener(Modifies modifies, IRenamer renamer, ModuleDefinition targetModule) : base(targetModule) + public ModifyInjectTypeClonerListener(ModifyFlags modify, IRenamer renamer, ModuleDefinition targetModule) : base(targetModule) { - Modifies = modifies; + Modify = modify; Renamer = renamer; } - public Modifies Modifies { get; } + public ModifyFlags Modify { get; } public IRenamer Renamer { get; } public override void OnClonedMember(IMemberDefinition original, IMemberDefinition cloned) { - if (Modifies.HasFlag(Modifies.Rename)) + if (Modify.HasFlag(ModifyFlags.Rename)) { Renamer.Rename(cloned); } - if (Modifies.HasFlag(Modifies.RemoveNamespace)) + if (Modify.HasFlag(ModifyFlags.RemoveNamespace)) { Renamer.RemoveNamespace(cloned); } - if (Modifies.HasFlag(Modifies.EmptyMethodParameterName)) + if (Modify.HasFlag(ModifyFlags.EmptyMethodParameterName)) { if (cloned is MethodDefinition method) { diff --git a/src/BitMono.Core/Protecting/Injection/MscrolibInjector.cs b/src/BitMono.Core/Protecting/Injection/MscrolibInjector.cs index 2639dd9c..83d9de55 100644 --- a/src/BitMono.Core/Protecting/Injection/MscrolibInjector.cs +++ b/src/BitMono.Core/Protecting/Injection/MscrolibInjector.cs @@ -61,9 +61,9 @@ public CustomAttribute InjectAttribute(ModuleDefinition module, string @namespac public TypeDefinition CreateCompilerGeneratedType(ModuleDefinition module, string name = null) { var @object = module.CorLibTypeFactory.Object.ToTypeDefOrRef(); - var invislbeType = new TypeDefinition(null, name ?? "", TypeAttributes.Public, @object); - InjectCompilerGeneratedAttribute(module, invislbeType); - return invislbeType; + var invisibleType = new TypeDefinition(null, name ?? "", TypeAttributes.Public, @object); + InjectCompilerGeneratedAttribute(module, invisibleType); + return invisibleType; } public TypeDefinition CreateCompilerGeneratedValueType(ModuleDefinition module, string name = null) { diff --git a/src/BitMono.Core/Protecting/Renaming/Renamer.cs b/src/BitMono.Core/Protecting/Renaming/Renamer.cs index ca46fa72..7d4b016e 100644 --- a/src/BitMono.Core/Protecting/Renaming/Renamer.cs +++ b/src/BitMono.Core/Protecting/Renaming/Renamer.cs @@ -4,24 +4,24 @@ public class Renamer : IRenamer { private readonly NameCriticalAnalyzer m_NameCriticalAnalyzer; private readonly SpecificNamespaceCriticalAnalyzer m_SpecificNamespaceCriticalAnalyzer; - private readonly IConfiguration m_Configuration; + private readonly Obfuscation m_Obfuscation; private readonly Random m_Random; public Renamer( NameCriticalAnalyzer nameCriticalAnalyzer, SpecificNamespaceCriticalAnalyzer specificNamespaceCriticalAnalyzer, - IBitMonoObfuscationConfiguration configuration, + IOptions configuration, RuntimeImplementations runtime) { m_NameCriticalAnalyzer = nameCriticalAnalyzer; m_SpecificNamespaceCriticalAnalyzer = specificNamespaceCriticalAnalyzer; - m_Configuration = configuration.Configuration; + m_Obfuscation = configuration.Value; m_Random = runtime.Random; } public string RenameUnsafely() { - var strings = m_Configuration.GetRandomStrings(); + var strings = m_Obfuscation.RandomStrings; var randomStringOne = strings[m_Random.Next(0, strings.Length - 1)] + " " + strings[m_Random.Next(0, strings.Length - 1)]; var randomStringTwo = strings[m_Random.Next(0, strings.Length - 1)]; var randomStringThree = strings[m_Random.Next(0, strings.Length - 1)]; @@ -82,6 +82,6 @@ public void RemoveNamespace(IMetadataMember member) } public void RemoveNamespace(params IMetadataMember[] members) { - members.ForEach(member => RemoveNamespace(member)); + members.ForEach(RemoveNamespace); } } \ No newline at end of file diff --git a/src/BitMono.Core/Protecting/Resolvers/AttemptAttributeResolver.cs b/src/BitMono.Core/Protecting/Resolvers/AttemptAttributeResolver.cs index ce209141..50fda2ad 100644 --- a/src/BitMono.Core/Protecting/Resolvers/AttemptAttributeResolver.cs +++ b/src/BitMono.Core/Protecting/Resolvers/AttemptAttributeResolver.cs @@ -1,21 +1,21 @@ namespace BitMono.Core.Protecting.Resolvers; -public class AttemptAttributeResolver : IAttemptAttributeResolver +public class AttemptAttributeResolver { - private readonly ICustomAttributeResolver m_CustomAttributesResolver; + private readonly CustomAttributeResolver m_CustomAttributesResolver; - public AttemptAttributeResolver(ICustomAttributeResolver customAttributesResolver) + public AttemptAttributeResolver(CustomAttributeResolver customAttributesResolver) { m_CustomAttributesResolver = customAttributesResolver; } - public bool TryResolve(IHasCustomAttribute from, string @namespace, string name, [AllowNull] out Dictionary keyValuePairs) + public bool TryResolve(IHasCustomAttribute from, string @namespace, string name, [AllowNull] out IEnumerable attributesResolve) { - keyValuePairs = m_CustomAttributesResolver.Resolve(from, @namespace, name); - if (keyValuePairs != null) - { - return true; - } - return false; + attributesResolve = m_CustomAttributesResolver.Resolve(from, @namespace, name); + return attributesResolve.IsNullOrEmpty() == false; + } + public bool TryResolve(IHasCustomAttribute from, string @namespace, string name) + { + return TryResolve(from, @namespace, name, out _); } } \ No newline at end of file diff --git a/src/BitMono.Core/Protecting/Resolvers/AttributeResolver.cs b/src/BitMono.Core/Protecting/Resolvers/AttributeResolver.cs index 65c51273..533c76b3 100644 --- a/src/BitMono.Core/Protecting/Resolvers/AttributeResolver.cs +++ b/src/BitMono.Core/Protecting/Resolvers/AttributeResolver.cs @@ -1,19 +1,19 @@ namespace BitMono.Core.Protecting.Resolvers; -public class AttributeResolver : IAttributeResolver +public class AttributeResolver : IAttributeResolver where TModel : class { - public virtual bool Resolve([AllowNull] string feature, IHasCustomAttribute from, [AllowNull] out CustomAttributeResolve attributeResolve) + public virtual bool Resolve([AllowNull] string featureName, IHasCustomAttribute from, [AllowNull] out TModel model) { - attributeResolve = null; + model = default; return false; } - public virtual bool Resolve([AllowNull] string feature, IHasCustomAttribute from) + public virtual bool Resolve([AllowNull] string featureName, IHasCustomAttribute from) { - return Resolve(feature, from, out _); + return Resolve(featureName, from, out _); } public virtual bool Resolve(IHasCustomAttribute from) { - return Resolve(feature: null, from); + return Resolve(featureName: null, from); } public virtual bool Resolve(Type featureType, IHasCustomAttribute from) { diff --git a/src/BitMono.Core/Protecting/Resolvers/CriticalAttributeResolver.cs b/src/BitMono.Core/Protecting/Resolvers/CriticalAttributeResolver.cs new file mode 100644 index 00000000..d698d343 --- /dev/null +++ b/src/BitMono.Core/Protecting/Resolvers/CriticalAttributeResolver.cs @@ -0,0 +1,31 @@ +namespace BitMono.Core.Protecting.Resolvers; + +public class CriticalAttributeResolver : AttributeResolver +{ + private readonly Criticals m_Criticals; + private readonly AttemptAttributeResolver m_AttemptAttributeResolver; + + public CriticalAttributeResolver(IOptions criticals, AttemptAttributeResolver attemptAttributeResolver) + { + m_Criticals = criticals.Value; + m_AttemptAttributeResolver = attemptAttributeResolver; + } + + public override bool Resolve([AllowNull] string feature, IHasCustomAttribute from, [AllowNull] out CustomAttributeResolve attributeResolve) + { + attributeResolve = null; + if (m_Criticals.UseCriticalAttributes == false) + { + return false; + } + foreach (var criticalAttribute in m_Criticals.CriticalAttributes) + { + if (m_AttemptAttributeResolver.TryResolve(from, criticalAttribute.Namespace, criticalAttribute.Name, out var attributesResolve)) + { + attributeResolve = attributesResolve.First(); + return true; + } + } + return false; + } +} \ No newline at end of file diff --git a/src/BitMono.Core/Protecting/Resolvers/CustomAttributeResolver.cs b/src/BitMono.Core/Protecting/Resolvers/CustomAttributeResolver.cs index 3976bc68..a33f73b2 100644 --- a/src/BitMono.Core/Protecting/Resolvers/CustomAttributeResolver.cs +++ b/src/BitMono.Core/Protecting/Resolvers/CustomAttributeResolver.cs @@ -1,37 +1,46 @@ namespace BitMono.Core.Protecting.Resolvers; -public class CustomAttributeResolver : ICustomAttributeResolver +public class CustomAttributeResolver { [return: AllowNull] - public Dictionary Resolve(IHasCustomAttribute from, string @namespace, string name) + public IEnumerable Resolve(IHasCustomAttribute from, string @namespace, string name) { - var keyValuePairs = new Dictionary(); for (var i = 0; i < from.CustomAttributes.Count; i++) { var customAttribute = from.CustomAttributes[i]; - foreach (var namedArgument in customAttribute.Signature.NamedArguments) + if (customAttribute.Constructor.DeclaringType.IsTypeOf(@namespace, name)) { - if (customAttribute.Constructor.DeclaringType.IsTypeOf(@namespace, name)) + var namedValues = new Dictionary(); + var fixedValues = new List(); + foreach (var namedArgument in customAttribute.Signature.NamedArguments) { if (namedArgument.Argument.Element is Utf8String utf8String) { - keyValuePairs.Add(namedArgument.MemberName.Value, new CustomAttributeResolve - { - Value = utf8String.Value, - CustomAttribute = customAttribute - }); + namedValues.Add(namedArgument.MemberName.Value, utf8String.Value); } else { - keyValuePairs.Add(namedArgument.MemberName.Value, new CustomAttributeResolve - { - Value = namedArgument.Argument.Element, - CustomAttribute = customAttribute - }); + namedValues.Add(namedArgument.MemberName.Value, namedArgument.Argument.Element); } } + foreach (var fixedArgument in customAttribute.Signature.FixedArguments) + { + if (fixedArgument.Element is Utf8String utf8String) + { + fixedValues.Add(utf8String.Value); + } + else + { + fixedValues.Add(fixedArgument.Element); + } + } + yield return new CustomAttributeResolve + { + NamedValues = namedValues, + FixedValues = fixedValues, + Attribute = customAttribute + }; } } - return keyValuePairs; } } \ No newline at end of file diff --git a/src/BitMono.Core/Protecting/Resolvers/NoInliningMethodMemberResolver.cs b/src/BitMono.Core/Protecting/Resolvers/NoInliningMethodMemberResolver.cs index bd3b7880..9a6e718e 100644 --- a/src/BitMono.Core/Protecting/Resolvers/NoInliningMethodMemberResolver.cs +++ b/src/BitMono.Core/Protecting/Resolvers/NoInliningMethodMemberResolver.cs @@ -2,26 +2,26 @@ public class NoInliningMethodMemberResolver : IMemberResolver { - private readonly IConfiguration m_Configuration; + private readonly Obfuscation m_Obfuscation; - public NoInliningMethodMemberResolver(IBitMonoObfuscationConfiguration configuration) + public NoInliningMethodMemberResolver(IOptions obfuscation) { - m_Configuration = configuration.Configuration; + m_Obfuscation = obfuscation.Value; } - public bool Resolve(IProtection protection, IMetadataMember member) + public bool Resolve([AllowNull] IProtection protection, IMetadataMember member) { - if (m_Configuration.GetValue(nameof(Obfuscation.NoInliningMethodObfuscationExclude)) == false) + if (m_Obfuscation.NoInliningMethodObfuscationExclude == false) { - return false; + return true; } if (member is MethodDefinition method) { if (method.NoInlining) { - return true; + return false; } } - return false; + return true; } } diff --git a/src/BitMono.Core/Protecting/Resolvers/ObfuscateAssemblyAttributeData.cs b/src/BitMono.Core/Protecting/Resolvers/ObfuscateAssemblyAttributeData.cs new file mode 100644 index 00000000..e7ff9d21 --- /dev/null +++ b/src/BitMono.Core/Protecting/Resolvers/ObfuscateAssemblyAttributeData.cs @@ -0,0 +1,8 @@ +namespace BitMono.Core.Protecting.Resolvers; + +public class ObfuscateAssemblyAttributeData +{ + public bool AssemblyIsPrivate { get; set; } + public bool StripAfterObfuscation { get; set; } + public CustomAttribute CustomAttribute { get; set; } +} \ No newline at end of file diff --git a/src/BitMono.Core/Protecting/Resolvers/ObfuscateAssemblyAttributeResolver.cs b/src/BitMono.Core/Protecting/Resolvers/ObfuscateAssemblyAttributeResolver.cs new file mode 100644 index 00000000..43d21c09 --- /dev/null +++ b/src/BitMono.Core/Protecting/Resolvers/ObfuscateAssemblyAttributeResolver.cs @@ -0,0 +1,40 @@ +namespace BitMono.Core.Protecting.Resolvers; + +public class ObfuscateAssemblyAttributeResolver : AttributeResolver +{ + private readonly Obfuscation m_Obfuscation; + private readonly AttemptAttributeResolver m_AttemptAttributeResolver; + private readonly string m_AttributeNamespace; + private readonly string m_AttributeName; + + public ObfuscateAssemblyAttributeResolver(IOptions configuration, AttemptAttributeResolver attemptAttributeResolver) + { + m_Obfuscation = configuration.Value; + m_AttemptAttributeResolver = attemptAttributeResolver; + m_AttributeNamespace = typeof(ObfuscateAssemblyAttribute).Namespace; + m_AttributeName = nameof(ObfuscateAssemblyAttribute); + } + + public override bool Resolve([AllowNull] string feature, IHasCustomAttribute from, [AllowNull] out ObfuscateAssemblyAttributeData model) + { + model = null; + if (m_Obfuscation.ObfuscateAssemblyAttributeObfuscationExclude == false) + { + return false; + } + if (m_AttemptAttributeResolver.TryResolve(from, m_AttributeNamespace, m_AttributeName, out var attributesResolve) == false) + { + return false; + } + var attribute = attributesResolve.First(); + var assemblyIsPrivate = attribute.FixedValues[0] is bool; + var stripAfterObfuscation = attribute.NamedValues.GetValueOrDefault(nameof(ObfuscateAssemblyAttribute.StripAfterObfuscation), defaultValue: true); + model = new ObfuscateAssemblyAttributeData + { + AssemblyIsPrivate = assemblyIsPrivate, + StripAfterObfuscation = stripAfterObfuscation, + CustomAttribute = attribute.Attribute + }; + return true; + } +} \ No newline at end of file diff --git a/src/BitMono.Core/Protecting/Resolvers/ObfuscationAttributeData.cs b/src/BitMono.Core/Protecting/Resolvers/ObfuscationAttributeData.cs new file mode 100644 index 00000000..08f04963 --- /dev/null +++ b/src/BitMono.Core/Protecting/Resolvers/ObfuscationAttributeData.cs @@ -0,0 +1,10 @@ +namespace BitMono.Core.Protecting.Resolvers; + +public class ObfuscationAttributeData +{ + public bool ApplyToMembers { get; set; } + public bool Exclude { get; set; } + public bool StripAfterObfuscation { get; set; } + public string Feature { get; set; } + public CustomAttribute CustomAttribute { get; set; } +} \ No newline at end of file diff --git a/src/BitMono.Core/Protecting/Resolvers/ObfuscationAttributeResolver.cs b/src/BitMono.Core/Protecting/Resolvers/ObfuscationAttributeResolver.cs index a616b76a..00e4d41c 100644 --- a/src/BitMono.Core/Protecting/Resolvers/ObfuscationAttributeResolver.cs +++ b/src/BitMono.Core/Protecting/Resolvers/ObfuscationAttributeResolver.cs @@ -1,47 +1,52 @@ namespace BitMono.Core.Protecting.Resolvers; -public class ObfuscationAttributeResolver : AttributeResolver +public class ObfuscationAttributeResolver : AttributeResolver { - private readonly IConfiguration m_Configuration; - private readonly IAttemptAttributeResolver m_AttemptAttributeResolver; + private readonly Obfuscation m_Obfuscation; + private readonly AttemptAttributeResolver m_AttemptAttributeResolver; private readonly string m_AttributeNamespace; private readonly string m_AttributeName; - public ObfuscationAttributeResolver(IBitMonoObfuscationConfiguration configuration, IAttemptAttributeResolver attemptAttributeResolver) + public ObfuscationAttributeResolver(IOptions configuration, AttemptAttributeResolver attemptAttributeResolver) { - m_Configuration = configuration.Configuration; + m_Obfuscation = configuration.Value; m_AttemptAttributeResolver = attemptAttributeResolver; m_AttributeNamespace = typeof(ObfuscationAttribute).Namespace; m_AttributeName = nameof(ObfuscationAttribute); } - public override bool Resolve([AllowNull] string feature, IHasCustomAttribute from, [AllowNull] out CustomAttributeResolve attributeResolve) + public override bool Resolve(string featureName, IHasCustomAttribute from, [AllowNull] out ObfuscationAttributeData model) { - attributeResolve = null; - if (m_Configuration.GetValue(nameof(Obfuscation.ObfuscationAttributeObfuscationExclude)) == false) + model = null; + if (m_Obfuscation.ObfuscationAttributeObfuscationExclude == false) { return false; } - if (m_AttemptAttributeResolver.TryResolve(from, m_AttributeNamespace, m_AttributeName, out var keyValuePairs) == false) + if (m_AttemptAttributeResolver.TryResolve(from, m_AttributeNamespace, m_AttributeName, out var attributesResolve) == false) { return false; } - if (string.IsNullOrWhiteSpace(feature)) + foreach (var attribute in attributesResolve) { - return true; - } - if (keyValuePairs.TryGetValue(nameof(ObfuscationAttribute.Feature), out attributeResolve) == false) - { - return false; - } - if (attributeResolve.Value is string valueFeature) - { - if (valueFeature.Equals(feature, StringComparison.OrdinalIgnoreCase)) + if (attribute.NamedValues.TryGetTypedValue(nameof(ObfuscationAttribute.Feature), out string feature)) { - var exclude = keyValuePairs.TryGetValueOrDefault(nameof(ObfuscationAttribute.Exclude), defaultValue: true); - if (exclude) + if (feature.Equals(featureName, StringComparison.OrdinalIgnoreCase)) { - return true; + var exclude = attribute.NamedValues.GetValueOrDefault(nameof(ObfuscationAttribute.Exclude), defaultValue: true); + var applyToMembers = attribute.NamedValues.GetValueOrDefault(nameof(ObfuscationAttribute.Exclude), defaultValue: true); + var stripAfterObfuscation = attribute.NamedValues.GetValueOrDefault(nameof(ObfuscationAttribute.StripAfterObfuscation), defaultValue: true); + if (exclude) + { + model = new ObfuscationAttributeData + { + Exclude = exclude, + ApplyToMembers = applyToMembers, + StripAfterObfuscation = stripAfterObfuscation, + Feature = feature, + CustomAttribute = attribute.Attribute + }; + return true; + } } } } diff --git a/src/BitMono.Core/Protecting/Resolvers/ProtectionsResolver.cs b/src/BitMono.Core/Protecting/Resolvers/ProtectionsResolver.cs index 132e4fde..67c6719d 100644 --- a/src/BitMono.Core/Protecting/Resolvers/ProtectionsResolver.cs +++ b/src/BitMono.Core/Protecting/Resolvers/ProtectionsResolver.cs @@ -3,9 +3,9 @@ public class ProtectionsResolver { private readonly List m_Protections; - private readonly IEnumerable m_ProtectionSettings; + private readonly IEnumerable m_ProtectionSettings; - public ProtectionsResolver(List protections, IEnumerable protectionSettings) + public ProtectionsResolver(List protections, IEnumerable protectionSettings) { m_Protections = protections; m_ProtectionSettings = protectionSettings; diff --git a/src/BitMono.Core/Protecting/Resolvers/SafeToMakeChangesMemberResolver.cs b/src/BitMono.Core/Protecting/Resolvers/SafeToMakeChangesMemberResolver.cs index d66b1e44..60eef3a1 100644 --- a/src/BitMono.Core/Protecting/Resolvers/SafeToMakeChangesMemberResolver.cs +++ b/src/BitMono.Core/Protecting/Resolvers/SafeToMakeChangesMemberResolver.cs @@ -3,33 +3,56 @@ public class SafeToMakeChangesMemberResolver : IMemberResolver { private readonly ObfuscationAttributeResolver m_ObfuscationAttributeResolver; - private readonly NoInliningMethodMemberResolver m_NoInliningMethodMemberResolver; + private readonly ObfuscateAssemblyAttributeResolver m_ObfuscateAssemblyAttributeResolver; + private readonly CriticalAttributeResolver m_CriticalAttributeResolver; + private readonly SerializableBitCriticalAnalyzer m_SerializableBitCriticalAnalyzer; private readonly SpecificNamespaceCriticalAnalyzer m_SpecificNamespaceCriticalAnalyzer; public SafeToMakeChangesMemberResolver( ObfuscationAttributeResolver obfuscationAttributeResolver, - NoInliningMethodMemberResolver noInliningMethodMemberResolver, + ObfuscateAssemblyAttributeResolver obfuscateAssemblyAttributeResolver, + CriticalAttributeResolver criticalAttributeResolver, + SerializableBitCriticalAnalyzer serializableBitCriticalAnalyzer, SpecificNamespaceCriticalAnalyzer specificNamespaceCriticalAnalyzer) { m_ObfuscationAttributeResolver = obfuscationAttributeResolver; - m_NoInliningMethodMemberResolver = noInliningMethodMemberResolver; + m_ObfuscateAssemblyAttributeResolver = obfuscateAssemblyAttributeResolver; + m_CriticalAttributeResolver = criticalAttributeResolver; + m_SerializableBitCriticalAnalyzer = serializableBitCriticalAnalyzer; m_SpecificNamespaceCriticalAnalyzer = specificNamespaceCriticalAnalyzer; } public bool Resolve(IProtection protection, IMetadataMember member) { - var feature = protection.GetName(); if (member is IHasCustomAttribute customAttribute) { - if (m_ObfuscationAttributeResolver.Resolve(feature, customAttribute)) + var feature = protection.GetName(); + if (m_ObfuscationAttributeResolver.Resolve(feature, customAttribute, out var obfuscationAttributeData)) { - return false; + if (obfuscationAttributeData.Exclude) + { + return false; + } + } + if (m_ObfuscateAssemblyAttributeResolver.Resolve(null, customAttribute, out var obfuscateAssemblyAttributeData)) + { + if (obfuscateAssemblyAttributeData.AssemblyIsPrivate) + { + return false; + } } - if (m_NoInliningMethodMemberResolver.Resolve(protection, customAttribute)) + if (m_CriticalAttributeResolver.Resolve(feature, customAttribute)) { return false; } } + if (member is TypeDefinition type) + { + if (m_SerializableBitCriticalAnalyzer.NotCriticalToMakeChanges(type) == false) + { + return false; + } + } if (m_SpecificNamespaceCriticalAnalyzer.NotCriticalToMakeChanges(member) == false) { return false; diff --git a/src/BitMono.GUI.API/BitMono.GUI.API.csproj b/src/BitMono.GUI.API/BitMono.GUI.API.csproj index 1c43a3a6..38866300 100644 --- a/src/BitMono.GUI.API/BitMono.GUI.API.csproj +++ b/src/BitMono.GUI.API/BitMono.GUI.API.csproj @@ -13,9 +13,18 @@ none + + false + none + + + + none + + - + diff --git a/src/BitMono.GUI.API/IStoringProtections.cs b/src/BitMono.GUI.API/IStoringProtections.cs index 032eb90e..38c29c12 100644 --- a/src/BitMono.GUI.API/IStoringProtections.cs +++ b/src/BitMono.GUI.API/IStoringProtections.cs @@ -2,5 +2,5 @@ public interface IStoringProtections { - List Protections { get; } + List Protections { get; } } \ No newline at end of file diff --git a/src/BitMono.GUI.Utilities/BitMono.GUI.Utilities.csproj b/src/BitMono.GUI.Utilities/BitMono.GUI.Utilities.csproj index 531eaac0..1917bd95 100644 --- a/src/BitMono.GUI.Utilities/BitMono.GUI.Utilities.csproj +++ b/src/BitMono.GUI.Utilities/BitMono.GUI.Utilities.csproj @@ -13,11 +13,20 @@ none + + false + none + + + + none + + - + diff --git a/src/BitMono.GUI/BitMono.GUI.csproj b/src/BitMono.GUI/BitMono.GUI.csproj index dacb48b8..804da1ba 100644 --- a/src/BitMono.GUI/BitMono.GUI.csproj +++ b/src/BitMono.GUI/BitMono.GUI.csproj @@ -42,6 +42,15 @@ none + + false + none + + + + none + + @@ -80,14 +89,15 @@ - - + + + diff --git a/src/BitMono.GUI/Data/StoringProtections.cs b/src/BitMono.GUI/Data/StoringProtections.cs index 878b740b..bd54f328 100644 --- a/src/BitMono.GUI/Data/StoringProtections.cs +++ b/src/BitMono.GUI/Data/StoringProtections.cs @@ -1,13 +1,11 @@ -using BitMono.Core.Extensions; - -namespace BitMono.GUI.Data; +namespace BitMono.GUI.Data; internal class StoringProtections : IStoringProtections { - public StoringProtections(IBitMonoProtectionsConfiguration configuration) + public StoringProtections(IOptions settings) { - Protections = configuration.GetProtectionSettings(); + Protections = settings.Value.Protections; } - public List Protections { get; } + public List Protections { get; } } \ No newline at end of file diff --git a/src/BitMono.GUI/GlobalUsings.cs b/src/BitMono.GUI/GlobalUsings.cs index 3d67e6c1..b0810910 100644 --- a/src/BitMono.GUI/GlobalUsings.cs +++ b/src/BitMono.GUI/GlobalUsings.cs @@ -4,7 +4,6 @@ global using BitMono.API.Protecting; global using BitMono.GUI.API; global using BitMono.GUI.Data; -global using BitMono.GUI.Modules; global using BitMono.GUI.Shared.Alerting; global using BitMono.GUI.Shared.Inputs; global using BitMono.Host.Modules; @@ -20,5 +19,10 @@ global using Serilog.Formatting.Display; global using System.Collections.Concurrent; global using System.Reflection; +global using AsmResolver.DotNet; +global using BitMono.API.Protecting.Resolvers; +global using BitMono.Core.Protecting.Resolvers; +global using BitMono.GUI.Utilities.Extensions; +global using Microsoft.Extensions.Options; global using static BitMono.Utilities.Extensions.Collections.CollectionExtensions; global using ILogger = Serilog.ILogger; \ No newline at end of file diff --git a/src/BitMono.GUI/MauiProgram.cs b/src/BitMono.GUI/MauiProgram.cs index e099b59c..f6c5ecb0 100644 --- a/src/BitMono.GUI/MauiProgram.cs +++ b/src/BitMono.GUI/MauiProgram.cs @@ -28,7 +28,7 @@ public static MauiApp CreateMauiApp() Assembly.LoadFrom(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ProtectionsFile)); builder.ConfigureContainer(new AutofacServiceProviderFactory(), configure => { - configure.RegisterModule(new BitMonoModule(configureLogger => + configure.RegisterModule(new BitMonoModule(configureLogger: configureLogger => { configureLogger.WriteTo.Async(configure => { diff --git a/src/BitMono.GUI/Pages/Obfuscation/Protect.razor.cs b/src/BitMono.GUI/Pages/Obfuscation/Protect.razor.cs index f62a3466..7665c50a 100644 --- a/src/BitMono.GUI/Pages/Obfuscation/Protect.razor.cs +++ b/src/BitMono.GUI/Pages/Obfuscation/Protect.razor.cs @@ -1,8 +1,4 @@ -using AsmResolver.DotNet; -using BitMono.API.Protecting.Resolvers; -using BitMono.Core.Protecting.Resolvers; - -namespace BitMono.GUI.Pages.Obfuscation; +namespace BitMono.GUI.Pages.Obfuscation; public partial class Protect { @@ -11,7 +7,6 @@ public partial class Protect private IBrowserFile _obfuscationFile; [Inject] public ILogger Logger { get; set; } - [Inject] public IBitMonoAppSettingsConfiguration Configuration { get; set; } [Inject] public ICollection MemberResolvers { get; set; } [Inject] public ICollection Protections { get; set; } [Inject] public IStoringProtections StoringProtections { get; set; } @@ -40,9 +35,8 @@ public async Task ObfuscateAsync() var baseDirectory = AppDomain.CurrentDomain.BaseDirectory; var runtimeModule = ModuleDefinition.FromFile(Path.Combine(baseDirectory, ExternalComponentsFile)); - var obfuscationConfiguration = ServiceProvider.GetRequiredService(); - var appSettingsConfiguration = ServiceProvider.GetRequiredService(); - var dnlibDefObfuscationAttributeResolver = ServiceProvider.GetRequiredService(); + var obfuscation = ServiceProvider.GetRequiredService>().Value; + var obfuscationAttributeResolver = ServiceProvider.GetRequiredService(); var dependencies = Directory.GetFiles(_dependenciesDirectoryName); var dependeciesData = new List(); @@ -50,21 +44,12 @@ public async Task ObfuscateAsync() { dependeciesData.Add(File.ReadAllBytes(dependencies[i])); } - - var bitMonoContext = new BitMonoContextFactory(new DependenciesDataResolver(_dependenciesDirectoryName), obfuscationConfiguration) - .Create(_outputDirectoryName, _obfuscationFile.Name); - var guiDataWriter = new GUIDataWriter(); - await new BitMonoEngine( - guiDataWriter, - dnlibDefObfuscationAttributeResolver, - obfuscationConfiguration, - MemberResolvers.ToList(), - Protections.ToList(), - StoringProtections.Protections, - Logger) - .ObfuscateAsync(bitMonoContext, moduleBytes, new CancellationTokenSource()); - new TipsNotifier(appSettingsConfiguration, Logger).Notify(); + var dataResolver = new DependenciesDataResolver(_dependenciesDirectoryName); + var bitMonoContextFactory = new BitMonoContextFactory(dataResolver, obfuscation); + var bitMonoContext = bitMonoContextFactory.Create(_outputDirectoryName, _obfuscationFile.Name); + //var engine = new BitMonoEngine(obfuscationAttributeResolver, obfuscation, StoringProtections.Protections, MemberResolvers.ToList(), Protections.ToList(), Logger); + //await engine.StartAsync(); } catch (Exception ex) { @@ -88,7 +73,7 @@ public async Task ObfuscateFileAsync() } if (string.IsNullOrWhiteSpace(_dependenciesDirectoryName)) { - await AlertsContainer.ShowAlertAsync("obfuscation-info", "Please, specify dependecies folder!", Alerts.Danger); + await AlertsContainer.ShowAlertAsync("obfuscation-info", "Please, specify dependencies folder!", Alerts.Danger); return; } if (string.IsNullOrWhiteSpace(_outputDirectoryName)) diff --git a/src/BitMono.GUI/Pages/Obfuscation/Protections.razor b/src/BitMono.GUI/Pages/Obfuscation/Protections.razor index c2ce1471..e77a5d9f 100644 --- a/src/BitMono.GUI/Pages/Obfuscation/Protections.razor +++ b/src/BitMono.GUI/Pages/Obfuscation/Protections.razor @@ -34,18 +34,6 @@ {
- @if (protectionSetting.AsProtection(RegisteredProtections, out IProtection protection) - && protection is IPipelineStage callingCondition) - { - if (callingCondition.Stage == PipelineStages.ModuleWritten) - { -
- - - -
- } - }
@protectionSetting.Name
diff --git a/src/BitMono.GUI/Pages/Obfuscation/Protections.razor.cs b/src/BitMono.GUI/Pages/Obfuscation/Protections.razor.cs index 343a4cbc..b3865122 100644 --- a/src/BitMono.GUI/Pages/Obfuscation/Protections.razor.cs +++ b/src/BitMono.GUI/Pages/Obfuscation/Protections.razor.cs @@ -26,12 +26,12 @@ public void DisableAll() protectionSettings.Disable(); } } - public void MoveUp(ProtectionSettings protectionSetting) + public void MoveUp(ProtectionSetting protectionSetting) { var index = StoringProtections.Protections.IndexOf(protectionSetting); StoringProtections.Protections.Swap(index, index - 1); } - public void MoveDown(ProtectionSettings protectionSetting) + public void MoveDown(ProtectionSetting protectionSetting) { var index = StoringProtections.Protections.IndexOf(protectionSetting); StoringProtections.Protections.Swap(index, index + 1); diff --git a/src/BitMono.GUI/Shared/CreateProtectionModal.razor.cs b/src/BitMono.GUI/Shared/CreateProtectionModal.razor.cs index 7c68092e..799f2e5a 100644 --- a/src/BitMono.GUI/Shared/CreateProtectionModal.razor.cs +++ b/src/BitMono.GUI/Shared/CreateProtectionModal.razor.cs @@ -3,14 +3,14 @@ public partial class CreateProtectionModal { [Inject] public IJSRuntime JSRuntime { get; set; } - [Parameter, EditorRequired] public ICollection Collection { get; set; } - [Parameter] public EventCallback OnSubmit { get; set; } - public ProtectionSettings Model { get; set; } + [Parameter, EditorRequired] public ICollection Collection { get; set; } + [Parameter] public EventCallback OnSubmit { get; set; } + public ProtectionSetting Model { get; set; } protected override Task OnInitializedAsync() { - Model = new ProtectionSettings { Name = string.Empty }; + Model = new ProtectionSetting { Name = string.Empty }; return Task.CompletedTask; } diff --git a/src/BitMono.GUI/_Imports.razor b/src/BitMono.GUI/_Imports.razor index 96b356db..1ac3f83c 100644 --- a/src/BitMono.GUI/_Imports.razor +++ b/src/BitMono.GUI/_Imports.razor @@ -20,5 +20,4 @@ @using BitMono.GUI.Shared.Inputs @using static BitMono.Core.Extensions.ConfigurationExtensions -@using static BitMono.Utilities.Extensions.Collections.CollectionExtensions -@using static BitMono.GUI.Utilities.Extensions.JSRuntimeExtensions \ No newline at end of file +@using static BitMono.Utilities.Extensions.Collections.CollectionExtensions \ No newline at end of file diff --git a/src/BitMono.Host/BitMono.Host.csproj b/src/BitMono.Host/BitMono.Host.csproj index 9601d8ce..165da086 100644 --- a/src/BitMono.Host/BitMono.Host.csproj +++ b/src/BitMono.Host/BitMono.Host.csproj @@ -1,7 +1,7 @@  - netstandard2.0;net461 + netstandard2.0;net462 10.0 @@ -21,15 +21,25 @@ none + + false + none + + + + none + + - - - - - + + + + + + - + @@ -45,17 +55,14 @@ - - Always - - Always + PreserveNewest - Always + PreserveNewest - Always + PreserveNewest diff --git a/src/BitMono.Host/BitMonoApplication.cs b/src/BitMono.Host/BitMonoApplication.cs index 3e307db4..cdb0660d 100644 --- a/src/BitMono.Host/BitMonoApplication.cs +++ b/src/BitMono.Host/BitMonoApplication.cs @@ -4,7 +4,7 @@ public class BitMonoApplication : IApplication { private readonly ContainerBuilder m_ContainerBuilder; private readonly List m_Modules; - + public BitMonoApplication() { m_ContainerBuilder = new ContainerBuilder(); diff --git a/src/BitMono.Host/Configurations/BitMonoAppSettingsConfiguration.cs b/src/BitMono.Host/Configurations/BitMonoAppSettingsConfiguration.cs deleted file mode 100644 index 1059d7df..00000000 --- a/src/BitMono.Host/Configurations/BitMonoAppSettingsConfiguration.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace BitMono.Host.Configurations; - -public class BitMonoAppSettingsConfiguration : JsonConfigurationAccessor, IBitMonoAppSettingsConfiguration -{ - public BitMonoAppSettingsConfiguration() : base(file: "appsettings.json") - { - } -} \ No newline at end of file diff --git a/src/BitMono.Host/GlobalUsings.cs b/src/BitMono.Host/GlobalUsings.cs index ff5ac1cf..9137917f 100644 --- a/src/BitMono.Host/GlobalUsings.cs +++ b/src/BitMono.Host/GlobalUsings.cs @@ -11,6 +11,7 @@ global using BitMono.Core.Protecting; global using BitMono.Core.Protecting.Injection; global using BitMono.Core.Protecting.Renaming; +global using BitMono.Core.Protecting.Resolvers; global using BitMono.Host.Configurations; global using Microsoft.Extensions.Configuration; global using Microsoft.Extensions.DependencyInjection; @@ -19,6 +20,6 @@ global using System; global using System.Collections.Generic; global using System.IO; -global using System.Linq; global using System.Reflection; +global using BitMono.Shared.Models; global using Module = Autofac.Module; \ No newline at end of file diff --git a/src/BitMono.Host/Modules/BitMonoModule.cs b/src/BitMono.Host/Modules/BitMonoModule.cs index 768add1b..18e04338 100644 --- a/src/BitMono.Host/Modules/BitMonoModule.cs +++ b/src/BitMono.Host/Modules/BitMonoModule.cs @@ -2,19 +2,26 @@ public class BitMonoModule : Module { + private readonly Action m_ConfigureServices; private readonly Action m_ConfigureLogger; private readonly Action m_ConfigureConfigurationBuilder; public BitMonoModule( + Action configureServices = default, Action configureLogger = default, Action configureConfigurationBuilder = default) { + m_ConfigureServices = configureServices; m_ConfigureLogger = configureLogger; m_ConfigureConfigurationBuilder = configureConfigurationBuilder; } protected override void Load(ContainerBuilder containerBuilder) { + m_ConfigureServices?.Invoke(containerBuilder); + + var serviceCollection = new ServiceCollection(); + var currentAssemblyDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); var fileFormat = string.Format(Path.Combine(currentAssemblyDirectory, "logs", "bitmono-{0:yyyy-MM-dd-HH-mm-ss}.log"), DateTime.Now).Replace("\\", "/"); @@ -31,10 +38,7 @@ protected override void Load(ContainerBuilder containerBuilder) m_ConfigureLogger.Invoke(loggerConfiguration); var logger = loggerConfiguration.CreateLogger(); - containerBuilder.Register((_, _) => - { - return logger; - }); + containerBuilder.Register((_, _) => logger); } var configurationBuilder = new ConfigurationBuilder(); @@ -46,20 +50,24 @@ protected override void Load(ContainerBuilder containerBuilder) .As() .OwnedByLifetimeScope(); } - - containerBuilder.Register(context => new BitMonoAppSettingsConfiguration()) - .As() + + serviceCollection.AddOptions(); + var protections = new BitMonoProtectionsConfiguration(); + var criticals = new BitMonoCriticalsConfiguration(); + var obfuscation = new BitMonoObfuscationConfiguration(); + serviceCollection.Configure(options => protections.Configuration.Bind(options)); + serviceCollection.Configure(criticals.Configuration); + serviceCollection.Configure(obfuscation.Configuration); + + containerBuilder.Register(context => protections) + .As() .OwnedByLifetimeScope(); - - containerBuilder.Register(context => new BitMonoCriticalsConfiguration()) + + containerBuilder.Register(context => criticals) .As() .OwnedByLifetimeScope(); - containerBuilder.Register(context => new BitMonoProtectionsConfiguration()) - .As() - .OwnedByLifetimeScope(); - - containerBuilder.Register(context => new BitMonoObfuscationConfiguration()) + containerBuilder.Register(context => obfuscation) .As() .OwnedByLifetimeScope(); @@ -83,24 +91,21 @@ protected override void Load(ContainerBuilder containerBuilder) .OwnedByLifetimeScope() .SingleInstance(); - var assemblies = AppDomain.CurrentDomain.GetAssemblies(); - containerBuilder.RegisterAssemblyTypes(assemblies) - .PublicOnly() - .Where(t => t.GetInterface(nameof(ICustomAttributeResolver)) != null) - .AsImplementedInterfaces() + containerBuilder.RegisterType() + .AsSelf() .OwnedByLifetimeScope() .SingleInstance(); - containerBuilder.RegisterAssemblyTypes(assemblies) - .PublicOnly() - .Where(t => t.GetInterface(nameof(IAttemptAttributeResolver)) != null) - .AsImplementedInterfaces() + containerBuilder.RegisterType() + .AsSelf() .OwnedByLifetimeScope() .SingleInstance(); + var assemblies = AppDomain.CurrentDomain.GetAssemblies(); containerBuilder.RegisterAssemblyTypes(assemblies) .PublicOnly() - .Where(t => t.GetInterface(nameof(IAttributeResolver)) != null) + .Where(t => t.GetInterface(nameof(IMemberResolver)) != null) + .AsImplementedInterfaces() .OwnedByLifetimeScope() .SingleInstance(); @@ -112,10 +117,8 @@ protected override void Load(ContainerBuilder containerBuilder) containerBuilder.RegisterAssemblyTypes(assemblies) .PublicOnly() - .Where(t => t.GetInterface(nameof(IMemberResolver)) != null) + .AsClosedTypesOf(typeof(IAttributeResolver<>)) .OwnedByLifetimeScope() - .AsSelf() - .AsImplementedInterfaces() .SingleInstance(); containerBuilder.RegisterAssemblyTypes(assemblies) @@ -124,5 +127,7 @@ protected override void Load(ContainerBuilder containerBuilder) .OwnedByLifetimeScope() .AsImplementedInterfaces() .SingleInstance(); + + containerBuilder.Populate(serviceCollection); } } \ No newline at end of file diff --git a/src/BitMono.Host/appsettings.json b/src/BitMono.Host/appsettings.json deleted file mode 100644 index 3e22d7b2..00000000 --- a/src/BitMono.Host/appsettings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "Tips": [ - "[Tip]: Mark your method with attribute [MethodImpl(MethodImplOptions.NoInlining)] to ignore obfuscation of your method!", - "[Tip]: Mark your Type or method with attribute [Obfuscation(Feature = name)] to ignore obfuscation!", - "[Tip]: Open config.json and set Watermark to 'false', to disable watermarking of your file!", - "[Tip]: Drop your libraries in 'libs' directory!" - ] -} \ No newline at end of file diff --git a/src/BitMono.Host/criticals.json b/src/BitMono.Host/criticals.json index 0462028c..d65e51e4 100644 --- a/src/BitMono.Host/criticals.json +++ b/src/BitMono.Host/criticals.json @@ -1,15 +1,48 @@ { - // DO NOT write here all of your methods because if you rename them in VS/Rider/VS Code (eg, with hotkey CTLR + R + R/without hotkey, doesn't matter) + // DO NOT write here all of your methods/things because if you rename them in VS/Rider/VS Code (eg, with hotkey CTRL + R + R/without hotkey, doesn't matter) // whatever else, they're not will be changed here as well. // This is not for complex things, just write here your critical things - it means: for example, imagine Unity there are a lot of methods // which doesn't even have an 'override' i.e 'override void Update()' (which is called every tick) - just void Update(), in such cases these methods // shouldn't be renamed because this is like const things for Unity, and they're very important, // for complex things use [ObfuscationAttribute(Feature = "ProtectionName")], - // but if you don't have plans with the mess in your code and you don't really have plans in near future to rename these critical things it can be done then. + // but if you don't have plans with the mess in your code, and you don't really have plans in near future to rename these critical things it can be done then. + + // Exclude from obfuscation if the member has attribute + // Set to true indicates whether enabled + "UseCriticalAttributes": true, + "CriticalAttributes": [ + // Unity + { + "Namespace": "UnityEngine", + "Name": "SerializeField" + } + ], + // Exclude from obfuscation if the Model (type, i.e class) has [Serializable]/[JsonProperty], etc, attributes + // Set to true indicates whether enabled + "UseCriticalModelAttributes": true, + "CriticalModelAttributes": [ + { + "Namespace": "System", + "Name": "SerializableAttribute" + }, + { + "Namespace": "System.Xml.Serialization", + "Name": "XmlAttributeAttribute" + }, + { + "Namespace": "System.Xml.Serialization", + "Name": "XmlArrayItemAttribute" + }, + { + "Namespace": "Newtonsoft.Json", + "Name": "JsonPropertyAttribute" + } + + ], + // Exclude from obfuscation if the type inherited specific interface + // Set to true indicates whether enabled "UseCriticalInterfaces": true, - "UseCriticalBaseTypes": true, - "UseCriticalMethods": true, "CriticalInterfaces": [ // RocketMod "IRocketPlugin", @@ -21,6 +54,9 @@ "IOpenModPlugin" ], + // Exclude from obfuscation if the type inherited specific base type + // Set to true indicates whether enabled + "UseCriticalBaseTypes": true, "CriticalBaseTypes": [ // RocketMod "RocketPlugin", @@ -34,6 +70,9 @@ "RustPlugin" ], + // Exclude from obfuscation method by name + // Set to true indicates whether enabled + "UseCriticalMethods": true, "CriticalMethods": [ // Unity "Awake", diff --git a/src/BitMono.Host/obfuscation.json b/src/BitMono.Host/obfuscation.json index 7950b04d..bf7a841e 100644 --- a/src/BitMono.Host/obfuscation.json +++ b/src/BitMono.Host/obfuscation.json @@ -11,14 +11,21 @@ // Set to true indicates whether enabled "NoInliningMethodObfuscationExclude": true, - // Exclude from obfuscation if it is a type/method and etc - // should has an [Obfuscation(Feature = "Name")] attribute with Protection name known as Feature + // Exclude from obfuscation if type/method has [ObfuscationAttribute(..)] + // should have an [Obfuscation(Feature = "Name")] attribute with Protection name known as Feature // Set to true indicates whether enabled "ObfuscationAttributeObfuscationExclude": true, - // Exclude from obfuscation if the Model (type, i.e class) has [Serializable]/[JsonProperty], etc, attributes + // Exclude from obfuscation if assembly has [ObfuscateAssemblyAttribute(true)] // Set to true indicates whether enabled - "ModelAttributeObfuscationExclude": true, + "ObfuscateAssemblyAttributeObfuscationExclude": true, + + // Strip attribute after obfuscation if assembly has [ObfuscateAssemblyAttribute(true, StripAfterObfuscation = true)] + // or member has [Obfuscation(Feature = "Some_BitMono_Feature", StripAfterObfuscation = true] + // By default, you could just specify [Obfuscation(Feature = "Some_BitMono_Feature"] - and this will strip it + // (StripAfterObfuscation is true by default in dotnet sources), the same with ObfuscateAssemblyAttribute + // Set to true indicates whether enabled + "StripObfuscationAttributes": true, // Output errors that were registered while building the PE image. BitMono feature is that // being used vulnerabilities of decompilers and Mono and this is the most powerful of them, @@ -27,11 +34,11 @@ // Set to true indicates whether enabled "OutputPEImageBuildErrors": true, - // Sometimes when you dont have needed dependency for your app, a tons of reasons could be for that, - // if you got an error that says you dont have needed dependency first of all atleast try to add this dependency - // otherwise if this is deprecated - you can set this to false to ignore error and continue obfuscation - // NB! but be aware of kind a weird errors and issues that breaking you app and it stops working after that - // If this is Unity go to your game path (eg, steam), openup the directory and search for Managed directory xxx_Data\Managed, + // Sometimes when you don't have needed dependency for your app, a tons of reasons could be for that, + // if you got an error that says you don't have needed dependency first of all at least try to add this dependency + // otherwise if this is deprecated - you can set this as false to ignore error and continue obfuscation + // NB! but be aware of kind a weird errors and issues that breaking you app, and it stops working after that + // If this is Unity go to your game path (eg, steam), open-up the directory and search for Managed directory xxx_Data\Managed, // Copy asked libraries from there and feed them to BitMono // Stay it true to stay enabled if this is possible! "FailOnNoRequiredDependency": true, diff --git a/src/BitMono.Obfuscation.API/BitMono.Obfuscation.API.csproj b/src/BitMono.Obfuscation.API/BitMono.Obfuscation.API.csproj index 23fb43a2..a3f358a6 100644 --- a/src/BitMono.Obfuscation.API/BitMono.Obfuscation.API.csproj +++ b/src/BitMono.Obfuscation.API/BitMono.Obfuscation.API.csproj @@ -1,7 +1,7 @@  - netstandard2.0;net461 + netstandard2.0;net462 10.0 @@ -21,6 +21,15 @@ none + + false + none + + + + none + + diff --git a/src/BitMono.Obfuscation.API/IObfuscationNeedsFactory.cs b/src/BitMono.Obfuscation.API/IObfuscationNeedsFactory.cs new file mode 100644 index 00000000..23b9b70c --- /dev/null +++ b/src/BitMono.Obfuscation.API/IObfuscationNeedsFactory.cs @@ -0,0 +1,6 @@ +namespace BitMono.Obfuscation.API; + +public interface IObfuscationNeedsFactory +{ + ObfuscationNeeds Create(); +} \ No newline at end of file diff --git a/src/BitMono.Obfuscation.API/ObfuscationNeeds.cs b/src/BitMono.Obfuscation.API/ObfuscationNeeds.cs new file mode 100644 index 00000000..66b1969c --- /dev/null +++ b/src/BitMono.Obfuscation.API/ObfuscationNeeds.cs @@ -0,0 +1,9 @@ +namespace BitMono.Obfuscation.API; + +public class ObfuscationNeeds +{ + public string FileName { get; set; } + public string FileBaseDirectory { get; set; } + public string DependenciesDirectoryName { get; set; } + public string OutputDirectoryName { get; set; } +} \ No newline at end of file diff --git a/src/BitMono.Obfuscation/BitMono.Obfuscation.csproj b/src/BitMono.Obfuscation/BitMono.Obfuscation.csproj index 7d0b79c2..8ee5a494 100644 --- a/src/BitMono.Obfuscation/BitMono.Obfuscation.csproj +++ b/src/BitMono.Obfuscation/BitMono.Obfuscation.csproj @@ -1,7 +1,7 @@  - netstandard2.0;net461 + netstandard2.0;net462 10.0 @@ -21,6 +21,15 @@ none + + false + none + + + + none + + diff --git a/src/BitMono.Obfuscation/BitMonoContextFactory.cs b/src/BitMono.Obfuscation/BitMonoContextFactory.cs index dd56e435..191378c0 100644 --- a/src/BitMono.Obfuscation/BitMonoContextFactory.cs +++ b/src/BitMono.Obfuscation/BitMonoContextFactory.cs @@ -3,12 +3,12 @@ public class BitMonoContextFactory { private readonly IDependenciesDataResolver m_DependenciesDataResolver; - private readonly IConfiguration m_Configuration; + private readonly Shared.Models.Obfuscation m_Obfuscation; - public BitMonoContextFactory(IDependenciesDataResolver dependenciesDataResolver, IBitMonoObfuscationConfiguration configuration) + public BitMonoContextFactory(IDependenciesDataResolver dependenciesDataResolver, Shared.Models.Obfuscation obfuscation) { m_DependenciesDataResolver = dependenciesDataResolver; - m_Configuration = configuration.Configuration; + m_Obfuscation = obfuscation; } public BitMonoContext Create(string outputDirectoryName, string fileName) @@ -17,8 +17,8 @@ public BitMonoContext Create(string outputDirectoryName, string fileName) { OutputDirectoryName = outputDirectoryName, DependenciesData = m_DependenciesDataResolver.Resolve(), - Watermark = m_Configuration.GetValue(nameof(Shared.Models.Obfuscation.Watermark)), - FileName = fileName, + Watermark = m_Obfuscation.Watermark, + FileName = fileName }; } } \ No newline at end of file diff --git a/src/BitMono.Obfuscation/BitMonoEngine.cs b/src/BitMono.Obfuscation/BitMonoEngine.cs index aa41d907..778a6e37 100644 --- a/src/BitMono.Obfuscation/BitMonoEngine.cs +++ b/src/BitMono.Obfuscation/BitMonoEngine.cs @@ -2,33 +2,33 @@ public class BitMonoEngine { - private readonly IDataWriter m_DataWriter; private readonly ObfuscationAttributeResolver m_ObfuscationAttributeResolver; - private readonly IBitMonoObfuscationConfiguration m_ObfuscationConfiguration; + private readonly ObfuscateAssemblyAttributeResolver m_ObfuscateAssemblyAttributeResolver; + private readonly Shared.Models.Obfuscation m_Obfuscation; + private readonly List m_ProtectionSettings; private readonly List m_MemberResolvers; private readonly List m_Protections; - private readonly List m_ProtectionSettings; private readonly ILogger m_Logger; public BitMonoEngine( - IDataWriter dataWriter, ObfuscationAttributeResolver obfuscationAttributeResolver, - IBitMonoObfuscationConfiguration obfuscationConfiguration, + ObfuscateAssemblyAttributeResolver obfuscateAssemblyAttributeResolver, + Shared.Models.Obfuscation obfuscation, + List protectionSetting, List memberResolvers, List protections, - List protectionSettings, ILogger logger) { - m_DataWriter = dataWriter; m_ObfuscationAttributeResolver = obfuscationAttributeResolver; - m_ObfuscationConfiguration = obfuscationConfiguration; + m_ObfuscateAssemblyAttributeResolver = obfuscateAssemblyAttributeResolver; + m_Obfuscation = obfuscation; + m_ProtectionSettings = protectionSetting; m_MemberResolvers = memberResolvers; m_Protections = protections; - m_ProtectionSettings = protectionSettings; m_Logger = logger.ForContext(); } - internal async Task StartAsync(ProtectionContext context) + internal async Task StartAsync(ProtectionContext context, IDataWriter dataWriter) { context.ThrowIfCancellationRequested(); @@ -42,33 +42,25 @@ internal async Task StartAsync(ProtectionContext context) return false; } - var obfuscator = new BitMonoObfuscator(context, m_MemberResolvers, protectionsSort, m_DataWriter, m_ObfuscationAttributeResolver, m_ObfuscationConfiguration, m_Logger); + var obfuscator = new BitMonoObfuscator(context, m_MemberResolvers, protectionsSort, dataWriter, m_ObfuscationAttributeResolver, m_ObfuscateAssemblyAttributeResolver, m_Obfuscation, m_Logger); await obfuscator.ProtectAsync(); return true; } - public async Task StartAsync(BitMonoContext context, IModuleFactory moduleFactory, CancellationToken cancellationToken) + public async Task StartAsync(ObfuscationNeeds needs, IModuleFactory moduleFactory, IDataWriter dataWriter, CancellationToken cancellationToken) { + var dependenciesDataResolver = new DependenciesDataResolver(needs.DependenciesDirectoryName); + var bitMonoContextFactory = new BitMonoContextFactory(dependenciesDataResolver, m_Obfuscation); + var bitMonoContext = bitMonoContextFactory.Create(needs.OutputDirectoryName, needs.FileName); + var runtimeModule = ModuleDefinition.FromFile(typeof(BitMono.Runtime.Data).Assembly.Location); var moduleFactoryResult = moduleFactory.Create(); - var protectionContextFactory = new ProtectionContextFactory(moduleFactoryResult, runtimeModule, context, cancellationToken); + var protectionContextFactory = new ProtectionContextFactory(moduleFactoryResult, runtimeModule, bitMonoContext, cancellationToken); var protectionContext = protectionContextFactory.Create(); - new OutputFilePathFactory().Create(context); - return await StartAsync(protectionContext); - } - public async Task StartAsync(BitMonoContext context, byte[] data, IErrorListener errorListener, CancellationToken cancellationToken) - { - return await StartAsync(context, new ModuleFactory(data, errorListener), cancellationToken); - } - public async Task StartAsync(BitMonoContext context, string fileName, IErrorListener errorListener, CancellationToken cancellationToken) - { - return await StartAsync(context, new ModuleFactory(File.ReadAllBytes(fileName), errorListener), cancellationToken); - } - public async Task StartAsync(BitMonoContext context, byte[] data, CancellationToken cancellationToken) - { - return await StartAsync(context, data, new LogErrorListener(m_Logger), cancellationToken); + new OutputFilePathFactory().Create(bitMonoContext); + return await StartAsync(protectionContext, dataWriter); } - public async Task StartAsync(BitMonoContext context, string fileName, CancellationToken cancellationToken) + public async Task StartAsync(ObfuscationNeeds needs, CancellationToken cancellationToken) { - return await StartAsync(context, fileName, new LogErrorListener(m_Logger), cancellationToken); + return await StartAsync(needs, new ModuleFactory(File.ReadAllBytes(needs.FileName), new LogErrorListener(m_Logger)), new FileDataWriter(), cancellationToken); } } \ No newline at end of file diff --git a/src/BitMono.Obfuscation/BitMonoObfuscator.cs b/src/BitMono.Obfuscation/BitMonoObfuscator.cs index 5f70ed6a..f8426e47 100644 --- a/src/BitMono.Obfuscation/BitMonoObfuscator.cs +++ b/src/BitMono.Obfuscation/BitMonoObfuscator.cs @@ -7,14 +7,17 @@ public class BitMonoObfuscator private readonly ProtectionsSort m_ProtectionsSort; private readonly IDataWriter m_DataWriter; private readonly ObfuscationAttributeResolver m_ObfuscationAttributeResolver; - private readonly IConfiguration m_ObfuscationConfiguration; + private readonly ObfuscateAssemblyAttributeResolver m_ObfuscateAssemblyAttributeResolver; + private readonly Shared.Models.Obfuscation m_Obfuscation; private readonly IInvokablePipeline m_InvokablePipeline; private readonly MembersResolver m_MemberResolver; private readonly ProtectionExecutionNotifier m_ProtectionExecutionNotifier; private readonly ProtectionsNotifier m_ProtectionsNotifier; + private readonly ObfuscationAttributesStripper m_ObfuscationAttributesStripper; + private readonly ObfuscationAttributesStripNotifier m_ObfuscationAttributesStripNotifier; private readonly ILogger m_Logger; private PEImageBuildResult _imageBuild; - private Stopwatch _stopWatch; + private long _startTime; public BitMonoObfuscator( ProtectionContext context, @@ -22,7 +25,8 @@ public BitMonoObfuscator( ProtectionsSort protectionsSortResult, IDataWriter dataWriter, ObfuscationAttributeResolver obfuscationAttributeResolver, - IBitMonoObfuscationConfiguration obfuscationConfiguration, + ObfuscateAssemblyAttributeResolver obfuscateAssemblyAttributeResolver, + Shared.Models.Obfuscation obfuscation, ILogger logger) { m_Context = context; @@ -30,12 +34,16 @@ public BitMonoObfuscator( m_ProtectionsSort = protectionsSortResult; m_DataWriter = dataWriter; m_ObfuscationAttributeResolver = obfuscationAttributeResolver; - m_ObfuscationConfiguration = obfuscationConfiguration.Configuration; + m_ObfuscateAssemblyAttributeResolver = obfuscateAssemblyAttributeResolver; + m_Obfuscation = obfuscation; m_Logger = logger.ForContext(); m_InvokablePipeline = new InvokablePipeline(m_Context); m_MemberResolver = new MembersResolver(); m_ProtectionExecutionNotifier = new ProtectionExecutionNotifier(m_Logger); - m_ProtectionsNotifier = new ProtectionsNotifier(obfuscationConfiguration, m_Logger); + m_ProtectionsNotifier = new ProtectionsNotifier(m_Obfuscation, m_Logger); + m_ObfuscationAttributesStripper = new ObfuscationAttributesStripper(m_Obfuscation, + m_ObfuscationAttributeResolver, m_ObfuscateAssemblyAttributeResolver); + m_ObfuscationAttributesStripNotifier = new ObfuscationAttributesStripNotifier(m_Logger); } public async Task ProtectAsync() @@ -66,8 +74,7 @@ private Task outputProtectionsAsync(ProtectionContext context) } private Task startTimeCounterAsync(ProtectionContext context) { - _stopWatch = new Stopwatch(); - _stopWatch.Start(); + _startTime = Stopwatch.GetTimestamp(); return Task.FromResult(true); } private Task outputFrameworkInformationAsync(ProtectionContext context) @@ -88,7 +95,7 @@ private Task resolveDependenciesAsync(ProtectionContext context) } if (assemblyResolve.Succeed == false) { - if (m_ObfuscationConfiguration.GetValue(nameof(Shared.Models.Obfuscation.FailOnNoRequiredDependency))) + if (m_Obfuscation.FailOnNoRequiredDependency) { m_Logger.Fatal("Please, specify needed dependencies, or set in obfuscation.json FailOnNoRequiredDependency to false"); return Task.FromResult(false); @@ -146,23 +153,8 @@ private Task optimizeMacrosAsync(ProtectionContext context) } private Task stripObfuscationAttributesAsync(ProtectionContext context) { - foreach (var customAttribute in context.Module.FindDefinitions().OfType()) - { - foreach (var protection in m_ProtectionsSort.ProtectionsResolve.FoundProtections) - { - if (m_ObfuscationAttributeResolver.Resolve(protection.GetName(), customAttribute, out CustomAttributeResolve attributeResolve)) - { - if (customAttribute.CustomAttributes.Remove(attributeResolve.CustomAttribute)) - { - m_Logger.Information("Successfully stripped obfuscation attribute"); - } - else - { - m_Logger.Warning("Failed to stip obfuscation attribute"); - } - } - } - } + var obfuscationAttributesStrip = m_ObfuscationAttributesStripper.Strip(context, m_ProtectionsSort); + m_ObfuscationAttributesStripNotifier.Notify(obfuscationAttributesStrip); return Task.FromResult(true); } private Task createPEImageAsync(ProtectionContext context) @@ -172,7 +164,7 @@ private Task createPEImageAsync(ProtectionContext context) } private Task outputPEImageBuildErrorsAsync(ProtectionContext context) { - if (m_ObfuscationConfiguration.GetValue(nameof(Shared.Models.Obfuscation.OutputPEImageBuildErrors))) + if (m_Obfuscation.OutputPEImageBuildErrors) { if (_imageBuild.DiagnosticBag.HasErrors) { @@ -217,8 +209,8 @@ private async Task packAsync(ProtectionContext context) } private Task outputElapsedTimeAsync(ProtectionContext context) { - _stopWatch.Stop(); - m_Logger.Information("Since obfuscation elapsed: {0}", _stopWatch.Elapsed.ToString()); + var elapsedTime = StopwatchUtilities.GetElapsedTime(_startTime, Stopwatch.GetTimestamp()); + m_Logger.Information("Since obfuscation elapsed: {0}", elapsedTime.ToString()); return Task.FromResult(true); } private void onFail() diff --git a/src/BitMono.CLI/Modules/CLIDataWriter.cs b/src/BitMono.Obfuscation/FileDataWriter.cs similarity index 68% rename from src/BitMono.CLI/Modules/CLIDataWriter.cs rename to src/BitMono.Obfuscation/FileDataWriter.cs index 2afa49a6..c9c084c5 100644 --- a/src/BitMono.CLI/Modules/CLIDataWriter.cs +++ b/src/BitMono.Obfuscation/FileDataWriter.cs @@ -1,6 +1,6 @@ -namespace BitMono.CLI.Modules; +namespace BitMono.Obfuscation; -internal class CLIDataWriter : IDataWriter +internal class FileDataWriter : IDataWriter { public Task WriteAsync(string outputFile, byte[] outputBuffer) { diff --git a/src/BitMono.Obfuscation/GlobalUsings.cs b/src/BitMono.Obfuscation/GlobalUsings.cs index 09d8b335..f12003fb 100644 --- a/src/BitMono.Obfuscation/GlobalUsings.cs +++ b/src/BitMono.Obfuscation/GlobalUsings.cs @@ -5,7 +5,6 @@ global using AsmResolver.PE.DotNet; global using AsmResolver.PE.DotNet.Builder; global using AsmResolver.PE.File.Headers; -global using BitMono.API.Configuration; global using BitMono.API.Protecting; global using BitMono.API.Protecting.Contexts; global using BitMono.API.Protecting.Pipeline; @@ -16,7 +15,6 @@ global using BitMono.Obfuscation.API; global using BitMono.Shared.Models; global using BitMono.Utilities.Extensions.AsmResolver; -global using Microsoft.Extensions.Configuration; global using System; global using System.Collections.Generic; global using System.Diagnostics; @@ -26,4 +24,5 @@ global using System.Text; global using System.Threading; global using System.Threading.Tasks; +global using Pocket.Extensions; global using ILogger = Serilog.ILogger; \ No newline at end of file diff --git a/src/BitMono.Obfuscation/MembersResolver.cs b/src/BitMono.Obfuscation/MembersResolver.cs index 2b4c8e2a..09143b05 100644 --- a/src/BitMono.Obfuscation/MembersResolver.cs +++ b/src/BitMono.Obfuscation/MembersResolver.cs @@ -4,16 +4,16 @@ public class MembersResolver { public IEnumerable Resolve(IProtection protection, IEnumerable members, IEnumerable resolvers) { - foreach (var definition in members) + foreach (var member in members) { - foreach (var resolver in resolvers) + if (canBeResolved(protection, member, resolvers)) { - if (resolver.Resolve(protection, definition)) - { - yield return definition; - break; - } + yield return member; } } } + private bool canBeResolved(IProtection protection, IMetadataMember member, IEnumerable resolvers) + { + return resolvers.All(r => r.Resolve(protection, member)); + } } \ No newline at end of file diff --git a/src/BitMono.Obfuscation/ModuleFactory.cs b/src/BitMono.Obfuscation/ModuleFactory.cs index 1ea6b0fd..0e310304 100644 --- a/src/BitMono.Obfuscation/ModuleFactory.cs +++ b/src/BitMono.Obfuscation/ModuleFactory.cs @@ -1,4 +1,6 @@ -public class ModuleFactory : IModuleFactory +namespace BitMono.Obfuscation; + +public class ModuleFactory : IModuleFactory { private readonly byte[] m_Bytes; private readonly IErrorListener m_ErrorListener; diff --git a/src/BitMono.Obfuscation/ObfuscationAttributesStrip.cs b/src/BitMono.Obfuscation/ObfuscationAttributesStrip.cs new file mode 100644 index 00000000..27025fb3 --- /dev/null +++ b/src/BitMono.Obfuscation/ObfuscationAttributesStrip.cs @@ -0,0 +1,9 @@ +namespace BitMono.Obfuscation; + +public class ObfuscationAttributesStrip +{ + public List ObfuscationAttributesSuccessStrip { get; set; } + public List ObfuscationAttributesFailStrip { get; set; } + public List ObfuscateAssemblyAttributesSuccessStrip { get; set; } + public List ObfuscateAssemblyAttributesFailStrip { get; set; } +} \ No newline at end of file diff --git a/src/BitMono.Obfuscation/ObfuscationAttributesStripNotifier.cs b/src/BitMono.Obfuscation/ObfuscationAttributesStripNotifier.cs new file mode 100644 index 00000000..ee5a56b0 --- /dev/null +++ b/src/BitMono.Obfuscation/ObfuscationAttributesStripNotifier.cs @@ -0,0 +1,31 @@ +namespace BitMono.Obfuscation; + +public class ObfuscationAttributesStripNotifier +{ + private readonly ILogger m_Logger; + + public ObfuscationAttributesStripNotifier(ILogger logger) + { + m_Logger = logger; + } + + public void Notify(ObfuscationAttributesStrip obfuscationAttributesStrip) + { + if (obfuscationAttributesStrip.ObfuscationAttributesSuccessStrip.IsEmpty() == false) + { + m_Logger.Information("Successfully stripped {0} obfuscation attribute(s)!", obfuscationAttributesStrip.ObfuscationAttributesSuccessStrip.Count); + } + if (obfuscationAttributesStrip.ObfuscateAssemblyAttributesSuccessStrip.IsEmpty() == false) + { + m_Logger.Information("Successfully stripped {0} assembly obfuscation attribute(s)!", obfuscationAttributesStrip.ObfuscateAssemblyAttributesSuccessStrip.Count); + } + if (obfuscationAttributesStrip.ObfuscationAttributesFailStrip.IsEmpty() == false) + { + m_Logger.Information("Failed to strip {0} assembly obfuscation attribute(s)!", obfuscationAttributesStrip.ObfuscationAttributesFailStrip.Count); + } + if (obfuscationAttributesStrip.ObfuscateAssemblyAttributesFailStrip.IsEmpty() == false) + { + m_Logger.Information("Failed to strip {0} obfuscation attribute(s)!", obfuscationAttributesStrip.ObfuscateAssemblyAttributesFailStrip.Count); + } + } +} \ No newline at end of file diff --git a/src/BitMono.Obfuscation/ObfuscationAttributesStripper.cs b/src/BitMono.Obfuscation/ObfuscationAttributesStripper.cs new file mode 100644 index 00000000..73429738 --- /dev/null +++ b/src/BitMono.Obfuscation/ObfuscationAttributesStripper.cs @@ -0,0 +1,70 @@ +namespace BitMono.Obfuscation; + +public class ObfuscationAttributesStripper +{ + private readonly Shared.Models.Obfuscation m_Obfuscation; + private readonly ObfuscationAttributeResolver m_ObfuscationAttributeResolver; + private readonly ObfuscateAssemblyAttributeResolver m_ObfuscateAssemblyAttributeResolver; + + public ObfuscationAttributesStripper( + Shared.Models.Obfuscation obfuscation, + ObfuscationAttributeResolver obfuscationAttributeResolver, + ObfuscateAssemblyAttributeResolver obfuscateAssemblyAttributeResolver) + { + m_Obfuscation = obfuscation; + m_ObfuscationAttributeResolver = obfuscationAttributeResolver; + m_ObfuscateAssemblyAttributeResolver = obfuscateAssemblyAttributeResolver; + } + + public ObfuscationAttributesStrip Strip(ProtectionContext context, ProtectionsSort protectionsSort) + { + var obfuscationAttributesSuccessStrip = new List(); + var obfuscationAttributesFailStrip = new List(); + var obfuscateAssemblyAttributesSuccessStrip = new List(); + var obfuscateAssemblyAttributesFailStrip = new List(); + foreach (var customAttribute in context.Module.FindDefinitions().OfType()) + { + foreach (var protection in protectionsSort.ProtectionsResolve.FoundProtections) + { + var protectionName = protection.GetName(); + if (m_Obfuscation.StripObfuscationAttributes) + { + if (m_ObfuscationAttributeResolver.Resolve(protectionName, customAttribute, out ObfuscationAttributeData obfuscationAttributeData)) + { + if (obfuscationAttributeData.StripAfterObfuscation) + { + var attribute = obfuscationAttributeData.CustomAttribute; + if (customAttribute.CustomAttributes.Remove(attribute)) + { + obfuscationAttributesSuccessStrip.Add(attribute); + } + else + { + obfuscationAttributesFailStrip.Add(attribute); + } + } + } + if (m_ObfuscateAssemblyAttributeResolver.Resolve(null, customAttribute, out ObfuscateAssemblyAttributeData obfuscateAssemblyAttributeData)) + { + var attribute = obfuscateAssemblyAttributeData.CustomAttribute; + if (customAttribute.CustomAttributes.Remove(attribute)) + { + obfuscateAssemblyAttributesSuccessStrip.Add(attribute); + } + else + { + obfuscateAssemblyAttributesFailStrip.Add(attribute); + } + } + } + } + } + return new ObfuscationAttributesStrip + { + ObfuscationAttributesSuccessStrip = obfuscationAttributesSuccessStrip, + ObfuscationAttributesFailStrip = obfuscationAttributesFailStrip, + ObfuscateAssemblyAttributesSuccessStrip = obfuscateAssemblyAttributesSuccessStrip, + ObfuscateAssemblyAttributesFailStrip = obfuscateAssemblyAttributesFailStrip + }; + } +} \ No newline at end of file diff --git a/src/BitMono.Obfuscation/ProtectionsNotifier.cs b/src/BitMono.Obfuscation/ProtectionsNotifier.cs index ae77c28a..9248b6a0 100644 --- a/src/BitMono.Obfuscation/ProtectionsNotifier.cs +++ b/src/BitMono.Obfuscation/ProtectionsNotifier.cs @@ -2,18 +2,18 @@ public class ProtectionsNotifier { - private readonly IConfiguration m_Configuration; + private readonly Shared.Models.Obfuscation m_Obfuscation; private readonly ILogger m_Logger; - public ProtectionsNotifier(IBitMonoObfuscationConfiguration configuration, ILogger logger) + public ProtectionsNotifier(Shared.Models.Obfuscation obfuscation, ILogger logger) { - m_Configuration = configuration.Configuration; + m_Obfuscation = obfuscation; m_Logger = logger.ForContext(); } public void Notify(ProtectionsSort protectionsSort) { - if (m_Configuration.GetValue(nameof(Shared.Models.Obfuscation.NotifyProtections))) + if (m_Obfuscation.NotifyProtections) { if (protectionsSort.HasProtections) { diff --git a/src/BitMono.Obfuscation/ProtectionsSorter.cs b/src/BitMono.Obfuscation/ProtectionsSorter.cs index 1b4e76f1..e3d8218f 100644 --- a/src/BitMono.Obfuscation/ProtectionsSorter.cs +++ b/src/BitMono.Obfuscation/ProtectionsSorter.cs @@ -11,7 +11,7 @@ public ProtectionsSorter(ObfuscationAttributeResolver obfuscationAttributeResolv m_Assembly = assembly; } - public ProtectionsSort Sort(List protections, IEnumerable protectionSettings) + public ProtectionsSort Sort(List protections, IEnumerable protectionSettings) { var protectionsResolve = new ProtectionsResolver(protections, protectionSettings).Sort(); var obfuscationAttributeProtections = protectionsResolve.FoundProtections.Where(p => m_ObfuscationAttributeResolver.Resolve(p.GetName(), m_Assembly) == true); diff --git a/src/BitMono.Obfuscation/TipsNotifier.cs b/src/BitMono.Obfuscation/TipsNotifier.cs deleted file mode 100644 index 49a47339..00000000 --- a/src/BitMono.Obfuscation/TipsNotifier.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace BitMono.Obfuscation; - -public class TipsNotifier -{ - private readonly IConfiguration m_Configuration; - private readonly ILogger m_Logger; - - public TipsNotifier(IBitMonoAppSettingsConfiguration configuration, ILogger logger) - { - m_Configuration = configuration.Configuration; - m_Logger = logger.ForContext(); - } - - public void Notify() - { - var tips = m_Configuration.GetSection("Tips").Get(); - var random = new Random(); - var tip = tips.Reverse().ToArray()[random.Next(0, tips.Length)]; - m_Logger.Information("Today is your day! Generating helpful tip for you - see it a bit down!"); - m_Logger.Information(tip); - } -} \ No newline at end of file diff --git a/src/BitMono.Protections/BitMono.Protections.csproj b/src/BitMono.Protections/BitMono.Protections.csproj index 1aa511f1..50c9fa00 100644 --- a/src/BitMono.Protections/BitMono.Protections.csproj +++ b/src/BitMono.Protections/BitMono.Protections.csproj @@ -1,7 +1,7 @@  - netstandard2.0;net461 + netstandard2.0;net462 10.0 @@ -21,6 +21,15 @@ none + + false + none + + + + none + + @@ -30,8 +39,8 @@ - - + + diff --git a/src/BitMono.Protections/DotNetHook.cs b/src/BitMono.Protections/DotNetHook.cs index 9ce03a09..75e2f658 100644 --- a/src/BitMono.Protections/DotNetHook.cs +++ b/src/BitMono.Protections/DotNetHook.cs @@ -15,7 +15,7 @@ public Task ExecuteAsync(ProtectionContext context, ProtectionParameters paramet { var runtimeHookingType = context.RuntimeModule.ResolveOrThrow(typeof(Hooking)); var runtimeRedirectStubMethod = runtimeHookingType.Methods.Single(c => c.Name.Equals(nameof(Hooking.RedirectStub))); - var listener = new ModifyInjectTypeClonerListener(Modifies.All, m_Renamer, context.Module); + var listener = new ModifyInjectTypeClonerListener(ModifyFlags.All, m_Renamer, context.Module); var memberCloneResult = new MemberCloner(context.Module, listener) .Include(runtimeHookingType) .Clone(); diff --git a/src/BitMono.Protections/StringsEncryption.cs b/src/BitMono.Protections/StringsEncryption.cs index 926b1d3e..3d5047a4 100644 --- a/src/BitMono.Protections/StringsEncryption.cs +++ b/src/BitMono.Protections/StringsEncryption.cs @@ -21,7 +21,7 @@ public Task ExecuteAsync(ProtectionContext context, ProtectionParameters paramet var runtimeDecryptorType = context.RuntimeModule.ResolveOrThrow(typeof(Decryptor)); var runtimeDecryptMethod = runtimeDecryptorType.Methods.Single(c => c.Name.Equals(nameof(Decryptor.Decrypt))); - var listener = new ModifyInjectTypeClonerListener(Modifies.All, m_Renamer, context.Module); + var listener = new ModifyInjectTypeClonerListener(ModifyFlags.All, m_Renamer, context.Module); var memberCloneResult = new MemberCloner(context.Module, listener) .Include(runtimeDecryptorType) .Clone(); diff --git a/src/BitMono.Runtime/BitMono.Runtime.csproj b/src/BitMono.Runtime/BitMono.Runtime.csproj index e4f39300..81115cf3 100644 --- a/src/BitMono.Runtime/BitMono.Runtime.csproj +++ b/src/BitMono.Runtime/BitMono.Runtime.csproj @@ -1,7 +1,7 @@  - net461 + net462 10.0 @@ -13,4 +13,13 @@ none + + false + none + + + + none + + diff --git a/src/BitMono.Shared/BitMono.Shared.csproj b/src/BitMono.Shared/BitMono.Shared.csproj index e4cc57d5..e6546af8 100644 --- a/src/BitMono.Shared/BitMono.Shared.csproj +++ b/src/BitMono.Shared/BitMono.Shared.csproj @@ -1,7 +1,7 @@  - netstandard2.0;net461 + netstandard2.0;net462 10.0 @@ -21,11 +21,20 @@ none + + false + none + + + + none + + - + diff --git a/src/BitMono.Shared/GlobalUsings.cs b/src/BitMono.Shared/GlobalUsings.cs index e26234b5..27f92b0c 100644 --- a/src/BitMono.Shared/GlobalUsings.cs +++ b/src/BitMono.Shared/GlobalUsings.cs @@ -1,2 +1,3 @@ -global using AsmResolver.DotNet; -global using Newtonsoft.Json; \ No newline at end of file +global using Newtonsoft.Json; +global using System.Collections.Generic; +global using NullGuard; \ No newline at end of file diff --git a/src/BitMono.Shared/Models/CriticalAttribute.cs b/src/BitMono.Shared/Models/CriticalAttribute.cs new file mode 100644 index 00000000..62b4a79c --- /dev/null +++ b/src/BitMono.Shared/Models/CriticalAttribute.cs @@ -0,0 +1,7 @@ +namespace BitMono.Shared.Models; + +public class CriticalAttribute +{ + public string Namespace { get; set; } + public string Name { get; set; } +} \ No newline at end of file diff --git a/src/BitMono.Shared/Models/Criticals.cs b/src/BitMono.Shared/Models/Criticals.cs new file mode 100644 index 00000000..818834aa --- /dev/null +++ b/src/BitMono.Shared/Models/Criticals.cs @@ -0,0 +1,20 @@ +namespace BitMono.Shared.Models; + +public class Criticals +{ + public bool UseCriticalAttributes { get; set; } + public bool UseCriticalModelAttributes { get; set; } + public bool UseCriticalInterfaces { get; set; } + public bool UseCriticalBaseTypes { get; set; } + public bool UseCriticalMethods { get; set; } + [AllowNull] + public List CriticalAttributes { get; set; } + [AllowNull] + public List CriticalModelAttributes { get; set; } + [AllowNull] + public List CriticalInterfaces { get; set; } + [AllowNull] + public List CriticalBaseTypes { get; set; } + [AllowNull] + public List CriticalMethods { get; set; } +} \ No newline at end of file diff --git a/src/BitMono.Shared/Models/Obfuscation.cs b/src/BitMono.Shared/Models/Obfuscation.cs index ed5018de..21939b4e 100644 --- a/src/BitMono.Shared/Models/Obfuscation.cs +++ b/src/BitMono.Shared/Models/Obfuscation.cs @@ -5,12 +5,16 @@ public class Obfuscation public bool Watermark { get; set; } public bool NotifyProtections { get; set; } public bool NoInliningMethodObfuscationExclude { get; set; } + public bool SerializableBitObfuscationExclude { get; set; } public bool ObfuscationAttributeObfuscationExclude { get; set; } - public bool ModelAttributeObfuscationExclude { get; set; } + public bool ObfuscateAssemblyAttributeObfuscationExclude { get; set; } + public bool StripObfuscationAttributes { get; set; } public bool OutputPEImageBuildErrors { get; set; } public bool FailOnNoRequiredDependency { get; set; } public bool OpenFileDestinationInFileExplorer { get; set; } public bool SpecificNamespacesObfuscationOnly { get; set; } + [AllowNull] public string[] SpecificNamespaces { get; set; } + [AllowNull] public string[] RandomStrings { get; set; } } \ No newline at end of file diff --git a/src/BitMono.Shared/Models/ProtectionSetting.cs b/src/BitMono.Shared/Models/ProtectionSetting.cs new file mode 100644 index 00000000..7619946e --- /dev/null +++ b/src/BitMono.Shared/Models/ProtectionSetting.cs @@ -0,0 +1,17 @@ +namespace BitMono.Shared.Models; + +public class ProtectionSetting +{ + [JsonRequired] public string Name { get; set; } + public bool Enabled { get; set; } + [JsonIgnore] public bool Disabled => Enabled == false; + + public void Enable() + { + Enabled = true; + } + public void Disable() + { + Enabled = false; + } +} \ No newline at end of file diff --git a/src/BitMono.Shared/Models/ProtectionSettings.cs b/src/BitMono.Shared/Models/ProtectionSettings.cs index fa0d9af9..558039a6 100644 --- a/src/BitMono.Shared/Models/ProtectionSettings.cs +++ b/src/BitMono.Shared/Models/ProtectionSettings.cs @@ -1,17 +1,7 @@ -namespace BitMono.Shared.Models; +namespace BitMono.Shared.Models; public class ProtectionSettings { - [JsonRequired] public string Name { get; set; } - public bool Enabled { get; set; } - [JsonIgnore] public bool Disabled => Enabled == false; - - public void Enable() - { - Enabled = true; - } - public void Disable() - { - Enabled = false; - } + [AllowNull] + public List Protections { get; set; } } \ No newline at end of file diff --git a/src/BitMono.Utilities/BitMono.Utilities.csproj b/src/BitMono.Utilities/BitMono.Utilities.csproj index 453fc7ea..f3643ca7 100644 --- a/src/BitMono.Utilities/BitMono.Utilities.csproj +++ b/src/BitMono.Utilities/BitMono.Utilities.csproj @@ -1,7 +1,7 @@  - netstandard2.0;net461 + netstandard2.0;net462 10.0 @@ -21,12 +21,21 @@ none + + false + none + + + + none + + - + diff --git a/src/BitMono.Utilities/GlobalUsings.cs b/src/BitMono.Utilities/GlobalUsings.cs index bd87ee88..fbaa6b93 100644 --- a/src/BitMono.Utilities/GlobalUsings.cs +++ b/src/BitMono.Utilities/GlobalUsings.cs @@ -1,11 +1,9 @@ global using AsmResolver; global using AsmResolver.DotNet; -global using AsmResolver.DotNet.Cloning; global using AsmResolver.DotNet.Code.Cil; global using AsmResolver.PE.DotNet.Cil; global using AsmResolver.PE.DotNet.Metadata.Tables; global using AsmResolver.PE.DotNet.Metadata.Tables.Rows; -global using BitMono.API.Protecting.Renaming; global using MoreLinq; global using NullGuard; global using System; diff --git a/test/BitMono.Benchmarks/BitMono.Benchmarks.csproj b/test/BitMono.Benchmarks/BitMono.Benchmarks.csproj new file mode 100644 index 00000000..fb4bcbb1 --- /dev/null +++ b/test/BitMono.Benchmarks/BitMono.Benchmarks.csproj @@ -0,0 +1,26 @@ + + + + net6.0 + 10 + Exe + + + + none + + + + false + none + + + + + + + + + + + diff --git a/test/BitMono.Benchmarks/GlobalUsings.cs b/test/BitMono.Benchmarks/GlobalUsings.cs new file mode 100644 index 00000000..10443b3e --- /dev/null +++ b/test/BitMono.Benchmarks/GlobalUsings.cs @@ -0,0 +1,5 @@ +global using System.Reflection; +global using BenchmarkDotNet.Attributes; +global using BenchmarkDotNet.Jobs; +global using BenchmarkDotNet.Running; +global using BitMono.Core.Extensions; \ No newline at end of file diff --git a/test/BitMono.Benchmarks/Program.cs b/test/BitMono.Benchmarks/Program.cs new file mode 100644 index 00000000..047ce59f --- /dev/null +++ b/test/BitMono.Benchmarks/Program.cs @@ -0,0 +1,9 @@ +namespace BitMono.Benchmarks; + +internal static class Program +{ + private static void Main(string[] args) + { + BenchmarkRunner.Run(Assembly.GetExecutingAssembly()); + } +} \ No newline at end of file diff --git a/test/BitMono.Benchmarks/RuntimeFrameworkInformationBenchmark.cs b/test/BitMono.Benchmarks/RuntimeFrameworkInformationBenchmark.cs new file mode 100644 index 00000000..8ade89cd --- /dev/null +++ b/test/BitMono.Benchmarks/RuntimeFrameworkInformationBenchmark.cs @@ -0,0 +1,13 @@ +namespace BitMono.Benchmarks; + +[SimpleJob(RuntimeMoniker.Net461)] +[SimpleJob(RuntimeMoniker.Net47)] +[MemoryDiagnoser] +public class RuntimeFrameworkInformationBenchmark +{ + [Benchmark] + public void RuntimeInformation() + { + RuntimeUtilities.GetFrameworkInformation(); + } +} \ No newline at end of file diff --git a/test/BitMono.Core.Tests/App.config b/test/BitMono.Core.Tests/App.config new file mode 100644 index 00000000..7d52ade7 --- /dev/null +++ b/test/BitMono.Core.Tests/App.config @@ -0,0 +1,254 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/BitMono.Core.Tests/BitMono.Core.Tests.csproj b/test/BitMono.Core.Tests/BitMono.Core.Tests.csproj new file mode 100644 index 00000000..451ced86 --- /dev/null +++ b/test/BitMono.Core.Tests/BitMono.Core.Tests.csproj @@ -0,0 +1,41 @@ + + + + net6.0 + 10 + + + + false + none + + + + false + none + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + + + + diff --git a/test/BitMono.Core.Tests/GlobalUsings.cs b/test/BitMono.Core.Tests/GlobalUsings.cs new file mode 100644 index 00000000..d0991c88 --- /dev/null +++ b/test/BitMono.Core.Tests/GlobalUsings.cs @@ -0,0 +1,13 @@ +global using System.Collections; +global using System.Collections.Generic; +global using System.Linq; +global using AsmResolver.DotNet; +global using BitMono.Core.Protecting.Analyzing; +global using BitMono.Core.Protecting.Resolvers; +global using BitMono.Core.TestCases.CustomAttributes; +global using BitMono.Core.TestCases.Methods; +global using BitMono.Shared.Models; +global using FluentAssertions; +global using Xunit; +global using BitMono.Protections; +global using Microsoft.Extensions.Options; \ No newline at end of file diff --git a/test/BitMono.Core.Tests/Protecting/Analyzing/CriticalMethodsCriticalAnalyzerTest.cs b/test/BitMono.Core.Tests/Protecting/Analyzing/CriticalMethodsCriticalAnalyzerTest.cs new file mode 100644 index 00000000..49cce9c0 --- /dev/null +++ b/test/BitMono.Core.Tests/Protecting/Analyzing/CriticalMethodsCriticalAnalyzerTest.cs @@ -0,0 +1,64 @@ +namespace BitMono.Core.Tests.Protecting.Analyzing; + +public class MethodsData : IEnumerable +{ + public IEnumerator GetEnumerator() + { + yield return new object[] { nameof(CriticalMethods.Update) }; + yield return new object[] { nameof(CriticalMethods.LateUpdate) }; + yield return new object[] { nameof(CriticalMethods.FixedUpdate) }; + yield return new object[] { nameof(CriticalMethods.OnDrawGizmos) }; + } + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } +} + +public class CriticalMethodsCriticalAnalyzerTest +{ + [Theory] + [ClassData(typeof(MethodsData))] + public void WhenMethodIsCritical_AndMethodIsCritical_ThenShouldBeFalse(string methodName) + { + var criticals = new Criticals + { + UseCriticalMethods = true, + CriticalMethods = new List + { + methodName + } + }; + var options = Options.Create(criticals); + var criticalAnalyzer = Setup.CriticalMethodsCriticalAnalyzer(options); + var module = ModuleDefinition.FromFile(typeof(CriticalMethods).Assembly.Location); + var type = module.TopLevelTypes.First(t => t.Name == nameof(CriticalMethods)); + var method = type.Methods.First(m => m.Name == methodName); + + var result = criticalAnalyzer.NotCriticalToMakeChanges(method); + + result.Should().BeFalse(); + } + [Theory] + [ClassData(typeof(MethodsData))] + public void WhenMethodIsNotCritical_AndMethodIsNotCritical_ThenShouldBeTrue(string methodName) + { + var criticals = new Criticals + { + UseCriticalMethods = true, + CriticalMethods = new List + { + methodName + } + }; + var options = Options.Create(criticals); + var criticalAnalyzer = Setup.CriticalMethodsCriticalAnalyzer(options); + var module = ModuleDefinition.FromFile(typeof(CriticalMethods).Assembly.Location); + var type = module.TopLevelTypes.First(t => t.Name == nameof(CriticalMethods)); + var method = type.Methods.First(m => m.Name == nameof(CriticalMethods.VoidMethod)); + + var result = criticalAnalyzer.NotCriticalToMakeChanges(method); + + result.Should().BeTrue(); + } +} \ No newline at end of file diff --git a/test/BitMono.Core.Tests/Protecting/Analyzing/SerializableBitCriticalAnalyzerTest.cs b/test/BitMono.Core.Tests/Protecting/Analyzing/SerializableBitCriticalAnalyzerTest.cs new file mode 100644 index 00000000..8047d8e9 --- /dev/null +++ b/test/BitMono.Core.Tests/Protecting/Analyzing/SerializableBitCriticalAnalyzerTest.cs @@ -0,0 +1,37 @@ +namespace BitMono.Core.Tests.Protecting.Analyzing; + +public class SerializableBitCriticalAnalyzerTest +{ + [Fact] + public void WhenTypeSerializableBitCriticalAnalyzing_AndTypeHasSerializableBit_ThenShouldBeFalse() + { + var obfuscation = new Obfuscation + { + SerializableBitObfuscationExclude = true + }; + var criticalAnalyzer = Setup.SerializableBitCriticalAnalyzer(Options.Create(obfuscation)); + var module = ModuleDefinition.FromModule(typeof(SerializableTypes).Module); + var types = module.TopLevelTypes.First(t => t.Name == nameof(SerializableTypes)); + var type = types.NestedTypes.First(n => n.Name == nameof(SerializableTypes.SerializableBit)); + + var result = criticalAnalyzer.NotCriticalToMakeChanges(type); + + result.Should().BeFalse(); + } + [Fact] + public void WhenTypeSerializableBitCriticalAnalyzing_AndTypeHasNoSerializableBit_ThenShouldBeTrue() + { + var obfuscation = new Obfuscation + { + SerializableBitObfuscationExclude = true + }; + var criticalAnalyzer = Setup.SerializableBitCriticalAnalyzer(Options.Create(obfuscation)); + var module = ModuleDefinition.FromModule(typeof(SerializableTypes).Module); + var types = module.TopLevelTypes.First(t => t.Name == nameof(SerializableTypes)); + var type = types.NestedTypes.First(n => n.Name == nameof(SerializableTypes.NoSerializableBit)); + + var result = criticalAnalyzer.NotCriticalToMakeChanges(type); + + result.Should().BeTrue(); + } +} \ No newline at end of file diff --git a/test/BitMono.Core.Tests/Protecting/Resolvers/NoInliningMethodMemberResolverTest.cs b/test/BitMono.Core.Tests/Protecting/Resolvers/NoInliningMethodMemberResolverTest.cs new file mode 100644 index 00000000..431dee4b --- /dev/null +++ b/test/BitMono.Core.Tests/Protecting/Resolvers/NoInliningMethodMemberResolverTest.cs @@ -0,0 +1,39 @@ +namespace BitMono.Core.Tests.Protecting.Resolvers; + +public class NoInliningMethodMemberResolverTest +{ + [Fact] + public void WhenNoInliningMethodResolving_AndMethodHasInliningBit_ThenShouldBeFalse() + { + var obfuscation = new Obfuscation + { + NoInliningMethodObfuscationExclude = true, + }; + var options = Options.Create(obfuscation); + var resolver = Setup.NoInliningMethodMemberResolver(options); + var module = ModuleDefinition.FromFile(typeof(NoInliningMethods).Assembly.Location); + var type = module.TopLevelTypes.First(t => t.Name == nameof(NoInliningMethods)); + var method = type.Methods.First(m => m.Name == nameof(NoInliningMethods.NoInliningMethod)); + + var result = resolver.Resolve(null, method); + + result.Should().BeFalse(); + } + [Fact] + public void WhenNoInliningMethodResolving_AndMethodHasNoInliningBit_ThenShouldBeTrue() + { + var obfuscation = new Obfuscation + { + NoInliningMethodObfuscationExclude = true, + }; + var options = Options.Create(obfuscation); + var resolver = Setup.NoInliningMethodMemberResolver(options); + var module = ModuleDefinition.FromFile(typeof(NoInliningMethods).Assembly.Location); + var type = module.TopLevelTypes.First(t => t.Name == nameof(NoInliningMethods)); + var method = type.Methods.First(m => m.Name == nameof(NoInliningMethods.VoidMethod)); + + var result = resolver.Resolve(null, method); + + result.Should().BeTrue(); + } +} \ No newline at end of file diff --git a/test/BitMono.Core.Tests/Protecting/Resolvers/ObfuscateAssemblyAttributeResolverTest.cs b/test/BitMono.Core.Tests/Protecting/Resolvers/ObfuscateAssemblyAttributeResolverTest.cs new file mode 100644 index 00000000..a7fdd8d1 --- /dev/null +++ b/test/BitMono.Core.Tests/Protecting/Resolvers/ObfuscateAssemblyAttributeResolverTest.cs @@ -0,0 +1,20 @@ +namespace BitMono.Core.Tests.Protecting.Resolvers; + +public class ObfuscateAssemblyAttributeResolverTest +{ + [Fact] + public void WhenObfuscateAssemblyAttributeResolving_AndAssemblyHasObfuscateAssemblyAttributeIsPrivateTrue_ThenShouldBeTrue() + { + var obfuscation = new Obfuscation + { + ObfuscateAssemblyAttributeObfuscationExclude = true, + }; + var options = Options.Create(obfuscation); + var resolver = Setup.ObfuscateAssemblyAttributeResolver(options); + var module = ModuleDefinition.FromFile(typeof(CustomAttributesInstance).Assembly.Location); + + var result = resolver.Resolve(module.Assembly); + + result.Should().BeTrue(); + } +} \ No newline at end of file diff --git a/test/BitMono.Core.Tests/Protecting/Resolvers/ObfuscationAttributeResolverTest.cs b/test/BitMono.Core.Tests/Protecting/Resolvers/ObfuscationAttributeResolverTest.cs new file mode 100644 index 00000000..d9e806e2 --- /dev/null +++ b/test/BitMono.Core.Tests/Protecting/Resolvers/ObfuscationAttributeResolverTest.cs @@ -0,0 +1,76 @@ +namespace BitMono.Core.Tests.Protecting.Resolvers; + +public class ObfuscationAttributeResolverTest +{ + [Theory] + [InlineData(nameof(CallToCalli))] + public void WhenObfuscationAttributeResolving_AndTypeHasComplexObfuscationAttributeWithExcludeFalse_ThenShouldBeFalse(string feature) + { + var obfuscation = new Obfuscation + { + ObfuscationAttributeObfuscationExclude = true, + }; + var options = Options.Create(obfuscation); + var resolver = Setup.ObfuscationAttributeResolver(options); + var module = ModuleDefinition.FromFile(typeof(ObfuscationTypes).Assembly.Location); + var types = module.TopLevelTypes.First(t => t.Name == nameof(ObfuscationTypes)); + var type = types.NestedTypes.First(n => + n.Name == nameof(ObfuscationTypes.ObfuscationAttributeCallToCalliWithExcludeFalse)); + + var result = resolver.Resolve(feature, type); + + result.Should().BeFalse(); + } + [Theory] + [InlineData(nameof(CallToCalli))] + public void WhenObfuscationAttributeResolving_AndTypeHasObfuscationAttributeCallToCalli_ThenShouldBeTrue(string feature) + { + var obfuscation = new Obfuscation + { + ObfuscationAttributeObfuscationExclude = true, + }; + var options = Options.Create(obfuscation); + var resolver = Setup.ObfuscationAttributeResolver(options); + var module = ModuleDefinition.FromFile(typeof(ObfuscationTypes).Assembly.Location); + var types = module.TopLevelTypes.First(t => t.Name == nameof(ObfuscationTypes)); + var type = types.NestedTypes.First(n => n.Name == nameof(ObfuscationTypes.ObfuscationAttributeCallToCalli)); + + var result = resolver.Resolve(feature, type); + + result.Should().BeTrue(); + } + [Fact] + public void WhenObfuscationAttributeResolving_AndTypeHasVoidObfuscationAttribute_ThenShouldBeFalse() + { + var obfuscation = new Obfuscation + { + ObfuscationAttributeObfuscationExclude = true, + }; + var options = Options.Create(obfuscation); + var resolver = Setup.ObfuscationAttributeResolver(options); + var module = ModuleDefinition.FromFile(typeof(ObfuscationTypes).Assembly.Location); + var types = module.TopLevelTypes.First(t => t.Name == nameof(ObfuscationTypes)); + var type = types.NestedTypes.First(n => n.Name == nameof(ObfuscationTypes.VoidObfuscationAttribute)); + + var result = resolver.Resolve(string.Empty, type); + + result.Should().BeFalse(); + } + [Fact] + public void WhenObfuscationAttributeResolving_AndMethodHasVoidObfuscationAttribute_ThenShouldBeFalse() + { + var obfuscation = new Obfuscation + { + ObfuscationAttributeObfuscationExclude = true, + }; + var options = Options.Create(obfuscation); + var resolver = Setup.ObfuscationAttributeResolver(options); + var module = ModuleDefinition.FromFile(typeof(ObfuscationMethods).Assembly.Location); + var type = module.TopLevelTypes.First(n => n.Name == nameof(ObfuscationMethods)); + var method = type.Methods.First(m => m.Name == nameof(ObfuscationMethods.VoidObfuscationAttribute)); + + var result = resolver.Resolve(string.Empty, method); + + result.Should().BeFalse(); + } +} \ No newline at end of file diff --git a/test/BitMono.Core.Tests/Setup.cs b/test/BitMono.Core.Tests/Setup.cs new file mode 100644 index 00000000..2f1aa32a --- /dev/null +++ b/test/BitMono.Core.Tests/Setup.cs @@ -0,0 +1,34 @@ +namespace BitMono.Core.Tests; + +public static class Setup +{ + public static AttemptAttributeResolver AttemptAttributeResolver() + { + return new AttemptAttributeResolver(new CustomAttributeResolver()); + } + public static ModelAttributeCriticalAnalyzer ModelAttributeCriticalAnalyzer(IOptions criticals) + { + return new ModelAttributeCriticalAnalyzer(criticals, AttemptAttributeResolver()); + } + public static CriticalMethodsCriticalAnalyzer CriticalMethodsCriticalAnalyzer(IOptions criticals) + { + return new CriticalMethodsCriticalAnalyzer(criticals); + } + public static NoInliningMethodMemberResolver NoInliningMethodMemberResolver(IOptions obfuscation) + { + return new NoInliningMethodMemberResolver(obfuscation); + } + public static ObfuscationAttributeResolver ObfuscationAttributeResolver(IOptions obfuscation) + { + return new ObfuscationAttributeResolver(obfuscation, AttemptAttributeResolver()); + } + public static ObfuscateAssemblyAttributeResolver ObfuscateAssemblyAttributeResolver( + IOptions obfuscation) + { + return new ObfuscateAssemblyAttributeResolver(obfuscation, AttemptAttributeResolver()); + } + public static SerializableBitCriticalAnalyzer SerializableBitCriticalAnalyzer(IOptions obfuscation) + { + return new SerializableBitCriticalAnalyzer(obfuscation); + } +} \ No newline at end of file diff --git a/test/BitMono.Core.Tests/packages.config b/test/BitMono.Core.Tests/packages.config new file mode 100644 index 00000000..b3ce3fd6 --- /dev/null +++ b/test/BitMono.Core.Tests/packages.config @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/TestBinaries/DotNet/BitMono.Core.TestCases.CustomAttributes/AssemblyInfo.cs b/test/TestBinaries/DotNet/BitMono.Core.TestCases.CustomAttributes/AssemblyInfo.cs new file mode 100644 index 00000000..bb015559 --- /dev/null +++ b/test/TestBinaries/DotNet/BitMono.Core.TestCases.CustomAttributes/AssemblyInfo.cs @@ -0,0 +1 @@ +[assembly: ObfuscateAssembly(true, StripAfterObfuscation = true)] \ No newline at end of file diff --git a/test/TestBinaries/DotNet/BitMono.Core.TestCases.CustomAttributes/BitMono.Core.TestCases.CustomAttributes.csproj b/test/TestBinaries/DotNet/BitMono.Core.TestCases.CustomAttributes/BitMono.Core.TestCases.CustomAttributes.csproj new file mode 100644 index 00000000..eaf6d7b1 --- /dev/null +++ b/test/TestBinaries/DotNet/BitMono.Core.TestCases.CustomAttributes/BitMono.Core.TestCases.CustomAttributes.csproj @@ -0,0 +1,20 @@ + + + + netstandard2.0 + 10 + + + + none + + + + none + + + + + + + diff --git a/test/TestBinaries/DotNet/BitMono.Core.TestCases.CustomAttributes/CustomAttributesInstance.cs b/test/TestBinaries/DotNet/BitMono.Core.TestCases.CustomAttributes/CustomAttributesInstance.cs new file mode 100644 index 00000000..e5181728 --- /dev/null +++ b/test/TestBinaries/DotNet/BitMono.Core.TestCases.CustomAttributes/CustomAttributesInstance.cs @@ -0,0 +1,5 @@ +namespace BitMono.Core.TestCases.CustomAttributes; + +public static class CustomAttributesInstance +{ +} \ No newline at end of file diff --git a/test/TestBinaries/DotNet/BitMono.Core.TestCases.CustomAttributes/GlobalUsings.cs b/test/TestBinaries/DotNet/BitMono.Core.TestCases.CustomAttributes/GlobalUsings.cs new file mode 100644 index 00000000..a9c1358c --- /dev/null +++ b/test/TestBinaries/DotNet/BitMono.Core.TestCases.CustomAttributes/GlobalUsings.cs @@ -0,0 +1,4 @@ +global using System; +global using System.Reflection; +global using System.Runtime.CompilerServices; +global using BitMono.Protections; \ No newline at end of file diff --git a/test/TestBinaries/DotNet/BitMono.Core.TestCases.CustomAttributes/NoInliningMethods.cs b/test/TestBinaries/DotNet/BitMono.Core.TestCases.CustomAttributes/NoInliningMethods.cs new file mode 100644 index 00000000..1ae8664f --- /dev/null +++ b/test/TestBinaries/DotNet/BitMono.Core.TestCases.CustomAttributes/NoInliningMethods.cs @@ -0,0 +1,12 @@ +namespace BitMono.Core.TestCases.CustomAttributes; + +public class NoInliningMethods +{ + public void VoidMethod() + { + } + [MethodImpl(MethodImplOptions.NoInlining)] + public void NoInliningMethod() + { + } +} \ No newline at end of file diff --git a/test/TestBinaries/DotNet/BitMono.Core.TestCases.CustomAttributes/ObfuscationMethods.cs b/test/TestBinaries/DotNet/BitMono.Core.TestCases.CustomAttributes/ObfuscationMethods.cs new file mode 100644 index 00000000..8081885b --- /dev/null +++ b/test/TestBinaries/DotNet/BitMono.Core.TestCases.CustomAttributes/ObfuscationMethods.cs @@ -0,0 +1,24 @@ +namespace BitMono.Core.TestCases.CustomAttributes; + +public class ObfuscationMethods +{ + public void NoObfuscationAttribute() + { + } + [Obfuscation] + public void VoidObfuscationAttribute() + { + } + [Obfuscation(Feature = nameof(CallToCalli))] + public void ObfuscationAttributeFeatureCallToCalli() + { + } + [Obfuscation(Feature = nameof(CallToCalli), Exclude = true)] + public void ObfuscationAttributeFeatureCallToCalliExcludeTrue() + { + } + [Obfuscation(Feature = nameof(CallToCalli), Exclude = true)] + public void ObfuscationAttributeFeatureCallToCalliExcludeFalse() + { + } +} \ No newline at end of file diff --git a/test/TestBinaries/DotNet/BitMono.Core.TestCases.CustomAttributes/ObfuscationTypes.cs b/test/TestBinaries/DotNet/BitMono.Core.TestCases.CustomAttributes/ObfuscationTypes.cs new file mode 100644 index 00000000..90e4e3e3 --- /dev/null +++ b/test/TestBinaries/DotNet/BitMono.Core.TestCases.CustomAttributes/ObfuscationTypes.cs @@ -0,0 +1,24 @@ +namespace BitMono.Core.TestCases.CustomAttributes; + +public class ObfuscationTypes +{ + public class NoObfuscationAttribute + { + } + [Obfuscation] + public class VoidObfuscationAttribute + { + } + [Obfuscation(Feature = nameof(CallToCalli))] + public class ObfuscationAttributeCallToCalli + { + } + [Obfuscation(Feature = nameof(CallToCalli), Exclude = true)] + public class ObfuscationAttributeCallToCalliWithExcludeTrue + { + } + [Obfuscation(Feature = nameof(CallToCalli), Exclude = false)] + public class ObfuscationAttributeCallToCalliWithExcludeFalse + { + } +} \ No newline at end of file diff --git a/test/TestBinaries/DotNet/BitMono.Core.TestCases.CustomAttributes/SerializableTypes.cs b/test/TestBinaries/DotNet/BitMono.Core.TestCases.CustomAttributes/SerializableTypes.cs new file mode 100644 index 00000000..7e459ed8 --- /dev/null +++ b/test/TestBinaries/DotNet/BitMono.Core.TestCases.CustomAttributes/SerializableTypes.cs @@ -0,0 +1,12 @@ +namespace BitMono.Core.TestCases.CustomAttributes; + +public class SerializableTypes +{ + public class NoSerializableBit + { + } + [Serializable] + public class SerializableBit + { + } +} \ No newline at end of file diff --git a/test/TestBinaries/DotNet/BitMono.Core.TestCases.Methods/BitMono.Core.TestCases.Methods.csproj b/test/TestBinaries/DotNet/BitMono.Core.TestCases.Methods/BitMono.Core.TestCases.Methods.csproj new file mode 100644 index 00000000..dd618bb2 --- /dev/null +++ b/test/TestBinaries/DotNet/BitMono.Core.TestCases.Methods/BitMono.Core.TestCases.Methods.csproj @@ -0,0 +1,8 @@ + + + + netstandard2.0 + 10 + + + diff --git a/test/TestBinaries/DotNet/BitMono.Core.TestCases.Methods/CriticalMethods.cs b/test/TestBinaries/DotNet/BitMono.Core.TestCases.Methods/CriticalMethods.cs new file mode 100644 index 00000000..038c227f --- /dev/null +++ b/test/TestBinaries/DotNet/BitMono.Core.TestCases.Methods/CriticalMethods.cs @@ -0,0 +1,20 @@ +namespace BitMono.Core.TestCases.Methods; + +public class CriticalMethods +{ + public void VoidMethod() + { + } + public void Update() + { + } + public void LateUpdate() + { + } + public void FixedUpdate() + { + } + public void OnDrawGizmos() + { + } +} \ No newline at end of file diff --git a/test/TestBinaries/DotNet/BitMono.Core.TestCases.Types/BitMono.Core.TestCases.Types.csproj b/test/TestBinaries/DotNet/BitMono.Core.TestCases.Types/BitMono.Core.TestCases.Types.csproj new file mode 100644 index 00000000..dd618bb2 --- /dev/null +++ b/test/TestBinaries/DotNet/BitMono.Core.TestCases.Types/BitMono.Core.TestCases.Types.csproj @@ -0,0 +1,8 @@ + + + + netstandard2.0 + 10 + + + diff --git a/test/TestBinaries/DotNet/BitMono.Core.TestCases.Types/EmptyType.cs b/test/TestBinaries/DotNet/BitMono.Core.TestCases.Types/EmptyType.cs new file mode 100644 index 00000000..e779e53e --- /dev/null +++ b/test/TestBinaries/DotNet/BitMono.Core.TestCases.Types/EmptyType.cs @@ -0,0 +1,5 @@ +namespace BitMono.Core.TestCases.Types; + +public class EmptyType +{ +} \ No newline at end of file diff --git a/test/TestBinaries/DotNet/BitMono.Core.TestCases.Types/GlobalUsings.cs b/test/TestBinaries/DotNet/BitMono.Core.TestCases.Types/GlobalUsings.cs new file mode 100644 index 00000000..911a5848 --- /dev/null +++ b/test/TestBinaries/DotNet/BitMono.Core.TestCases.Types/GlobalUsings.cs @@ -0,0 +1 @@ +global using System; \ No newline at end of file diff --git a/test/TestBinaries/DotNet/BitMono.Core.TestCases.Types/SerializableType.cs b/test/TestBinaries/DotNet/BitMono.Core.TestCases.Types/SerializableType.cs new file mode 100644 index 00000000..99e437e8 --- /dev/null +++ b/test/TestBinaries/DotNet/BitMono.Core.TestCases.Types/SerializableType.cs @@ -0,0 +1,6 @@ +namespace BitMono.Core.TestCases.Types; + +[Serializable] +public class SerializableType +{ +} \ No newline at end of file