--- name: winui3-reverse-engineering description: "Reverse engineer WinUI 3 / .NET 8 MSIX applications: ILSpy decompilation, self-contained publish, MSIX packaging with self-signed cert, and side-by-side launch with modified code" --- # WinUI 3 Reverse Engineering Pipeline ## When to use Reverse engineering a WinUI 3 / Windows App SDK / .NET 8 MSIX-packaged desktop application. Produces editable C# source, rebuildable MSIX, and a running modified app side-by-side with the original. ## Prerequisites - ILSpy CLI (`dotnet tool install --global ilspycmd`) - .NET 8 SDK - Windows SDK (makeappx.exe, signtool.exe, makepri.exe) - PowerShell 5+ - Target app installed as MSIX (in `C:\Program Files\WindowsApps\`) ## Steps ### 1. Locate the app ```powershell Get-Process | Select-Object Id,Path # Path will be like C:\Program Files\WindowsApps\\.exe ``` ### 2. Identify the stack - `.dll` next to `.exe` = .NET app (check for `coreclr.dll`, `hostfxr.dll`) - Main `.dll` (3+ MB) = application logic; `.exe` (small) = native loader - `resources.pri` = XAML binary (XBF) + strings + images - `Watchers\` or similar = backend services (may be pkg-compiled Node.js) ### 3. Decompile C# ```bash ilspycmd "C:\path\to\App.dll" -p -o "C:\output\src" --decompile-baml -r "C:\path\to\install\dir" ``` - `--decompile-baml` may not work for WinUI 3 (XBF v2.1, not BAML) - `-r` provides reference path for dependency resolution ### 4. Fix csproj - ILSpy generates bare `` without HintPath for WinRT projections - Copy all DLLs from install dir to `libs/` folder - Add `libs\*.dll` for each reference - Set `preview` (ILSpy may emit unsupported version) - Set `False` ### 5. Fix common compile errors - **CS0136** (duplicate variable): rename one occurrence - **CS0104** (ambiguous `Color`): qualify as `Windows.UI.Color.FromArgb(...)` - **CS1061** (`PaneBackground` not on NavView): use `Background` instead - **CS1061** (`RequestedTheme` not on Window): set on `Content` element instead - ILSpy inlines `const` values — fix inline literals (e.g., `FindOrRegisterForKey("OriginalKey")` → `FindOrRegisterForKey(AppInstanceKey)`) ### 6. Publish self-contained ```bash dotnet publish App.csproj -c Release -r win-x64 --self-contained true ``` - Framework-dependent publish fails in MSIX (no global .NET runtime visible) - Self-contained bundles .NET runtime into the package ### 7. Overlay original assets Copy from original MSIX to publish output (whitelist only, never overwrite published exe/dll): - `resources.pri` (XBF, strings, images) - `Assets/` folder - `Watchers/` folder (backend) - Locale directories (`xx-XX/`) - `Microsoft.UI.Xaml/` folder - Native WinUI DLLs (Microsoft.UI.Xaml.Controls.dll, CoreMessagingXP.dll, etc.) - `Microsoft.WindowsAppRuntime.dll`, `.Bootstrap.dll`, `.Bootstrap.Net.dll` ### 8. Create AppxManifest with new identity ```xml ``` - Use same Publisher CN as original (for cert matching) - Bump version on each rebuild - Keep `runFullTrust` capability ### 9. Self-signed cert + MSIX packaging ```powershell # Create cert matching manifest Publisher $cert = New-SelfSignedCertificate -Subject "CN=" -KeyUsage DigitalSignature -CertStoreLocation "Cert:\CurrentUser\My" -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.3","2.5.29.19={text}") # Add to Trusted Root and Trusted People # Export PFX, sign MSIX with signtool # Register with Add-AppxPackage # CRITICAL: Remove cert from all stores and delete PFX after install # See cleanup section below ``` ### 10. Launch and verify ```powershell Start-Process explorer.exe -ArgumentList 'shell:AppsFolder\!App' Start-Sleep -Seconds 10 # WinUI 3 needs time to initialize # Verify: PID, Path (must be Rev package), MainWindowTitle, RAM > 100MB # UI Automation: [System.Windows.Automation.AutomationElement]::FromHandle() # Screenshot: System.Drawing.Bitmap + CopyFromScreen + GetPixel for color verification ``` ## Key gotchas - WinUI 3 XAML is compiled to XBF v2.1 in `resources.pri`, NOT BAML — ILSpy `--decompile-baml` won't extract it - `copy_all.ps1` that copies ALL MSIX files will overwrite rebuilt exe/dll with originals — always whitelist - `NODE_SEA_FUSE:0` = disabled SEA; check for `pkg` markers (`PRELUDE_POSITION`, `process.versions.pkg`) instead - pkg auto-extracts to `%TEMP%\\\dist` — check there before manual extraction - Cert in LocalMachine\Root with accessible PFX = code signing security risk — always cleanup after - `Start-Process` cannot launch `shell:AppsFolder` URIs directly — use `explorer.exe` as intermediary - Process may show 0x0 window for 10+ seconds before UI initializes — wait before screenshot ## XBF extraction (if needed) ```powershell # Dump PRI makepri.exe dump /if "resources.pri" /of "dump.xml" /dt detailed /o # Extract XBF from Base64 in XML # XBF v2.1 offsets are relative to metadata start (byte 12), not absolute # Table entries are 12 bytes each (not 8 as in v1.0) # Node encoding differs from v1.0 — no working open-source parser exists ``` ## pkg-compiled Node.js backend detection - PE header: no CLR header (not .NET) - Search for `NODE_SEA_FUSE`, `pkg/prelude`, `process.versions.pkg` - `process.versions.pkg = '6.22.0'` confirms pkg version - Trailing data after PE sections (gzip compressed) = pkg payload - Auto-extraction: check `%TEMP%\\` for already-extracted dist ## Security cleanup (MANDATORY after install) ```powershell # Remove self-signed cert from all stores $certSubject = "CN=" # Remove from LocalMachine\Root, LocalMachine\TrustedPeople, CurrentUser\My # Delete PFX file # Verify: Get-ChildItem Cert:\... | Where-Object { $_.Subject -eq $certSubject } returns empty ```