4

I tried using Dotpeek and ILSpy.Net to decompile (my own code), they failed.

Do I need special obfuscation on distributed binaries of .Net Core 3 self-contained single executable ?

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.0</TargetFramework>
    <PublishTrimmed>true</PublishTrimmed>
    <PublishReadyToRun>true</PublishReadyToRun>
    <PublishSingleFile>true</PublishSingleFile>
    <RuntimeIdentifier>win-x64</RuntimeIdentifier>
  </PropertyGroup>
</Project>
Eren Ersönmez
  • 38,383
  • 7
  • 71
  • 92
Abhijeet
  • 13,562
  • 26
  • 94
  • 175
  • 2
    Self-contained executables are basically zip files containing the necessary DLLs. Dotpeek and ILSpy probably don`t support that format yet, but it is NOT obfuscated out of the box. – ESG Feb 02 '20 at 14:00
  • 1
    @ESG What do you think about .NET 5? – Jackop Nov 06 '20 at 03:22
  • @Jackop they changed how the executables are built so they don't need unpacking, but no idea if decompilers will support it – ESG Nov 06 '20 at 03:47

3 Answers3

9

The single-file exe is really an unmanaged wrapper and ILSpy doesn't support decompiling this. But when you run the exe, it unwraps its contents to a temp folder. So you can find the managed dll there and decompile it using ILSpy.

To find the temp folder, you can use any tool that shows locations of assemblies loaded by a process. SysInternals Process Monitor (procmon) is a good one.

You can setup procmon to filter by your exe name, and when you launch your exe, procmon should show some events for assemblies being loaded from a temp folder:

screenshot

You can browse to that folder and find your managed dll there. And you can decompile using ILSpy from that location.

I wrote a blog entry: https://eersonmez.blogspot.com/2020/02/ilspy-decompiling-net-core-self.html

Eren Ersönmez
  • 38,383
  • 7
  • 71
  • 92
  • 1
    > In .NET Core 3.0 you can compile to a single executable, but that executable is actually a compressed version of all the files needed to execute at runtime. When you execute the file, it first expands itself out into a temporary directory and then executes the entry point of the application from the directory that contains all the files. By contrast, .NET 5 will create a true, single-executable file that can execute directly in place. – Jackop Nov 06 '20 at 03:20
  • @Jackop Could you give me the references(docs) about `.NET 5 will create a true, single-executable file that can execute directly in place.` ? – huang Jan 22 '21 at 14:58
  • 1
    ILSpy 7.0 (currently available as preview) supports decompiling .NET Core 3 and .NET 5 bundles. – Daniel Feb 18 '21 at 12:33
3

I wrote a small dotnet tool after I stumbled upon this question and couldn't find a lightweight tool myself other than ILSpy.

You can install it using the following dotnet command: dotnet tool install -g sfextract.

After installing it, run it using the following command: sfextract application.exe -o output-dir

The bundle format for .NET 5.0 (bundle version 2) is identical to previous versions. .NET 6.0 (bundle version 6) has an additional field for each file entry containing the compressed size, since single-file applications can now be compressed using gzip by setting EnableCompressionInSingleFile to true.

https://www.nuget.org/packages/sfextract/ https://github.com/Droppers/SingleFileExtractor

Joery
  • 759
  • 4
  • 13
  • 33
  • Hi I tried this and it's perfectly decompiled my app. But how can I avoid someone from decompiling my app just in case I'll distribute to my other friends? – mark12345 May 04 '22 at 19:24
  • @mark12345 you can't, a .NET application is compiled to IL-code which are high level instructions that can be pretty accurately translated to for example C# again. NativeAOT is scheduled to be included with .NET 7, which will allow you to compile to machine code directly, this would make it more difficult to reverse engineer but is still possible. – Joery May 05 '22 at 07:49
0

Update 07/2022: .Net 5 single-file does not automatically unpack to the same temporary location as before. to force it to be unpacked you would need to add the following:

  1. in the project file add these properties (according to theseMicrosoft docs):
<PublishSingleFile>true</PublishSingleFile>
<IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
  1. Add an environment variable DOTNET_BUNDLE_EXTRACT_BASE_DIR with the location you want the files extracted to.

Update: One of the announcements made regarding .Net 5 states that the way single-file executables will be made would change, so this method will not work for them.

I wanted to add on @Eren Ersönmez's answer, that while ILSpy DotPeek don't support this at the time, since the self-contained single file is just a wrapper that contains all your DLLs and gets extracted on runtime, simply knowing where it is extracted to can save you using ProcMon or ProExp or windbg.

If you use windows you can go to c:\Users\{Local Username}\AppData\local\temp\.net\{Name of executable} which should lead to somewhere similar to c:\Users\alenros\AppData\Local\Temp.net\MyTestApplication

Launch your exe, and a folder with the same name will be created in that location. The folder will contain randomly named folders. open the latest one and there you will find all your extracted DLLs, which can then be decompiled.

Alenros
  • 816
  • 7
  • 23