7.2 KiB
Ghostwire architecture
Two ways to run the same code
python -m whatsapp_suite runs the editable source package. python whatsapp.py runs its generated portable distribution through the same CLI.
The builder stores the maintained modules, fixtures and selected assets in a compressed archive. The launcher verifies its payload, imports Python modules from memory, and extracts only the native helper needed for a live operation into a hash-verified cache beside the bundle. A C++ compiler is needed to change native code, not to run the portable file.
Live JavaScript execution
sequenceDiagram
participant CLI as Python CLI
participant DLL as Native helper
participant WV as Existing WhatsApp WebView
CLI->>CLI: Detect host and UI thread; verify helper
CLI->>DLL: Temporary Windows hook + shared request
DLL->>DLL: Discover and validate native layout
DLL->>WV: ExecuteScriptAsync
WV-->>DLL: JavaScript result
DLL-->>CLI: Shared result packet
CLI->>CLI: Release hook, mappings and handles
Python calls Windows APIs through ctypes. A WH_GETMESSAGE hook loads the helper on WhatsApp's UI thread. A thread message wakes it; a shared mapping carries a bounded request and result.
The helper scans the loaded WebView component for relocation-free code fingerprints and a matching vtable layout, then locates the existing object and validates its script-execution method. This avoids fixed module-relative function addresses. Compiler/object-field and interface ABI assumptions remain.
The hook is temporary. Normal exports and probes record cleanup of the hook, mapping, process handles and helper. Native failures are not evidence that a different layout is safe.
Read, search and send
| Operation | Data path | Boundary |
|---|---|---|
| ZIP export | App database getter → app row decoder → paginated records → ZIP | Local rows; no atomic snapshot, phone sync or media download |
| Old-message read | Timestamp scan → five oldest rows → app decoder | Bounded scan; not limited to loaded chat models |
| Contact export | Local contact table → selected identity/name/business fields | May contain separate PN/LID records |
| Desktop search | Existing app message search → bounded metadata | Search scope comes from the app |
| Saved-export search | Python JSON/JSONL parsing and normalization | Does not need the app |
| Self-message | Resolve own identity → guarded send → stored readback | One fixed test message; no arbitrary-recipient CLI |
Database text is decoded through WhatsApp's own JavaScript methods under the signed-in session. Failed row decodes remain explicit. Export publication refuses existing outputs and checks ZIP CRCs.
Listener and delivery
flowchart LR
M["Loaded message collection"] --> J["JS observer and decoded queue"]
J --> N["UI-thread native timer"]
N --> H["WinHTTP worker"]
H --> T["HTTPS target or loopback receiver"]
T --> A["HTTP 2xx"]
A --> Q["Remove acknowledged queue entries"]
R["Optional Windows minute task"] --> I["Restore after app restart"]
I --> J
The JavaScript producer observes message collection events, obtains stored rows through the app decoder, and queues bounded message events. It does not contain transport credentials. A UI-thread timer executes short queue scripts; a worker performs HTTP delivery outside that UI thread.
Direct HTTPS uses certificate validation and a token header. Loopback mode posts to a local receiver. Proxies and redirects are disabled. Native WinHTTP supplies the outbound transport; direct JavaScript localhost requests were blocked by WhatsApp's CSP during testing, and the implementation does not weaken CSP.
HTTP 2xx triggers queue acknowledgement. Failures leave records for retry. A consumer must deduplicate IDs; this is not exactly-once delivery. The built-in local receiver commits SQLite data before acknowledgement.
The installer exits after setup. The native relay retains a module reference so timer/worker callbacks remain valid. Stop cancels observation/timers and releases WebView references; an idle DLL remains loaded until app exit.
Restoration and configuration
WhatsApp process exit destroys the listener and native relay. Automatic restoration is a separate capability:
| Mode | Bootstrap | Lifetime |
|---|---|---|
Direct HTTPS with --auto-restore |
Per-user Windows task invokes webhook ensure every minute |
Short Python checks; no continuous local server |
Loopback receiver with --restore-config |
Receiver checks every five seconds | Receiver must remain running |
Optional watch |
Python restoration loop | Watcher remains running |
The task runs as the logged-in user with limited privileges. It stores paths to Python, the bundle and configuration; moving them breaks that registration. Direct restoration recovers a current-user DPAPI-protected token from the configuration. The bundle is portable, but that protected configuration is tied to the Windows user/machine.
Reinstallation reconciles qualifying loaded models since the saved start timestamp; it does not perform complete database catch-up. In-memory queues can be lost on exit, and messages in startup/polling gaps are not guaranteed to be delivered. See the webhook guide for schema and limits.
Source map
| Layer | Files |
|---|---|
| Command dispatch and tests | cli.py, runner.py, tests/ |
| Shared resources/cache | common.py |
| Windows orchestration | desktop.py, live.py, native_search.py |
| Data operations | history.py, zip_export.py, contacts_export.py, exports.py, self_message.py |
| Listener orchestration | webhook.py, assets/webhook_listener.js |
| Native implementations | native/math_probe.cpp, search_probe.cpp, webhook_probe.cpp, core_discovery.h |
| Portable packaging | build_whatsapp_bundle.py, generated whatsapp.py |
All Python filenames above are under whatsapp_suite/. See contributing for extension steps and hash updates.
Compatibility and security boundaries
The tested Desktop build is 2.2639.100.0. Other builds produce advisory metadata/warnings and are attempted, but dynamic address discovery does not imply compatibility with every future compiler/object layout. Changed layouts can fail or cause process instability.
The observed bridge uses documented Windows loading and WebView execution APIs. It does not demonstrate memory corruption, privilege escalation or broken encryption. The overall integration remains reverse-engineered process instrumentation: WhatsApp does not document these internal module calls as an external automation API. This is not a complete security audit.
Passwords/passkey private keys and media download are not implemented features. Core commands use no CDP or UI automation; optional research tools have separate transports. Hashes establish integrity, not publisher identity.
See validation for evidence, security for private-data handling, and Microsoft's Windows hook and WebView JavaScript documentation for the public APIs.