135 lines
5.0 KiB
Markdown
135 lines
5.0 KiB
Markdown
---
|
|
name: reverse-winui3-pkg-app
|
|
description: "Reverse engineer a WinUI 3 (.NET 8) desktop app with a pkg-compiled Node.js backend: ILSpy decompilation, XBF extraction from resources.pri, pkg payload extraction, self-contained publish, MSIX packaging with self-signed cert, and side-by-side launch"
|
|
---
|
|
|
|
# Reverse Engineering WinUI 3 + pkg-compiled Node.js Applications
|
|
|
|
## When to use
|
|
Reversing a Windows desktop app that is:
|
|
- WinUI 3 / Windows App SDK (.NET 8) frontend
|
|
- pkg-compiled Node.js backend (VibeProxyServices.exe pattern)
|
|
- Installed as MSIX in `C:\Program Files\WindowsApps\`
|
|
|
|
## Phase 1: Locate and identify
|
|
|
|
```powershell
|
|
# Find running process
|
|
Get-Process | Where-Object { $_.ProcessName -match 'TargetApp' }
|
|
# Get install path
|
|
(Get-Process TargetApp).Path
|
|
```
|
|
|
|
Identify app type by inspecting install directory:
|
|
- `coreclr.dll`, `hostfxr.dll` → .NET 8 app
|
|
- `VibeProxy.dll` (main logic) + `VibeProxy.exe` (thin launcher) → ILSpy target
|
|
- `resources.pri` → XBF/XAML resources embedded
|
|
- `Watchers\*.exe` (large, 100MB+) → likely pkg-compiled Node.js backend
|
|
|
|
## Phase 2: Decompile C# with ILSpy
|
|
|
|
```bash
|
|
# Install ILSpy CLI
|
|
dotnet tool install --global ilspycmd
|
|
|
|
# Decompile main DLL with reference path for WinRT projections
|
|
ilspycmd "C:\path\to\App.dll" -p -o "C:\output\src" -r "C:\path\to\install\dir"
|
|
```
|
|
|
|
Key fixes after decompilation:
|
|
- `LangVersion` in csproj: change to `preview` (ILSpy may set unsupported version)
|
|
- `CS0136` duplicate variables: rename second occurrence
|
|
- `FindOrRegisterForKey("literal")`: ILSpy inlines string constants — fix call site to use const
|
|
- `Color` ambiguity: qualify as `Windows.UI.Color.FromArgb(...)` not `Color.FromArgb(...)`
|
|
- `NavigationView.PaneBackground` doesn't exist in WinUI 3 — use `NavView.Background` instead
|
|
- `Window.RequestedTheme` not available — set theme on child elements instead
|
|
|
|
## Phase 3: Extract XBF from resources.pri
|
|
|
|
```bash
|
|
# Dump PRI with makepri
|
|
makepri.exe dump /if "resources.pri" /of "dump.xml" /dt detailed /o
|
|
|
|
# Extract XBF binaries from Base64 in dump XML (PowerShell script)
|
|
# XBF entries have type="EmbeddedData" with Base64Value
|
|
```
|
|
|
|
XBF v2.1 format (WinUI 3):
|
|
- Header: 12 bytes (magic + metaSize + nodeSize)
|
|
- Offsets are relative to byte 12 (meta_start)
|
|
- String table: uint32 count, then length-prefixed UTF-16LE strings with 2-byte padding
|
|
- Type/Property tables: 12 bytes per entry (not 8)
|
|
- Node section starts at `12 + metaSize`
|
|
- Node encoding differs from XBF v1.0 — existing tools (LibXbf) don't work
|
|
|
|
## Phase 4: Extract pkg backend
|
|
|
|
pkg self-extracts to `%TEMP%\AppName\version\dist` at runtime.
|
|
Check there first — no need to parse the 298MB binary.
|
|
|
|
```powershell
|
|
Get-ChildItem "$env:TEMP\AppName" -Recurse
|
|
```
|
|
|
|
If not extracted yet, identify pkg version:
|
|
- Search binary for `process.versions.pkg` → e.g. `'6.22.0'`
|
|
- Search for `NODE_SEA_FUSE` — if `:0`, it's pkg not SEA
|
|
- Trailing data after PE sections is gzip-compressed pkg payload
|
|
|
|
## Phase 5: Build and package
|
|
|
|
```bash
|
|
# Self-contained publish (critical — FDD won't work in MSIX)
|
|
dotnet publish App.csproj -c Release -r win-x64 --self-contained true
|
|
```
|
|
|
|
Create staging directory from publish output, then overlay original:
|
|
- `resources.pri` (XBF, strings, images)
|
|
- `Assets/` folder
|
|
- `Watchers/` folder
|
|
- Locale directories (`xx-XX/`)
|
|
- `Microsoft.UI.Xaml/` folder
|
|
- Native WinUI DLLs (whitelist — never overwrite published exe/dll)
|
|
|
|
## Phase 6: MSIX packaging with self-signed cert
|
|
|
|
```powershell
|
|
# Create cert matching manifest Publisher
|
|
$cert = New-SelfSignedCertificate -Subject "CN=PublisherFromManifest" ...
|
|
# Add to Trusted Root and Trusted People
|
|
# Pack with makeappx
|
|
makeappx.exe pack /d staging /p App.msix /nv
|
|
# Sign with signtool
|
|
signtool.exe sign /fd SHA256 /a /f cert.pfx /p password App.msix
|
|
# Install
|
|
Add-AppxPackage -Path App.msix
|
|
```
|
|
|
|
Requirements:
|
|
- `AllowAllTrustedApps=1` and `AllowDevelopmentWithoutDevLicense=1` in registry
|
|
- Manifest Publisher must exactly match cert Subject
|
|
- Bump version on each rebuild
|
|
- Remove stale `AppxSignature.p7x`, `AppxBlockMap.xml`, `AppxMetadata/` from staging
|
|
|
|
## Phase 7: Launch and verify
|
|
|
|
```powershell
|
|
# Launch via AppsFolder (not Start-Process directly)
|
|
Start-Process explorer.exe -ArgumentList 'shell:AppsFolder\PackageFamilyName!App'
|
|
# Wait 8-15 seconds for WinUI window
|
|
# Verify: PID path matches Rev package, MainWindowTitle set, RAM > 150MB
|
|
```
|
|
|
|
UI verification:
|
|
- UI Automation: `[System.Windows.Automation.AutomationElement]::FromHandle($hwnd)`
|
|
- Screenshot + pixel sampling for color/design changes
|
|
- Don't trust `base.Title` alone — custom title bar uses `AppTitleTextBlock.Text`
|
|
|
|
## Known limitations
|
|
|
|
- XAML markup (XBF v2.1) cannot be decompiled — original `resources.pri` is used
|
|
- ILSpy leaves `Unknown result type` comments in 61+ files (WinRT projection IL)
|
|
- `copy_all.ps1` pattern overwrites rebuilt exe/dll — always rebuild AFTER copying
|
|
- `Window.RequestedTheme` not available in WinUI 3 — set theme on child elements
|
|
- Process may take 10-15 seconds to create window handle after launch
|