.NET 6 使用 Obfuscar 进行代码混淆
本文來安利大家 Obfuscar 這個好用的基于 MIT 協(xié)議開源的混淆工具。這是一個非常老牌的混淆工具,從 2014 年就對外分發(fā),如今已有累計 495.5K 的 nuget 下載量。而且此工具也在不斷持續(xù)迭代更新,完全支持 dotnet 6 版本,對 WPF 和 WinForms 等等的支持也是非常好,支持多個不同混淆方式和等級的配置,支持混淆之后生成符號文件。本文將來告訴大家如何使用此混淆工具,以及此工具能達成的效果和此工具混淆的原理
開源
此工具是由?Lex Li?主導(dǎo)開發(fā)的,在 GitHub 上使用 MIT 最友好協(xié)議開源,開源地址是?https://github.com/obfuscar/obfuscar
使用方法
此工具的使用方式有多個不同的方式,比較推薦的是采用 dotnet tool 的方式進行使用。因為使用 dotnet tool 可以非常方便接入自己已有的 CI CD 上,而且也可以實現(xiàn)非常方便的更新邏輯
按照約定,使用 dotnet tool 的第一步是進行安裝,安裝的方法就是在命令行輸入以下代碼
dotnet tool install --global Obfuscar.GlobalTool如此即可完成安裝。安裝完成之后的使用方法是調(diào)用?obfuscar.console?命令,傳入混淆配置 Obfuscar.xml 文件即可,如下面命令行例子
obfuscar.console Obfuscar.xml也就是說最關(guān)鍵的只有兩點,第一個就是命令行的工作路徑,另一個就是混淆配置 Obfuscar.xml 文件
假定我有一個項目是 HeenerholiCeleehano 項目,此項目我需要對他進行混淆。此項目輸出的是 HeenerholiCeleehano.dll 文件,放在?C:\lindexi\Code\lindexi\HeenerholiCeleehano\HeenerholiCeleehano\bin\Release\net6.0-windows\?文件夾下
那么在混淆之前,請設(shè)置好命令行的工作路徑,如使用?cd?命令進入到輸出文件夾,如以下命令
cd C\lindexi\Code\lindexi\HeenerholiCeleehano\HeenerholiCeleehano\bin\Release\net6.0-windows\接下來是要在?C:\lindexi\Code\lindexi\HeenerholiCeleehano\HeenerholiCeleehano\bin\Release\net6.0-windows\?文件夾下放一個混淆配置 Obfuscar.xml 文件,文件內(nèi)容可以是如下
<?xml version='1.0'?> <Obfuscator><Var name="InPath" value="." /><Var name="OutPath" value=".\Obfuscar" /><Var name="KeepPublicApi" value="true" /><Var name="HidePrivateApi" value="true" /><Var name="HideStrings" value="false" /><Var name="UseUnicodeNames" value="true" /><Var name="ReuseNames" value="true" /><Var name="RenameFields" value="true" /><Var name="RegenerateDebugInfo" value="true" /><Module file="$(InPath)\HeenerholiCeleehano.dll" /><AssemblySearchPath path="C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App\6.0.1\" /><AssemblySearchPath path="C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.1\" /> </Obfuscator>以上配置文件的含義如下,我一一帶上注釋標識
<?xml version='1.0'?> <Obfuscator><!-- 輸入的工作路徑,采用如約定的 Windows 下的路徑表示法,如以下表示當前工作路徑 --><!-- 推薦使用當前工作路徑,因為 DLL 的混淆過程,需要找到 DLL 的所有依賴。剛好當前工作路徑下,基本都能滿足條件 --><Var name="InPath" value="." /><!-- 混淆之后的輸出路徑,如下面代碼,設(shè)置為當前工作路徑下的 Obfuscar 文件夾 --><!-- 混淆完成之后的新 DLL 將會存放在此文件夾里 --><Var name="OutPath" value=".\Obfuscar" /><!-- 以下的都是細節(jié)的配置,配置如何進行混淆 --><!-- 使用 KeepPublicApi 配置是否保持公開的 API 不進行混淆簽名,如公開的類型公開的方法等等,就不進行混淆簽名了 --><!-- 語法的寫法就是 name 表示某個開關(guān),而 value 表示值 --><!-- 對于大部分的庫來說,設(shè)置公開的 API 不進行混淆是符合預(yù)期的 --><Var name="KeepPublicApi" value="true" /><!-- 設(shè)置 HidePrivateApi 為 true 表示,對于私有的 API 進行隱藏,隱藏也就是混淆的意思 --><!-- 可以通過后續(xù)的配置,設(shè)置混淆的方式,例如使用 ABC 字符替換,或者使用不可見的 Unicode 代替 --><Var name="HidePrivateApi" value="true" /><!-- 設(shè)置 HideStrings 為 true 可以設(shè)置是否將使用的字符串進行二次編碼 --><!-- 由于進行二次編碼,將會稍微傷一點點性能,二次編碼需要在運行的時候,調(diào)用 Encoding 進行轉(zhuǎn)換為字符串 --><Var name="HideStrings" value="false" /><!-- 設(shè)置 UseUnicodeNames 為 true 表示使用不可見的 Unicode 字符代替原有的命名,通過此配置,可以讓反編譯看到的類和命名空間和成員等內(nèi)容都是不可見的字符 --><Var name="UseUnicodeNames" value="true" /><!-- 是否復(fù)用命名,設(shè)置為 true 的時候,將會復(fù)用命名,如在不同的類型里面,對字段進行混淆,那么不同的類型的字段可以是重名的 --><!-- 設(shè)置為 false 的時候,全局將不會有重復(fù)的命名 --><Var name="ReuseNames" value="true" /><!-- 配置是否需要重命名字段,默認配置了 HidePrivateApi 為 true 將都會打開重命名字段,因此這個配置的存在只是用來配置為 false 表示不要重命名字段 --><Var name="RenameFields" value="true" /><!-- 是否需要重新生成調(diào)試信息,生成 PDB 符號文件 --><Var name="RegenerateDebugInfo" value="true" /><!-- 需要進行混淆的程序集,可以傳入很多個,如傳入一排排 --><!-- <Module file="$(InPath)\Lib1.dll" /> --><!-- <Module file="$(InPath)\Lib2.dll" /> --><Module file="$(InPath)\HeenerholiCeleehano.dll" /><!-- 程序集的引用加載路徑,對于 dotnet 6 應(yīng)用,特別是 WPF 或 WinForms 項目,是需要特別指定引用加載路徑的 --><!-- 這里有一個小的需要敲黑板的知識點,應(yīng)該讓 Microsoft.WindowsDesktop.App 放在 Microsoft.NETCore.App 之前 --><!-- 對于部分項目,如果沒有找到如下順序,將會在混淆過程中,將某些程序集解析為舊版本,從而失敗 --><AssemblySearchPath path="C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App\6.0.1\" /><AssemblySearchPath path="C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.1\" /> </Obfuscator>詳細的配置,還請參閱官方文檔
執(zhí)行如上的命令行進行混淆,即可實現(xiàn)命名混淆效果
使用 dotPeek 反編譯可以看到字段被混淆為如下內(nèi)容
private readonly int \u00A0;private readonly short \u00A0;這里需要復(fù)習一下 IL 的知識,在 IL 里面,是允許不同的字段重名的,只要字段的類型不相同即可。因為使用的時候,是用類型名加字段名的方式使用的。這也能讓代碼更加混淆
以上就是我推薦的使用 dotnet tool 的方式
除了使用 dotnet tool 的方式之外,還可以自己將混淆過程嵌入到構(gòu)建過程里面,如此可以實現(xiàn)在開發(fā)階段對混淆的結(jié)果進行調(diào)試。也就是開發(fā)時調(diào)試的 DLL 就是混淆過后的
使用構(gòu)建過程的方式需要編輯一下 csproj 項目文件,先在項目文件使用下面代碼安裝 Obfuscar 庫,代碼如下
<ItemGroup><PackageReference Include="Obfuscar" Version="2.2.33"><PrivateAssets>all</PrivateAssets><IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets></PackageReference></ItemGroup>在需要寫構(gòu)建過程下,預(yù)計實際需求都是千奇百怪的,很難有統(tǒng)一的方式,本文只是提供一個簡單的例子
完成安裝之后,在項目上放一個混淆配置 Obfuscar.xml 文件,設(shè)置此文件如果較新則輸出
<ItemGroup><None Update="Obfuscar.xml"><CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory></None></ItemGroup>最后編寫一個 Target 用來在構(gòu)建完成之后調(diào)用命令行進行混淆,代碼如下
<Target Name="ObfuscarTask" AfterTargets="AfterBuild"><PropertyGroup><ObfuscateCommand>$(Obfuscar) "Obfuscar.xml"</ObfuscateCommand></PropertyGroup><Exec WorkingDirectory="$(OutputPath)" Command="$(ObfuscateCommand)" /></Target>如此即可實現(xiàn)在構(gòu)建完成之后,自動調(diào)用
以上的代碼放在?github?和?gitee?歡迎訪問
可以通過如下方式獲取本文的源代碼,先創(chuàng)建一個空文件夾,接著使用命令行 cd 命令進入此空文件夾,在命令行里面輸入以下代碼,即可獲取到本文的代碼
git init git remote add origin https://gitee.com/lindexi/lindexi_gd.git git pull origin b0b402abe4f32008d383d984bff677ac45cccde8以上使用的是 gitee 的源,如果 gitee 不能訪問,請?zhí)鎿Q為 github 的源
git remote remove origin git remote add origin https://github.com/lindexi/lindexi_gd.git獲取代碼之后,進入 HeenerholiCeleehano 文件夾
以上代碼的混淆配置 Obfuscar.xml 文件里使用的程序集引用路徑寫的是?C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App\6.0.1\?路徑,這是因為代碼是之前寫的,博客是鴿子很久才寫的,還請大家自行更新
混淆原理
此混淆工具底層使用?Mono.Cecil?進行程序集的讀取和編織,使用?Mono.Cecil?可以讀取出程序集的信息,從讀取到的信息進行更改,更改也就是混淆的核心邏輯,更改完成之后,再通過?Mono.Cecil?生成新的程序集文件,如此即可完成混淆
此工具在 GitHub 上完全開源,請看?https://github.com/obfuscar/obfuscar
更多細節(jié)邏輯還請自己去閱讀源代碼
更多閱讀
其他的混淆工具還有非常多,可以從?https://github.com/NotPrab/.NET-Obfuscator?找到更多的混淆工具列表
當然,有混淆工具,也就有反混淆工具。可以從?https://github.com/NotPrab/.NET-Deobfuscator?找到更多反混淆列表
總結(jié)
以上是生活随笔為你收集整理的.NET 6 使用 Obfuscar 进行代码混淆的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C# 观察文件的更改
- 下一篇: WPF效果第一百七十八篇ItemsCon