跪拜 Guibai
← Back to the summary

WeChat Mini Program Decompilation on Windows: The 8 Pitfalls That Break Every Tutorial

Complete WeChat Mini Program Decompilation Tutorial (Windows Beginner's Edition)

This article is based on a real, complete hands-on operation, including all steps, 8 pitfalls encountered, and their solutions. Environment: Windows 11 + PowerShell 5.1 + Node.js v22 + WeChat 4.x + WeChat DevTools 1.06


⚠️ Must-Read Before Use: Legal Boundaries

Only use in the following scenarios:

Prohibited:

The technical barrier for decompilation is not high, but the legal liability is real. This tutorial assumes you are operating under the first two legal scenarios.


Table of Contents

  1. Principle Overview
  2. Environment Setup
  3. Step 1: Locate the wxapkg Package
  4. Step 2: Determine Encryption Status
  5. Step 3: Decrypt and Unpack
  6. Step 4: Import into DevTools
  7. FAQ (8 Real Pitfalls)
  8. Methodology Summary
  9. Tool List

1. Principle Overview

1.1 How Mini Programs Exist on Your Computer

When you open a mini program in WeChat, WeChat downloads its code package to a local cache. The file suffix is .wxapkg. Decompilation is the process of restoring this package back into editable project source code.

Obtain .wxapkg → Decrypt → Unpack → Restore project structure → Import into DevTools for verification

1.2 Package Structure

File Meaning
__APP__.wxapkg Main Package — Main program code
_pages_xxx_.wxapkg Subpackage — Code split by page

Key Point: The main package and subpackages must be from the same version and all collected to restore a complete project.

1.3 Where Did the Source Code Go

After compilation, the source code is broken down into these files:

Compiled Product Restores To
app-service.js All .js logic code
page-frame.js / app-wxss.js All .wxml views + .wxss styles
app-config.json app.json and page .json configs

Among these, wxml is the hardest to restore — it is compiled into a JS generation function named $gwx, requiring the view tree to be reverse-engineered. This is also the biggest pitfall later on.


2. Environment Setup

2.1 What Needs to Be Installed

node -v          # Required, >= 16
git --version    # Required

2.2 Create Working Directory

New-Item -ItemType Directory -Force -Path "C:\work\decompile" | Out-Null
cd C:\work\decompile

The following text uses C:\work\decompile as the working directory; you can replace it with your own path.


3. Step 1: Locate the wxapkg Package

3.1 First, Let the Mini Program Be Cached

Open PC WeChat → Search for and open the target mini program → Click through several pages (ensure both main package and subpackages are loaded) → Close it.

If you don't open it, there's no cache, and you won't find anything later.

3.2 Find the Cache Directory

Paths differ for different WeChat versions:

WeChat Version Cache Path
WeChat 4.x (Personal) %APPDATA%\Tencent\xwechat\radium\users\<user hash>\applet\packages\<AppId>\<version>\
WeChat 3.x (Old Version) Documents\WeChat Files\Applet\<AppId>\
WeCom Documents\WXWork\<ID>\Applets\Applet\<AppId>\<version>\

The easiest way is a full disk search:

Get-ChildItem -Path "C:\" -Recurse -Filter "*.wxapkg" -ErrorAction SilentlyContinue |
    Select-Object FullName, Length, LastWriteTime |
    Sort-Object LastWriteTime -Descending

The search is slow; wait patiently for 1-3 minutes. You can also search only the WeChat directories:

Get-ChildItem -Path "$env:APPDATA\Tencent","$env:LOCALAPPDATA\Tencent" -Recurse -Filter "*.wxapkg" -ErrorAction SilentlyContinue |
    Select-Object FullName, Length, LastWriteTime |
    Sort-Object LastWriteTime -Descending

3.3 Lock Down Your Mini Program's AppId

The cache directory contains a bunch of AppIds (all the mini programs you've used). Use this script to sort by recent use:

# Replace <user hash> with your actual string
$root = "$env:APPDATA\Tencent\xwechat\radium\users\<user hash>\applet\packages"
Get-ChildItem $root -Directory | ForEach-Object {
  $files = Get-ChildItem $_.FullName -Recurse -Filter *.wxapkg -ErrorAction SilentlyContinue
  $latest = $files | Sort-Object LastWriteTime -Descending | Select-Object -First 1
  [PSCustomObject]@{
    AppId  = $_.Name
    PackageCount = $files.Count
    LastModified = $latest.LastWriteTime
    TotalSizeKB = [math]::Round(($files | Measure-Object Length -Sum).Sum / 1KB)
  }
} | Sort-Object LastModified -Descending | Format-Table -AutoSize

The one with the most recent modification time is the mini program you just opened. The AppId can also be found in the WeChat Official Accounts Platform backend.

3.4 Copy the Package to the Workspace

$src = "$env:APPDATA\Tencent\xwechat\radium\users\<user hash>\applet\packages\<Your AppId>"
Copy-Item -Path $src -Destination "C:\work\decompile\<Your AppId>" -Recurse -Force

Copy instead of operating directly on the original directory — avoids accidentally deleting WeChat's cache.

3.5 Confirm Package Integrity

Get-ChildItem "C:\work\decompile\<Your AppId>" -Recurse -Filter *.wxapkg |
  Select-Object @{n='VersionDir';e={$_.Directory.Name}},
                Name,
                @{n='KB';e={[math]::Round($_.Length/1KB)}},
                LastWriteTime |
  Sort-Object VersionDir, Name | Format-Table -AutoSize

Checklist:


4. Step 2: Determine Encryption Status

$pkg = "C:\work\decompile\<Your AppId>\<version>\__APP__.wxapkg"
$bytes = [System.IO.File]::ReadAllBytes($pkg)[0..15]
"First 16 bytes (Hex): " + (($bytes | ForEach-Object { $_.ToString('X2') }) -join ' ')
"First 16 bytes (ASCII): " + ([System.Text.Encoding]::ASCII.GetString($bytes) -replace '[^\x20-\x7E]','.')
File Header Meaning Handling Method
56 31 4D 4D 57 58(V1MMWX) PC WeChat encrypted Needs AppId to decrypt
First byte BE Unencrypted standard Can be unpacked directly

Why AppId is the source of the decryption key: PC WeChat uses the AppId to participate in deriving the key. This also means — you must know the AppId to decrypt, naturally limiting it to "mini programs you can identify."


5. Step 3: Decrypt and Unpack

5.1 Tool Selection

Tool Pros Cons
unveilr Best compatibility with various wcc compiler versions, high wxml restoration success rate npm package has been taken down, needs building from fork source
KillWxapkg Ready-to-use exe, high degree of automation Fails to restore wxml for older wcc versions (see Pitfall #1)

Recommendation: Use unveilr directly. If you want to quickly verify if decryption is possible, you can run KillWxapkg first.


5.2 Option A: KillWxapkg (Quick Start)

Download: https://github.com/Ackites/KillWxapkg/releases → Download the Windows amd64 version → Rename to KillWxapkg.exe and place in the working directory.

⚠️ Third-party open-source binary; it's recommended to scan with antivirus first.

cd C:\work\decompile
.\KillWxapkg.exe -h    # Check parameters first

.\KillWxapkg.exe -id <Your AppId> `
                 -in "C:\work\decompile\<Your AppId>\<version>" `
                 -out "C:\work\decompile\output" `
                 -restore -pretty -noClean
Parameter Effect
-id AppId (source of decryption key)
-in Input directory (the entire version directory, main package and subpackages together)
-out Output directory
-restore Restore project directory structure
-pretty Beautify code
-noClean Keep intermediate files (page-frame.js/app-wxss.js) — key for troubleshooting, strongly recommended

5.3 Option B: unveilr (Recommended, Correct wxml Restoration)

Step 1: Clone Source Code

The original repository r3x5ur/unveilr is invalid, and the npm package has also been taken down (npm i -g unveilr reports ENOVERSIONS). You need to use a fork:

cd C:\work\decompile
git clone https://github.com/hzzheyang/unveilr-v2.0.0.git unveilr

Backup forks:

Step 2: Install Dependencies

cd C:\work\decompile\unveilr
npm install --legacy-peer-deps --registry=https://registry.npmmirror.com

--legacy-peer-deps is required — the project's rollup version has a peer conflict with rollup-plugin-terser (see Pitfall #3).

Step 3: Configure Parameters (Important!)

When running source code with ts-node, unveilr enters development mode and directly ignores command-line arguments (see Pitfall #4). So parameters must be written into the configuration file.

Edit src\utils\getConfigurator.ts, change the wx: { ... } section to:

    wx: {
      appid: 'Your AppId',
      format: false,
      clearDecompile: true,
      clearSave: true,
      parse: true,
      depth: 1,
      output: 'C:/work/decompile/output',
      packages: ['C:/work/decompile/Your AppId/version'],
    },

format must be set to false! Setting it to true will format the code, breaking strings in wxml expressions across multiple lines and causing compilation failures (see Pitfall #2).

Use forward slashes / for paths to avoid escaping issues.

Step 4: Run

cd C:\work\decompile\unveilr
npm run run

Do not add any command-line arguments — parameters are hardcoded in the code; adding them will be misinterpreted as paths.

Step 5: Acceptance Check (The Most Important Step!)

Don't just look at the file count; you must check the content:

$all = Get-ChildItem "C:\work\decompile\output" -Recurse -Filter *.wxml -File
"Total: " + $all.Count
"Empty: " + ($all | Where-Object Length -eq 0).Count
"Avg KB: " + [math]::Round(($all | Measure-Object Length -Average).Average / 1KB, 1)
# Spot-check real content
Get-Content "C:\work\decompile\output\pages\home\index.wxml" -TotalCount 10 -Encoding UTF8
Phenomenon Judgment
0 empty files, avg 2-5 KB, content is <view class="..."> tag tree Success
Many 0-byte files, or content is <text>page path</text> Failed (placeholders, see Pitfall #1)

6. Step 4: Import into WeChat DevTools

6.1 Necessary Fixes Before Importing

The decompilation product is a compiled artifact. Some configurations are in runtime format and need to be converted back to source format. Use this script to fix them all at once:

$root = "C:\work\decompile\output"
$utf8 = New-Object System.Text.UTF8Encoding $false

# --- 1. app.json three fixes ---
$appPath = Join-Path $root "app.json"
$app = Get-Content $appPath -Raw -Encoding UTF8 | ConvertFrom-Json

# 1a. componentFramework from object to string
if ($app.componentFramework -and $app.componentFramework -isnot [string]) {
    $app.componentFramework = "exparser"
}

# 1b. Remove runtime field subpackage from plugins
if ($app.plugins) {
    foreach ($p in $app.plugins.PSObject.Properties) {
        $p.Value.PSObject.Properties.Remove('subpackage')
    }
}

# 1c. Remove plugin pages from pages array
$app.pages = @($app.pages | Where-Object { $_ -notlike '__plugin__*' })

[System.IO.File]::WriteAllText($appPath, ($app | ConvertTo-Json -Depth 100), $utf8)
"app.json fixed"

# --- 2. project.config.json: disable all secondary compilation ---
$pcPath = Join-Path $root "project.config.json"
if (Test-Path $pcPath) {
    $pc = Get-Content $pcPath -Raw -Encoding UTF8 | ConvertFrom-Json
    $pc.setting.es6        = $false
    $pc.setting.postcss    = $false
    $pc.setting.minified   = $false
    $pc.setting.enhance    = $false
    $pc.setting.minifyWXML = $false
    # Crucial! Prevent unused files from being stripped
    $pc.setting | Add-Member -NotePropertyName "ignoreUploadUnusedFiles" -NotePropertyValue $false -Force
    $pc.setting | Add-Member -NotePropertyName "ignoreDevUnusedFiles" -NotePropertyValue $false -Force
    [System.IO.File]::WriteAllText($pcPath, ($pc | ConvertTo-Json -Depth 100), $utf8)
    "project.config.json fixed"
}

# --- 3. Move away plugin residual directories ---
foreach ($dir in @("__plugin__", "wxlive-components")) {
    if (Test-Path "$root\$dir") {
        Move-Item "$root\$dir" "C:\work\decompile\${dir}_backup" -Force
        "$dir moved to backup"
    }
}

wxlive-components is the component directory for the live-streaming plugin. If your mini program doesn't use the live-streaming plugin, it might not exist; the script will automatically skip it.

6.2 Import

  1. Open WeChat DevToolsImport Project
  2. Directory: C:\work\decompile\output
  3. AppID: Enter your AppId
  4. Backend Service: Select 'Do not use cloud services'
  5. After importing, go to Details → Local Settings, check:
    • ✅ Do not verify valid domain names, web-view, TLS version, and HTTPS certificates
    • ✅ Disable ES6 to ES5 conversion
    • ✅ Disable style auto-completion on code upload
    • ✅ Disable automatic code compression on upload

After modifying project.config.json, you must reopen the project for changes to take effect.


7. FAQ (8 Real Pitfalls)

The following 8 pitfalls all come from real hands-on experience, listed in the order encountered.


Pitfall #1: wxml Files Are All Empty or Placeholders ⭐ Most Critical

Symptom:

wxml total: 347   empty: 210

Opening a non-empty wxml, the content is:

<!--pages/test/settings.wxml--><text>pages/test/settings.wxml</text>

The log is full of Saved file: xxx.wxml, looking perfectly normal.

Cause:

The mini program's wxml is compiled into a JS generation function named $gwx, stored in page-frame.js (subpackages) or app-wxss.js (main package).

Some compiler versions add an obfuscation suffix to this function, turning it into variants like $gwx_XC_29, $gwx_XC_31:

// Real form inside app-wxss.js
var gf = $gwx_XC_29('./components/common/card1.wxml');

KillWxapkg only matches the standard $gwx. When it encounters variant names, it can't find them → no error is reported, but it falls back to writing placeholders. This is the most insidious part: failure is disguised as success.

How to Confirm:

Select-String -Path "C:\work\decompile\output\app-wxss.js" -Pattern 'gwx_XC_\d+' | Measure-Object

If hundreds or thousands of matches are found, it means the variant format is being used.

Solution:

Switch to unveilr. It has much better compatibility with various wcc versions and $gwx variants. A real comparison using the same set of packages:

Tool wxml Result
KillWxapkg v2.4.1 210 empty + 137 placeholders = 0 real
unveilr v2.0.0 366 all real, avg 3.5 KB

Lesson:

Tool runs successfully ≠ Restoration succeeded. Always open files to check content, don't just look at file counts and logs.


Pitfall #2: wxml Compilation Error unexpected \ or String Spans Multiple Lines

Symptom:

[WXML file compilation error] ./components/actionTips/infoTips.wxml
Bad value with message: unexpected `\` at pos103.

Looking at the error location:

>{{type==1?self?'已通过认证 \n 会被推荐':'该用户已通过
      \n 认证,会被优先推荐':...}}

Single-quoted string spans multiple lines.

Cause:

unveilr's format: true formats the code, wrapping long expressions at line width — resulting in string literals also being broken. JS/WXML strings cannot span lines.

Solution:

Modify getConfigurator.ts, set format to false, and re-unpack:

format: false,

Do not attempt to patch the broken files with text replacement — in practice, this not only fails to address the root cause but also introduces encoding issues (see Pitfall #7).

Lesson:

Formatting is for humans to read, not for machines to run. For decompilation, prioritize correctness first, readability second.

Want readable code? Get it running first, then run prettier on .js files separately; don't touch .wxml.


Pitfall #3: npm install Reports ERESOLVE Dependency Conflict

Symptom:

npm error code ERESOLVE
npm error Found: [email protected]
npm error peer rollup@"^2.0.0" from [email protected]

Cause:

Build tool versions in the old project don't match. These are only build-time dependencies and do not affect the tool's operation.

Solution:

npm install --legacy-peer-deps --registry=https://registry.npmmirror.com

Pitfall #4: unveilr's --help Errors Out, Command-Line Arguments Ineffective

Symptom:

npm run run -- --help
# ExtractorError: File C:\...\unveilr\files cannot be extracted!

Inexplicably tries to extract a path called files.

Cause:

Read src/utils/isDev.ts:

export function isDevelopment() {
  return PathController.make(process.argv[1]).suffixWithout === 'ts'
}

As long as the entry file suffix is .ts, it's determined to be development mode. In development mode, getConfigurator.ts directly returns hardcoded configuration (where packages: ['files']), completely skipping command-line parsing.

Running source code with ts-node, the entry is exactly src/index.ts → all command-line arguments are voided.

Solution:

Two paths:

  1. Modify config (Recommended): Write parameters into the dev branch of getConfigurator.ts, run directly without any command-line arguments
  2. Run after building: npm run build generates dist/index.js, then use node dist/index.js wx -i <appid> -o <output> <package dir>

Lesson:

Reading tool source code is faster than blindly trying parameters. Three minutes reading getConfigurator.ts can pinpoint the issue; blindly trying parameters might take all day.


Pitfall #5: app.json: componentFramework field must be string

Symptom:

[app.json file content error] app.json: componentFramework field must be exparser,glass-easel

The actual value is an object:

"componentFramework": { "allUsed": ["exparser"], "default": "exparser" }

Cause:

Mini programs have two sets of json formats:

Format Usage
Source app.json "componentFramework": "exparser" Developer writes
Compiled product app-config.json { "allUsed": [...], "default": "..." } Runtime use

Decompilation infers source code from the compiled product; this field wasn't format-converted. A similar issue exists with plugins.subpackage.

Solution:

"componentFramework": "exparser",

In plugins, delete the line "subpackage": "__APP__":

"plugins": {
  "livePlayerPlugin": {
    "version": "1.3.5",
    "provider": "wx2b03c6e691cd7370"
  }
}

Pitfall #6: Plugin Component Not Found / __plugin__ Error

Symptom:

["usingComponents"]["page-live-player"]: Component not found at path .../wxlive-components/page-live-player/

Looking inside, that directory only has .json, no .wxml/.js/.wxss.

Cause:

Third-party plugin code (like WeChat's official live-streaming plugin wx2b03c6e691cd7370) is not cached locally in plaintext — WeChat delivers it from the server on demand. You can only decompile the configuration skeleton.

Existence Form Decompilable?
Your business code Plaintext in wxapkg
Third-party plugin Server delivers on demand

Plugins shouldn't exist as source code in the project anyway — the plugins field in app.json is a dependency declaration, similar to writing dependency names in package.json without stuffing node_modules into the repository.

Solution:

  1. Confirm app.json has the plugins declaration (usually already brought out by decompilation)
  2. Delete all pages starting with __plugin__/... from the pages array
  3. Move away the __plugin__ and wxlive-components directories

How to determine if a directory is "dead code":

Select-String -Path "C:\work\decompile\output\**\*.json" -Pattern "wxlive-components" | Select-Object -First 5

No output = nobody uses it = safe to move away.

This method is much more efficient than blindly fixing syntax. When a file fails to compile, first ask "does anyone even use it?".


Pitfall #7: PowerShell Reads/Writes Chinese Files as Garbled Text ⭐ High Frequency

Symptom 1 — A seemingly normal json reports a format error:

ConvertFrom-Json : Invalid object passed in
"desc": "浣犵殑浣嶇疆淇℃伅灏嗙敤浜庡皬绋嬪簭...绀?

Symptom 2 — After modifying a file with a script, compilation reports garbled character ? (U+FFFD).

Cause:

Windows PowerShell 5.1's Get-Content defaults to decoding with the system ANSI (GBK) code page, while decompilation products are UTF-8. Decoding UTF-8 Chinese as GBK produces "half characters", even swallowing the following quote → json looks broken.

Writing has the same issue: Set-Content -Encoding UTF8 writes UTF-8 with BOM.

Solution:

Reading must explicitly specify encoding:

Get-Content "app.json" -Raw -Encoding UTF8 | ConvertFrom-Json

Writing use .NET methods (no BOM, safest):

$utf8 = New-Object System.Text.UTF8Encoding $false
[System.IO.File]::WriteAllText($path, $content, $utf8)

Reading files also recommends .NET methods:

$content = [System.IO.File]::ReadAllText($path)   # Defaults to UTF-8

Memorize this rule: PowerShell 5.1 handling decompilation products: read with -Encoding UTF8, write with .NET methods.


Pitfall #8: module 'npm/xxx' is not defined ⭐ Most Subtle

Symptom:

Error: module 'npm/@tarojs/async-await/index.js' is not defined,
require args is './npm/@tarojs/async-await/index.js'
Page "pages/home/index" has not been registered yet.

The file clearly exists, and the content is valid JS:

Test-Path "C:\work\decompile\output\npm\@tarojs\async-await\index.js"   # True

Cause:

WeChat DevTools has a default setting ignoreUploadUnusedFiles (default true), which performs dependency analysis and strips "unreferenced" files.

Decompiled JS is minified:

!function(e){...}(require)

Static analysis cannot recognize this dynamic require, thus determining "nobody uses this file" → stripped during compilation → not defined at runtime.

app.js fails on the first line's require, so all subsequent page registrations never execute, leading to the accompanying Page has not been registered yet error.

Solution:

Add two fields in project.config.json's setting:

"ignoreUploadUnusedFiles": false,
"ignoreDevUnusedFiles": false

After modifying, reopen the project.

Lesson:

This type of pitfall — where "the tool's well-intentioned optimization destroys the restored product" — takes the most time because the file is right there on disk, the content is fine, everything looks correct.


Appendix: Other Minor Issues You Might Encounter

Error Cause Solution
WXS Compile Error Unexpected token } WXS syntax is stricter than JS, no trailing commas etc. Remove comma in ,}; or confirm if the component is even used, just move it away
npm i -g unveilr reports ENOVERSIONS Original npm package has been taken down Clone source from GitHub fork and build
--help parameter ineffective npm run swallows params + dev mode ignores params See Pitfall #4
Subpackage decompression incomplete Main package and subpackage versions inconsistent Ensure all packages from the same version directory are collected
Cannot find any wxapkg Mini program hasn't been opened in PC WeChat Open it first and browse several pages
__route__ is not defined app.js failure causes pages not registered Usually a side effect of Pitfall #8, fixing #8 resolves it

8. Methodology Summary

Complete Workflow

① Locate Cache   WeChat 4.x: %APPDATA%\Tencent\xwechat\radium\users\<hash>\applet\packages\<AppId>\<version>\
                      ↓
② Check Encryption   Header V1MMWX = Encrypted (AppId is key source) / 0xBE = Unencrypted
                      ↓
③ Gather a Complete Set   __APP__ + all _pages_* in the same version directory must be complete
                      ↓
④ Decrypt & Unpack   unveilr (format: false) / KillWxapkg (-noClean)
                      ↓
⑤ Verify Content   ★ Open files to check content, don't just look at file counts ★
                      ↓
⑥ Fix Config   Runtime format → Source format, disable all secondary compilation
                      ↓
⑦ Import & Verify   WeChat DevTools can compile and run = True success

Three Core Lessons

1. Tool Runs Successfully ≠ Restoration Succeeded

Logs full of Saved file, file counts match, but content might be all placeholders. The tool's fallback logic disguises failure as success. The only reliable verification method is to open files and check the content.

2. Disable All "Smart" Features

What you have is a compiled artifact, not source code. Any secondary processing is destructive:

Feature Consequence
format: true (decompiler) Breaks wxml strings
es6: true (DevTools) Re-runs babel, scrambles module IDs
minified: true Secondary compression, may break structure
ignoreUploadUnusedFiles: true Strips files static analysis can't recognize

Unified Principle: No transpiling, no minifying, no beautifying, no stripping.

3. Reading Source Code Is Faster Than Trying Parameters

When --help fails, directly read getConfigurator.ts and isDev.ts; three minutes to pinpoint "development mode ignores command-line arguments."

Similarly, when a file fails to compile, grep first to see if anything references it — if nobody uses it, just move it away, much faster than fixing syntax.

Preserve Intermediate Artifacts

When unpacking, be sure to add -noClean (KillWxapkg) or keep page-frame.js / app-wxss.js. These are the raw materials for wxml. If problems arise, having them allows you to determine whether it's "parser doesn't recognize variant names" or another reason. Delete them and you have to start over.


9. Tool List

Tool Address Purpose
unveilr Original repo https://github.com/r3x5ur/unveilr (invalid)
fork: https://github.com/hzzheyang/unveilr-v2.0.0
Decrypt & unpack, highest wxml restoration success rate
KillWxapkg https://github.com/Ackites/KillWxapkg Ready-to-use, high automation
wxapkg GUI https://github.com/wux1an/wxapkg GUI, suitable for quick attempts
wxappUnpacker https://github.com/Ryan-Miao/wxappUnpacker Classic Node.js script, good for learning principles
WeChat DevTools https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html Verify restoration results

Appendix: Complete Command Quick Reference

# ===== 1. Find packages =====
Get-ChildItem -Path "C:\" -Recurse -Filter "*.wxapkg" -ErrorAction SilentlyContinue |
    Select-Object FullName, Length, LastWriteTime | Sort-Object LastWriteTime -Descending

# ===== 2. Check encryption =====
$pkg = "path\__APP__.wxapkg"
$bytes = [System.IO.File]::ReadAllBytes($pkg)[0..15]
"HEX: " + (($bytes | ForEach-Object { $_.ToString('X2') }) -join ' ')

# ===== 3. Copy to workspace =====
Copy-Item -Path "cache path\<AppId>" -Destination "C:\work\decompile\<AppId>" -Recurse -Force

# ===== 4. Install unveilr =====
git clone https://github.com/hzzheyang/unveilr-v2.0.0.git unveilr
cd unveilr
npm install --legacy-peer-deps --registry=https://registry.npmmirror.com
# Edit src\utils\getConfigurator.ts to fill in parameters (format: false!)
npm run run

# ===== 5. Verify wxml =====
$all = Get-ChildItem "C:\work\decompile\output" -Recurse -Filter *.wxml -File
"Total: " + $all.Count + "  Empty: " + ($all | Where-Object Length -eq 0).Count
Get-Content "C:\work\decompile\output\app.json" -Raw -Encoding UTF8 | ConvertFrom-Json | Out-Null

# ===== 6. Fix config (see complete script in 6.1) =====

# ===== 7. Import into DevTools, disable all compilation optimizations =====

Conclusion

There is no myth of "one command runs it all" in decompilation. In this hands-on operation, from the first unpacking to finally getting it running, a total of 8 pitfalls were encountered — tool versions, compiler variants, dependency conflicts, development mode traps, encoding issues, configuration formats, plugin residuals, static analysis stripping.

The troubleshooting method for each pitfall is more valuable than the pitfall itself:

Learn these, and next time you encounter new tools, new versions, new errors, you can walk through it yourself.


This document is based on real hands-on operations, intended only for learning research and source code retrieval of self-owned projects. Please comply with laws and regulations.