Melindungi kode .Net dari rekayasa balik dengan ConfuserEx 0.6.0

Artikel ini menjelaskan pengalaman memerangi penggunaan obfuscator ConfuserEx 0.6.0 untuk melindungi layanan .Net di bawah Windows dan Mono. Itu kembali pada tahun 2016, tetapi, saya pikir, topik tersebut tidak kehilangan relevansinya sekarang.



ConfuserEx ( http://yck1509.github.io/ConfuserEx/ ) adalah salah satu obfuscator open source gratis untuk .Net. Mendukung Windows .NET Framework dan Mono.

Berisi sejumlah besar modul yang mengimplementasikan berbagai metode perlindungan kode (penggantian nama, obfuscation alur eksekusi, enkripsi resource dan konstanta, perlindungan terhadap debugging dan pembuatan profil, wrappers). ConfuserEx memungkinkan Anda memperluas fungsionalitas dengan menulis modul keamanan Anda sendiri.



Kode sumber terbuka memungkinkan Anda memodifikasi sistem proteksi, mengubah tanda tangan obfuscator, sehingga menyulitkan program de-obfuscator dan rekayasa balik manual.



Dokumentasi



Proyek ini memiliki dokumentasi yang cukup rinci dalam format WiKi .



Antarmuka pengguna



ConfuserEx mendukung mode UI dan baris perintah.



Mode baris perintah



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.


File proyek



Struktur file proyek dijelaskan dalam dokumentasi . File proyek berisi deskripsi rakitan yang perlu dilindungi, pengaturan modul perlindungan dan aturan yang digunakan modul perlindungan untuk melindungi rakitan.



Aturan memungkinkan Anda untuk secara selektif menerapkan (atau tidak menerapkan) modul perlindungan ke bagian kode yang berbeda. Selama kebingungan, aturan diperiksa untuk penerapannya pada elemen kode yang dilindungi saat ini. Dalam hal ini, kepatuhan yang disebut tanda tangan elemen kode dengan aturan dievaluasi . Aturan dapat berisi ekspresi logis yang kompleks .



.



<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>




ConfuserEx . , .



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:]'";




Untuk semua elemen kode yang dimulai dengan ShellCommand , menggunakan aturan dalam file proyek, modul Perlindungan Nama telah dinonaktifkan (nama dipertahankan). Anda bisa melihat hasil dari modul Constants Protection .



internal sealed class _ob : _qA
{
  private readonly string ShellCommandNetworkAdapterMACAddress = \u003CModule\u003E.\u206Eā€¬ā€Œā€­ā€­āÆā€¬ā€ā­ā­ā€®ā€¬ā¬ā¬ā€¬ā«ā«ā€Ŗā®ā€®ā€«ā€­ā€Œā®ā€Œā¬ā€¬āŖā­ā€­ā€Ŗā­ā€ŽāŖā«ā€®<string>(3331371713U);
  private readonly string ShellCommandNetworkAdapterCaption = \u003CModule\u003E.\u206Fā«ā€Œā€¬āÆā®ā­ā€ā®ā®ā«ā¬ā€«āÆā¬ā€­ā€āŖā¬ā€Œā€ā¬āÆāÆā€Ŗā€¬āŖā€«ā®ā€Žā¬ā€­ā«ā­ā¬ā¬ā€Žā€®āÆā€®<string>(4243712535U);</source>



All Articles