Skip to Content
Neue Version 12 verfügbar 🎉

Den Aufrufgraphen mit Dynamic Proxy verbergen

Ein Decompiler rekonstruiert vieles aus Methodenaufrufen: welche Framework-APIs Sie verwenden, wie Ihre eigenen Methoden ineinandergreifen und sogar die ursprünglichen Namen lokaler Variablen (abgeleitet aus den Typen, die Sie aufrufen). Dieses Beispiel schaltet mit dem NuGet-Paket von Babel Obfuscator Dynamic Proxy ein. Dynamic Proxy ersetzt direkte Aufrufe durch Aufrufe, die über generierte Proxy-Delegaten geleitet werden, sodass sich der Aufrufgraph nicht mehr aus den Metadaten ablesen lässt.

Für dieses Beispiel brauchen Sie eine Standortlizenz für Babel Obfuscator (Edition Ultimate, Server oder Data Center). Der Quellcode ist auf GitHub verfügbar:

git clone https://github.com/babelfornet/dynamic-proxy-nuget-example.git

Die zu verbergende Geschäftslogik besteht aus gewöhnlichen Methoden, die einander und die .NET-Bibliothek aufrufen (src/PricingEngine/Pricing.cs):

internal static class Pricing { public static decimal Quote(string sku, int quantity, string tier) { decimal unit = BasePrice(sku); // internal call decimal discounted = ApplyTierDiscount(unit, tier); decimal volume = ApplyVolumeBreak(discounted, quantity); return Math.Round(volume * quantity, 2); // external (BCL) call } // BasePrice / ApplyTierDiscount / ApplyVolumeBreak … }

Nach der Verschleierung ist keiner dieser Aufrufe mehr direkt, jeder läuft über einen generierten Proxy.

Das Konsolenprojekt PricingEngine schaltet Dynamic Proxy in Release mit einer einzigen Eigenschaft ein:

<ItemGroup Condition="'$(Configuration)' == 'Release'"> <PackageReference Include="Babel.Obfuscator" Version="12.0.0"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> </ItemGroup> <PropertyGroup Condition="'$(Configuration)' == 'Release'"> <DynamicProxy>external=true;internal=true;true</DynamicProxy> <FlattenNamespaces>true</FlattenNamespaces> <OverloadedRenaming>true</OverloadedRenaming> <BabelWarningsAsErrors>W00000</BabelWarningsAsErrors> </PropertyGroup>

Mit external=true werden Aufrufe in die .NET-Basisklassenbibliothek und in referenzierte Assemblys verborgen. Schon das vereitelt den Trick, mit dem ein Decompiler den ursprünglichen Namen einer Variable aus dem aufgerufenen Typ zurückgewinnt. Mit internal=true werden auch die Aufrufe zwischen Ihren eigenen Typen verborgen, was die Logik der Anwendung verschleiert. Dynamic Proxy deckt statische Aufrufe, Instanzaufrufe, virtuelle Aufrufe, Schnittstellenaufrufe und generische Aufrufe (einschließlich LINQ) ab und lässt eine kleine Gruppe von Aufrufen, die vom Aufrufer abhängen, direkt, damit sich das Verhalten nie ändert.

Ein Build des Beispiels in Release liefert eine identische Ausgabe und ersetzt dabei die ursprünglichen direkten Aufrufe der Preis-Engine durch generierte Proxy-Delegattypen. Der Aufrufablauf, den ein Decompiler rekonstruiert, ist nicht mehr der, den Sie geschrieben haben. Dynamic Proxy widersteht außerdem der automatisierten Deobfuskierung.

Last updated on