The article analyzes VVS stealer, a Python-based malware designed to exfiltrate sensitive information from Discord accounts and web browsers. This stealer utilizes Pyarmor for code obfuscation and was reportedly available for sale on Telegram as of April 2025.
Malware Overview
VVS stealer targets Discord users by exfiltrating credentials and tokens. Its advertised capabilities include:
- Stealing Discord data (tokens and account information).
- Intercepting active Discord sessions via injection.
- Extracting web browser data (cookies, passwords, browsing history, and autofill details).
The stealer achieves persistence by installing itself on system startup and operates by displaying fake error messages and capturing screenshots.
Technical Analysis: Obfuscation and Deobfuscation
VVS stealer employs Pyarmor for obfuscation, a tool that hinders static analysis and signature-based detection of Python scripts. The analysis involved deobfuscating samples to understand their operation.
PyInstaller Binary Extraction
The analyzed sample was distributed as a PyInstaller package. The pyi-archive_viewer utility was used to extract files, including the Python bytecode file named vvs, the Pyarmor runtime DLL (pyarmor_runtime.pyd), and associated __init__.py file (indicating Pyarmor version 9.1.4 Pro, license 007444, and timestamp 2025-04-27). A Python 3.11 DLL (python311.dll) was also identified.
Python bytecode within the PyInstaller package was in raw form, requiring the restoration of a Python 3.11.5 magic number header for successful decompilation.
Decompilation to Python Source Code
The vvs Python bytecode file was decompiled to Python source code using pycdc, a C++-based Python bytecode decompiler supporting Python 3.11. This process enabled the recovery of the original Python source code.
Pyarmor Obfuscation Unraveling
The payload included a Pyarmor header, which details protection parameters. Cryptography throughout the stealer uses AES-128-CTR. The header contains a file signature, Python version, protection type (BCC mode indicated by 09), ELF payload start/end markers, and AES-128-CTR nonce components.
BCC Mode
Pyarmor's BCC (ByteCode-to-Compilation) mode converts Python functions and methods into equivalent C functions, which are then compiled into machine instructions and called by obfuscated scripts. These C functions are stored in a separate ELF file. The mapping of Python constants to BCC functions, such as __pyarmor_bcc_58580__ to bcc_180, was identified, allowing for the partial recovery of original code from the ELF file's BCC function bodies.
Marshaled Bytecode Format
Pyarmor 9 marshaled bytecode differs from standard Python 3.11 bytecode by having the 0x20000000 bit set in the co_flags field and an extra data field. Disabling the deopt_code() function was necessary for bytecode decryption.
Code Object Structure and Encryption
Pyarmor code objects contain specific artifacts, including LOAD_CONST __pyarmor_enter_*__ and LOAD_CONST __pyarmor_exit_*__ instructions that wrap the encrypted bytecode. The bytecode sequence between these markers is encrypted with AES-128-CTR. The AES key (273b1b1373cf25e054a61e2cb8a947b8) is extracted from the Pyarmor runtime DLL, and a specific AES nonce XOR key (2db99d18a0763ed70bbd6b3c) is applied to generate the decryption nonce.
String Encryption
String constants exceeding eight characters are also AES-128-CTR encrypted (referred to as "mixed" in Pyarmor terminology). The same AES key (273b1b1373cf25e054a61e2cb8a947b8) is used, but a different AES nonce (692e767673e95c45a1e6876d) is computed from the Pyarmor runtime DLL. A 0x81 prefix indicates an encrypted string, while 0x01 indicates an unencrypted string.
Malware Capabilities
The deobfuscated code revealed the stealer's functionalities. The malware sample is configured to expire after 2026-10-31 23:59:59, terminating itself if executed past this date. All HTTP requests utilize the User-Agent string "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36".
Discord Data Exfiltration
The malware searches for encrypted Discord tokens, identified by the prefix dQw4w9WgXcQ:, within .ldb or .log files in LevelDB directories. It decrypts the encrypted_key from the Local State file using DPAPI. This decrypted key then serves as the AES key to decrypt Discord tokens using the AES-GCM algorithm.
Decrypted tokens are used to query Discord API endpoints for user information, including:
- Nitro subscription status
- Payment methods
- User ID, Username, Email, Phone number
- Friends, Guilds
- Multifactor authentication (MFA) status
- Locale, Verification status, Avatar image
- IP address (via
ipifyservice) - Computer name
This collected information is exfiltrated in JSON format via HTTP POST requests to predefined webhook endpoints, which may include a %WEBHOOK% environment variable or hard-coded URLs.
Discord Injection
The malware component, referred to as "Inj," initiates by terminating running Discord processes. It downloads a JavaScript (JS) payload, injection-obf.js, and places it into the Discord application directory, replacing the webhook endpoint URL and discord_desktop_core. This JS file is obfuscated using the JavaScript Obfuscator Tool.
The injected JS code establishes persistence within the Electron-based Discord application by modifying Atom Shell Archive Format (ASAR) archives. It monitors network traffic via the Chrome DevTools Protocol (CDP) and includes utility functions and event hooks. These event hooks activate when a user views backup codes, changes passwords, or adds a payment method, allowing for the collection of Discord user account and billing information. After injection, the malware restarts the Discord application process using Update.exe with the --processStart switch.
Web Browser Data Exfiltration
The stealer targets various web browser applications, including Chrome, Edge, Brave, Firefox, Opera, and Vivaldi, among others. It extracts autofill data, cookies, browsing history, and passwords.
The extracted data is compressed into a ZIP archive file named <USERNAME>_vault.zip and exfiltrated via HTTP POST requests to the same predefined webhook endpoints used for Discord data.
Startup Persistence
To maintain persistence on a compromised system, the malware copies itself to the %APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup folder. This mechanism ensures continued operation even if Discord application instances are reinstalled.
Fake Error Message Display
The malware uses the Win32 API function MessageBoxW from User32.dll to display a modal message box. This message box presents a fake fatal error, suggesting a computer restart is required.
Conclusion
VVS stealer's deployment demonstrates the use of legitimate tools such as Pyarmor for malware obfuscation. The analysis of its technical aspects illustrates its methods for credential theft and account information exfiltration across platforms like Discord and various web browsers.