134 lines
5.8 KiB
Markdown
134 lines
5.8 KiB
Markdown
---
|
|
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 <AppName> | Select-Object Id,Path
|
|
# Path will be like C:\Program Files\WindowsApps\<PackageFullName>\<App>.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 `<Reference>` without HintPath for WinRT projections
|
|
- Copy all DLLs from install dir to `libs/` folder
|
|
- Add `<HintPath>libs\*.dll</HintPath>` for each reference
|
|
- Set `<LangVersion>preview</LangVersion>` (ILSpy may emit unsupported version)
|
|
- Set `<GenerateAssemblyInfo>False</GenerateAssemblyInfo>`
|
|
|
|
### 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
|
|
<Identity Name="<OriginalName>Rev" Publisher="<OriginalPublisher>" Version="3.7.2.7" ProcessorArchitecture="x64" />
|
|
```
|
|
- 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=<PublisherCN>" -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\<PackageFamilyName>!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%\<AppName>\<version>\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%\<AppName>\` for already-extracted dist
|
|
|
|
## Security cleanup (MANDATORY after install)
|
|
```powershell
|
|
# Remove self-signed cert from all stores
|
|
$certSubject = "CN=<PublisherCN>"
|
|
# Remove from LocalMachine\Root, LocalMachine\TrustedPeople, CurrentUser\My
|
|
# Delete PFX file
|
|
# Verify: Get-ChildItem Cert:\... | Where-Object { $_.Subject -eq $certSubject } returns empty
|
|
```
|