本文介绍了在Windows和Mono下使用ConfuserEx 0.6.0混淆器来保护.Net服务的实践经验。早在2016年,但我认为该主题现在并没有失去其相关性。
ConfuserEx(http://yck1509.github.io/ConfuserEx/)是.Net的免费开源混淆器之一。支持Windows .NET Framework和Mono。
包含大量实现各种代码保护方法的模块(重命名,混淆执行流,对资源和常量进行加密,针对调试和概要分析的保护,包装器)。ConfuserEx允许您通过编写自己的安全模块来扩展功能。
开源代码允许您修改保护系统,更改混淆器的签名,从而使去混淆器程序和手动逆向工程变得困难。
文献资料
该项目有相当详细的WiKi格式文档。
用户界面
ConfuserEx支持UI和命令行模式。
命令行模式
ConfuserEx\bin\Confuser.CLI.exe
ConfuserEx.CLI: No input files specified.
Usage:
Confuser.CLI -n|noPause <project configuration>
Confuser.CLI -n|noPause -o|out=<output directory> <modules>
-n|noPause : no pause after finishing protection.
-o|out : specifies output directory.
-probe : specifies probe directory.
-plugin : specifies plugin path.
-debug : specifies debug symbol generation.</source>
ConfuserEx\bin\Confuser.CLI.exe -n LicenseManagerService.crproj
[INFO] ConfuserEx v0.6.0-custom Copyright (C) Ki 2014
[INFO] Running on Microsoft Windows NT 6.1.7601 Service Pack 1, .NET Framework v4.0.30319.0, 64 bits
[DEBUG] Discovering plugins...
[INFO] Discovered 10 protections, 1 packers.
[DEBUG] Resolving component dependency...
[INFO] Loading input modules...
[INFO] Loading 'LicenseManagerService\bin\x86\Release\LicenseManagerService.exe'...
[INFO] Initializing...
[DEBUG] Building pipeline...
[INFO] Resolving dependencies...
[DEBUG] Checking Strong Name...
[DEBUG] Creating global .cctors...
[DEBUG] Executing 'Name analysis' phase...
[DEBUG] Building VTables & identifier list...
[DEBUG] Analyzing...
[INFO] Processing module 'LicenseManagerService.exe'...
[DEBUG] Executing 'Invalid metadata addition' phase...
[DEBUG] Executing 'Renaming' phase...
[DEBUG] Renaming...
[DEBUG] Executing 'Anti-debug injection' phase...
[DEBUG] Executing 'Anti-dump injection' phase...
[DEBUG] Executing 'Anti-ILDasm marking' phase...
[DEBUG] Executing 'Encoding reference proxies' phase...
[DEBUG] Executing 'Constant encryption helpers injection' phase...
[DEBUG] Executing 'Resource encryption helpers injection' phase...
[DEBUG] Executing 'Constants encoding' phase...
[DEBUG] Executing 'Anti-tamper helpers injection' phase...
[DEBUG] Executing 'Control flow mangling' phase...
[DEBUG] Executing 'Post-renaming' phase...
[DEBUG] Executing 'Anti-tamper metadata preparation' phase...
[DEBUG] Executing 'Packer info extraction' phase...
[INFO] Writing module 'LicenseManagerService.exe'...
[DEBUG] Encrypting resources...
[INFO] Finalizing...
[INFO] Packing...
[DEBUG] Encrypting modules...
[INFO] Protecting packer stub...
[DEBUG] Discovering plugins...
[INFO] Discovered 11 protections, 1 packers.
[DEBUG] Resolving component dependency...
[INFO] Loading input modules...
[INFO] Loading 'LicenseManagerService\bin\x86\Release\LicenseManagerService.exe'...
[INFO] Initializing...
[DEBUG] Building pipeline...
[INFO] Resolving dependencies...
[DEBUG] Checking Strong Name...
[DEBUG] Creating global .cctors...
[DEBUG] Executing 'Name analysis' phase...
[DEBUG] Building VTables & identifier list...
[DEBUG] Analyzing...
[INFO] Processing module 'LicenseManagerService.exe'...
[DEBUG] Executing 'Packer info encoding' phase...
[DEBUG] Executing 'Invalid metadata addition' phase...
[DEBUG] Executing 'Renaming' phase...
[DEBUG] Renaming...
[DEBUG] Executing 'Anti-debug injection' phase...
[DEBUG] Executing 'Anti-dump injection' phase...
[DEBUG] Executing 'Anti-ILDasm marking' phase...
[DEBUG] Executing 'Encoding reference proxies' phase...
[DEBUG] Executing 'Constant encryption helpers injection' phase...
[DEBUG] Executing 'Resource encryption helpers injection' phase...
[DEBUG] Executing 'Constants encoding' phase...
[DEBUG] Executing 'Anti-tamper helpers injection' phase...
[DEBUG] Executing 'Control flow mangling' phase...
[DEBUG] Executing 'Post-renaming' phase...
[DEBUG] Executing 'Anti-tamper metadata preparation' phase...
[DEBUG] Executing 'Packer info extraction' phase...
[INFO] Writing module 'LicenseManagerService.exe'...
[DEBUG] Encrypting resources...
[INFO] Finalizing...
[DEBUG] Saving to 'C:\Users\pash76\AppData\Local\Temp\ehwkjzxt.brh\mqqtgvji.gxk\LicenseManagerService\bin\x86\Release\LicenseManagerService.exe'...
[DEBUG] Executing 'Export symbol map' phase...
[INFO] Finish protecting packer stub.
[DEBUG] Saving to 'D:\pash76\Develop\License_manager\Confused\LicenseManagerService\bin\x86\Release\LicenseManagerService.exe'...
[DEBUG] Executing 'Export symbol map' phase...
[INFO] Done.
Finished at 9:35, 0:03 elapsed.
项目文件
项目文件的结构中描述的文档。项目文件包含对需要保护的程序集的描述,保护模块的设置以及应用保护模块以保护程序集的规则。
规则允许您有选择地将保护模块应用于(或不应用于)代码的不同部分。在混淆期间,将检查规则是否适用于当前受保护的代码元素。在这种情况下,评估代码元素的所谓签名与规则的符合性。规则可以包含复杂的逻辑表达式。
<project outputDir=".\Confused" baseDir=".\" xmlns="http://confuser.codeplex.com">
<rule pattern="true" inherit="false">
<protection id="anti ildasm" />
<protection id="anti tamper" action="remove" />
<protection id="constants">
<argument name="mode" value="dynamic" />
<argument name="decoderCount" value="13" />
<argument name="elements" value="SIP" />
<argument name="cfg" value="false" />
</protection>
<protection id="ctrl flow" />
<protection id="anti dump" action="remove" />
<protection id="anti debug" />
<protection id="invalid metadata" action="remove" />
<protection id="ref proxy" />
<protection id="resources">
<argument name="mode" value="dynamic" />
</protection>
<protection id="rename">
<argument name="mode" value="sequential" />
</protection>
</rule>
<packer id="compressor">
<argument name="key" value="dynamic" />
<argument name="compat" value="true" />
</packer>
<module path="LicenseManagerService\bin\x86\Release\LicenseManagerService.exe">
<rule pattern="
match('UAVLicenseManager\.CentOSSystemInfoProvider::ShellCommand.*')
or match(' ?LicenseManagerService\.Program(::)?')
or match(' ?LicenseManagerService\.UAVLicenseManagerService(::)?')
or (
match(' ?UAVLicenseManager\.License(::)?')
and is-public()
and (member-type('type') or member-type('field') or member-type('property'))
)
or match(' ?UAVLicenseManager\.LicenseKey(::)?')
or match(' ?UAVLicenseManager\.LicenseOwner(::)?')
or match(' ?UAVLicenseManager\.Location(::)?')
or match(' ?UAVLicenseManager\.LicenseLimit(::)?')
" inherit="true">
<protection id="rename" action="remove" />
</rule>
</module>
</project>
Name Protection Reflection . , .
mono, mono. , .
Windows | Mono | |
---|---|---|
Anti Debug Protection | ||
Anti Dump Protection | ||
Anti IL Dasm Protection | ||
Anti Tamper Protection | ||
Compressor | ( ) | |
Constants Protection | ( cfg ) | |
Control Flow Protection | ||
Invalid Metadata Protection | ||
Name Protection | ||
Reference Proxy Protection | ||
Resources Protection |
, , IL-. dotPeek ConfuserEx. , dotPeek .
ConfuserEx. , ConfusedByAttribute. -.
ConfuserEx\src\Confuser.Core\ConfuserEngine.cs
static void Inspection(ConfuserContext context) {
context.Logger.Info("Resolving dependencies...");
foreach (var dependency in context.Modules
.SelectMany(module => module.GetAssemblyRefs().Select(asmRef => Tuple.Create(asmRef, module)))) {
try {
AssemblyDef assembly = context.Resolver.ResolveThrow(dependency.Item1, dependency.Item2);
}
catch (AssemblyResolveException ex) {
context.Logger.ErrorException("Failed to resolve dependency of '" + dependency.Item2.Name + "'.", ex);
throw new ConfuserException(ex);
}
}
context.Logger.Debug("Checking Strong Name...");
foreach (ModuleDefMD module in context.Modules) {
var snKey = context.Annotations.Get<StrongNameKey>(module, Marker.SNKey);
if (snKey == null && module.IsStrongNameSigned)
context.Logger.WarnFormat("[{0}] SN Key is not provided for a signed module, the output may not be working.", module.Name);
else if (snKey != null && !module.IsStrongNameSigned)
context.Logger.WarnFormat("[{0}] SN Key is provided for an unsigned module, the output may not be working.", module.Name);
else if (snKey != null && module.IsStrongNameSigned &&
!module.Assembly.PublicKey.Data.SequenceEqual(snKey.PublicKey))
context.Logger.WarnFormat("[{0}] Provided SN Key and signed module's public key do not match, the output may not be working.", module.Name);
}
var marker = context.Registry.GetService<IMarkerService>();
context.Logger.Debug("Creating global .cctors...");
foreach (ModuleDefMD module in context.Modules) {
TypeDef modType = module.GlobalType;
if (modType == null) {
modType = new TypeDefUser("", "<Module>", null);
modType.Attributes = TypeAttributes.AnsiClass;
module.Types.Add(modType);
marker.Mark(modType, null);
}
MethodDef cctor = modType.FindOrCreateStaticConstructor();
if (!marker.IsMarked(cctor))
marker.Mark(cctor, null);
}
//context.Logger.Debug("Watermarking...");
//foreach (ModuleDefMD module in context.Modules) {
// TypeRef attrRef = module.CorLibTypes.GetTypeRef("System", "Attribute");
// var attrType = new TypeDefUser("", "ConfusedByAttribute", attrRef);
// module.Types.Add(attrType);
// marker.Mark(attrType, null);
// var ctor = new MethodDefUser(
// ".ctor",
// MethodSig.CreateInstance(module.CorLibTypes.Void, module.CorLibTypes.String),
// MethodImplAttributes.Managed,
// MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
// ctor.Body = new CilBody();
// ctor.Body.MaxStack = 1;
// ctor.Body.Instructions.Add(OpCodes.Ldarg_0.ToInstruction());
// ctor.Body.Instructions.Add(OpCodes.Call.ToInstruction(new MemberRefUser(module, ".ctor", MethodSig.CreateInstance(module.CorLibTypes.Void), attrRef)));
// ctor.Body.Instructions.Add(OpCodes.Ret.ToInstruction());
// attrType.Methods.Add(ctor);
// marker.Mark(ctor, null);
// var attr = new CustomAttribute(ctor);
// attr.ConstructorArguments.Add(new CAArgument(module.CorLibTypes.String, Version));
// module.CustomAttributes.Add(attr);
//}
}
, .net ConfuserEx. koi.
ConfuserEx\src\Confuser.Protections\Compress\Compressor.cs
ConfuserEx\src\Confuser.Runtime\Compressor.cs
ConfuserEx\src\Confuser.Protections\Compress\ExtractPhase.cs
ConfuserEx\src\Confuser.Protections\Compress\StubProtection.cs
( dotPeek). .
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
[assembly: InternalsVisibleTo("LicenseManagerServiceTests")]
namespace LicenseManagerService
{
static class Program
{
/// <summary>
/// .
/// </summary>
///
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new UAVLicenseManagerService()
};
ServiceBase.Run(ServicesToRun);
}
}
}
dotPeek
LicenseManagerService.Program, , Name Protection ( ). Control Flow Protection.
// Decompiled with JetBrains decompiler
// Type: LicenseManagerService.Program
// Assembly: LicenseManagerService, Version=1.0.5980.24716, Culture=neutral, PublicKeyToken=null
// MVID: A6EB17CC-65EE-4E2D-B66C-24E166429A4A
// Assembly location: D:\pash\Develop\License_manager\Confused\LicenseManagerService\bin\x86\Release\LicenseManagerService.exe
using System.Runtime.InteropServices;
using System.ServiceProcess;
namespace LicenseManagerService
{
internal static class Program
{
private static void Main()
{
ServiceBase[] serviceBaseArray1 = new ServiceBase[1]
{
(ServiceBase) new UAVLicenseManagerService()
};
label_1:
int num1 = 1005209177;
ServiceBase[] serviceBaseArray2;
while (true)
{
int num2 = 1280737639;
uint num3;
switch ((num3 = (uint) (num1 ^ num2)) % 3U)
{
case 0U:
goto label_1;
case 1U:
serviceBaseArray2 = serviceBaseArray1;
num1 = (int) num3 * 1248105312 ^ 483770479;
continue;
default:
goto label_4;
}
}
label_4:
Program.\u200E(serviceBaseArray2);
}
static void \u200E([In] ServiceBase[] obj0)
{
ServiceBase.Run(obj0);
}
}
}
private readonly string ShellCommandNetworkAdapterMACAddress =
@"ip -o link show | grep -m 1 'UP.*LOWER_UP.*ether\|LOWER_UP.*UP.*ether' | sed -n 's/.*ether \(.*\) brd.*/\1/p' | tr -d '\n[:blank:]'";
对于使用ShellCommand开头的所有代码元素,使用项目文件中的规则,名称保护模块已被禁用(名称已保留)。您可以看到“常量保护”模块的结果。
internal sealed class _ob : _qA
{
private readonly string ShellCommandNetworkAdapterMACAddress = \u003CModule\u003E.\u206E<string>(3331371713U);
private readonly string ShellCommandNetworkAdapterCaption = \u003CModule\u003E.\u206F<string>(4243712535U);</source>