Skill_Linux CLI C# DLL Inspection & Decompilation

🔒 You must be logged in as an Administrator or Editor to listen to this audio.

Skill: Linux CLI C# DLL Inspection & Decompilation

Description: A comprehensive workflow for locating specific C# methods, classes, or strings inside compiled .dll binaries, tracing their origin to specific NuGet packages, and decompiling them into readable C# source code entirely within a Linux terminal environment, bypassing the need for a GUI IDE (like Visual Studio).

Tags: linux, csharp, dotnet, cli, reverse-engineering, debugging, nuget


⚙️ Prerequisites & Environment Setup

Before executing decompilation workflows, ensure the environment is equipped with the necessary .NET CLI tools. The binary search methods rely on standard POSIX utilities (find, grep, strings) which are pre-installed on virtually all Linux distributions.

Install the CLI Decompiler (ilspycmd): Requires the .NET SDK. Install globally using the dotnet toolchain:

dotnet tool install -g ilspycmd

Note: Ensure ~/.dotnet/tools is added to the system $PATH.


Phase 1: Binary Discovery (Locating the Target DLL)

When you know a method name (e.g., EnableAutoSetupIfNotUITesting) but do not know which compiled assembly contains it, use standard Linux text-processing tools to query the raw binary files directly. This approach is significantly faster than decompiling every file.

Primary Approach: grep Binary Forcing

The fastest method to scan a bin directory. The -a flag forces grep to treat binary files as plain text, while -l ensures only the file paths are returned, preventing terminal corruption from binary output.

Command:

find ./bin -name "*.dll" -exec grep -la "TARGET_METHOD_NAME" {} +
  • find ./bin -name "*.dll": Recursively locates all compiled assemblies in the current project's output directory.
  • -exec ... {} +: Batches the located files and passes them as arguments to grep.
  • grep -la: Outputs only the file paths (-l) of binaries treated as text (-a) that contain the target string.

Fallback Approach: The strings Utility

If grep -a fails due to specific binary encoding or unexpected EOF markers, use the strings command. This utility extracts all printable character sequences from a binary file.

Command:

find ./bin -name "*.dll" | while read -r file; do strings "$file" | grep -q "TARGET_METHOD_NAME" && echo "$file"; done
  • strings "$file": Extracts readable text from the DLL.
  • grep -q: Runs silently. If a match is found, the loop executes echo "$file" to print the path of the matching assembly.

Phase 2: Dependency Tracing (Identifying the NuGet Package)

Once the specific DLL is identified (e.g., ./bin/Debug/net8.0/Lombiq.Tests.UI.AppExtensions.dll), determine exactly how it was introduced into the project.

Method A: Querying the Project Assets File (Definitive)

The project.assets.json file acts as a comprehensive dependency graph. Querying this file reveals whether the package is a direct or transitive dependency.

Command:

grep -B 10 "Lombiq.Tests.UI.AppExtensions.dll" obj/project.assets.json
  • -B 10: Prints the 10 lines before the match, exposing the parent JSON node which contains the exact NuGet package name and version (e.g., "Lombiq.Tests.UI.AppExtensions/8.0.0").

Method B: Querying the Global NuGet Cache

NuGet extracts downloaded packages into a global cache. Finding the DLL in this cache exposes its origin via the directory structure.

Command:

find ~/.nuget/packages -name "Lombiq.Tests.UI.AppExtensions.dll"
  • Output Structure: /home/user/.nuget/packages/{package_name}/{package_version}/lib/...

Phase 3: Source Code Extraction (Decompilation)

After locating the correct DLL, use ilspycmd to translate the Intermediate Language (IL) back into human-readable C# source code.

Option 1: Targeted Context Extraction (Fastest for Reading)

Decompile the entire DLL into standard output and pipe it directly into grep to extract the specific method and its surrounding context, without creating permanent files.

Command:

ilspycmd /path/to/TargetLibrary.dll | grep -n -A 50 "TARGET_METHOD_NAME"
  • -n: Prints the line number of the source code.
  • -A 50: Prints the 50 lines of code after the match, revealing the method signature and its internal implementation.
  • Use -B 10 in conjunction to see class definitions or attributes located immediately above the method.

Option 2: Full File Decompilation (Best for Deep Inspection)

Dump the decompiled code into a physical .cs file to navigate it using terminal editors like vim, nano, or less.

Command:

# Dump the code
ilspycmd /path/to/TargetLibrary.dll > /tmp/decompiled_library.cs

# Open with less and search
less /tmp/decompiled_library.cs
# Type '/' followed by the method name (e.g., /EnableAutoSetupIfNotUITesting) to jump to the code.

Option 3: Full Project Decompilation

If deep architectural inspection is required, ilspycmd can reconstruct an entire .csproj from the compiled binary.

Command:

ilspycmd /path/to/TargetLibrary.dll -p -o /tmp/DecompiledProjectDir
  • -p: Instructs the tool to create a project structure.
  • -o: Specifies the output directory where the .csproj and multiple .cs files will be written.

🤖 Agent Execution Flow

If automating this skill, an agent should follow this deterministic logic tree:

  1. Receive Objective: "Find the implementation of method X in the current project."
  2. Execute Phase 1: Run the find + grep command on the project's ./bin or ./obj directories to isolate the target .dll.
    • If no .dll is found: Check global NuGet cache (~/.nuget/packages).
  3. Execute Phase 2 (Optional): If the user needs to know where the code came from, parse obj/project.assets.json.
  4. Execute Phase 3: Run ilspycmd on the located .dll.
    • If ilspycmd is not found: Attempt to install it via dotnet tool install -g ilspycmd.
  5. Output Generation: Pipe the decompiled source through grep -A to extract the relevant block of code and return it to the context window.