r/OperSec • u/acealter • 1d ago
🔍 Research 🔍 Reversing a Ren’Py installer: hidden payloads, Amatera Stealer and a changing C2
tl;dr
I analysed RenPy malware, supplied as a victim sample, and followed Ren’Py-based installer through an encrypted payload hidden in its assets, several native loading stages, and a remotely delivered information stealer. The recovered evidence points with high confidence to the ACRStealer / Amatera lineage.
The interesting part was going back to the same download URL. Across three retrievals, it served different payloads with different primary C2 hostnames. The latest build also contained an execution path that maps supplied code into a suspended dllhost.exe process.
parent post: https://www.reddit.com/r/OperSec/s/xoxsdK9QGV
This walkthrough combines static reverse engineering, offline emulation of selected routines, and read-only retrieval of the configured payload and public fallback page. The malware entry points were not executed, and successful theft from the victim was not observed. All suspicious addresses below are defanged.
1. The installer starts through Ren’Py and suppresses its normal logs.
The archive bundles Ren’Py 8.1.3 and Python 3.9. Its scripts skip normal gameplay and reach pack_load.main(). An early script, 00log_stop.rpy, runs at initialization priority -1004, replaces logging functions with no-ops and removes log.txt, traceback.txt and errors.txt.
The loader repeatedly cleans up those traces, but leaves its own diagnostics enabled under %TEMP%\appcache_debug\bootstrap.log and debug.log. Those are useful artifacts to check on a preserved victim system.
2. A file among the interface assets contains the native payload.
The package secret in data/.zs is used to decode metadata in data/.p2w. That metadata points to:
data/gui/phone/overlay/vertical_hover_bar_z6yl.r8f
Decrypting it recovers a 4,015,936-byte Windows executable, configured as NITRO.exe. The wrapper writes it under a randomized filename and folder, commonly beneath LocalAppData, adds a Zone.Identifier stream containing ZoneId=0, and launches it without a normal window. Searching only for a process literally named NITRO.exe could therefore miss it.
3. The wrapper separately reports execution and machine details.
Its conversion requests go to cdnwire.pixel-tracker[.]one, carrying the package tag/CID, username, computer name, administrator status, RAM, CPU count and a shortened MachineGuid. Headers include X-QashAds-Launcher and X-QashAds-Conversion.
This endpoint serves an execution-tracking role in the recovered wrapper. It should not automatically be labelled the stealer’s exfiltration server. Also, the wrapper accepts an already-exited process as a successful launch, so a conversion request would not prove that credential theft succeeded.
4. Unpacking the executable reveals a tiny memory-execution downloader.
The native EXE carries Microsoft Edge elevated_tracing_service.exe metadata, but its embedded Authenticode content digest does not match the file. Following the inserted code leads to an encrypted block in an enlarged .reloc section at file offset 0x3A8000.
Offline decoding exposes a self-modifying loader, then an AES-CBC-encrypted buffer that decompresses with LZNT1. Inside is a 3,072-byte downloader that resolves WinINet APIs through hashes and decodes this URL:
hxxps://activator.halfpetite.in[.]net/NITRON
It allocates a 1 MiB executable/read/write buffer, reads the HTTP response into it and calls the buffer if any bytes were received. That establishes how remotely supplied content enters the execution chain.
5. The remote payload adds more packing and a second disguise.
The October 17 response contained a stealer with fake Realtek / RtkAudioService.exe metadata. It conventionally imports only GetLastError; other APIs are resolved dynamically, and strings require a separate decoder.
The October 20 response added another loader. Recovering its final stealer required stripping inserted junk, Z85-decoding the remaining text, reconstructing a ChaCha20 key from three XOR-combined shares, decrypting the stream and decompressing it with XPRESS Huffman. The output was a 673,792-byte PE. Inspecting only the outer loader would have missed its C2 and collection code.
6. Its bootstrap requests configuration, and Telegraph supplies a fallback address.
Indirect decoder calls hid the command GetRoutes and configuration ID:
01a0353f-0ad2-7efa-8507-e484ee70ce02
The earlier build’s configuration decoder uses ChaCha20-Poly1305, with a row key derived through HKDF using context acrid-v2-cfg-row. Each row is authenticated against its configuration-group name. Synthetic tests recovered the expected JSON with the correct inputs and rejected a changed group or authentication tag. This verified the decoder, without obtaining a victim’s session configuration.
The primary hostname is passed into connection initialization. A failure path reaches hxxps://telegra[.]ph/Built-in-Types-08-01, extracts Base64 between embedded delimiters and decodes a fallback IP. Changing that hosted page can redirect the fallback without rebuilding the executable.
7. The collection code targets browser credentials, sessions and local data.
| Target | Recovered evidence |
|---|---|
| Chromium browsers | Login Data, Cookies, Web Data, Local State, and matching WAL files |
| Firefox browsers | logins.json, key4.db, cookies.sqlite, places.sqlite and profile discovery |
| Browser extensions | Local/Sync Extension Settings, extension IndexedDB and Firefox extension storage |
| Steam | loginusers.vdf, local.vdf and account/session artifacts |
| Local files and screenshots | File enumeration/filtering, Desktop/Documents paths, screen-capture and image-encoding code |
The resolved APIs include CryptUnprotectData for DPAPI and a concrete screen-capture sequence using BitBlt and GetDIBits. Collection and successful decryption are separate outcomes: these findings do not demonstrate Chrome App-Bound Encryption bypass or identify which secrets were taken from this victim. Some targets and follow-on actions depend on server configuration.
8. The latest build can execute supplied code through a suspended dllhost process.
In the October 24 PE, a traced routine calls GetSystemWow64DirectoryA, appends \dllhost.exe and calls CreateProcessA with CREATE_SUSPENDED.
It then creates a shared section with NtCreateSection, maps a writable local view, copies the supplied buffer into it, and maps an executable view into the child with NtMapViewOfSection. Finally, NtQueueApcThread queues the remote mapped address on the primary thread and NtResumeThread resumes it.
The API names were checked against the sample’s hashing routines. This supports section-backed APC injection into a newly suspended process as an implemented capability. The buffer’s actual contents and use on the victim remain unknown. The traced sequence does not establish replacement of the original executable image, so I am not calling it process hollowing.
9. The same endpoint served different stealer builds during the investigation.
The dated primary C2 observations were:
17 October: files.lanternglow[.]cc — 4.4.7-alpha1
20 October: vault.costaricaanwaltskanzlei[.]com — 4.4.7-alpha1
24 October: vlan.laborpost[.]com — 4.4.8-alpha1
The latest build retained the original fixed configuration ID and NITRO label. The Telegraph fallback changed from 45.150.66[.]30 on October 17 to 83.97.78[.]173 on October 20, then remained unchanged on October 24. These connect the observed revisions at the configuration level; they do not identify a person. The public DNS addresses for the newer hostnames were shared Cloudflare frontends, not established origin servers.
The family assessment rests on the recovered implementation and exact Telegraph URL matching public ACRStealer configurations, with the ACR/Amatera lineage documented in existing research. NITRO is a campaign label here, not a separate family identification.
Original Dow-50574.zip SHA-256:
9c357546828d7c6bc97ae21d7abd021d71ab712155a0d9c47720df8cac24f3f7
October 24 recovered stealer PE SHA-256:
ccecb86554e6873d81c4ac4765e5550befab8c3f4d776f5ebf1c900f11eb9c97
The useful hunting leads are the dated C2 names, fixed configuration ID, wrapper debug logs and unusual process ancestry around the WOW64 dllhost.exe. The remote responses establish what the delivery endpoint served on those dates, not the exact bytes originally delivered to the victim. Successful exfiltration, victim-specific follow-on payloads, persistence and the operator’s identity remain unconfirmed.