diff --git a/src/generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/.pyc.md b/src/generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/.pyc.md index 6b118473f93..44256832700 100644 --- a/src/generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/.pyc.md +++ b/src/generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/.pyc.md @@ -115,7 +115,10 @@ test@test:python python_exe_unpack.py -p unpacked/malware_3.exe/archive If you weren't able to extract the python "original" code following the previous steps, then you can try to **extract** the **assembly** (but i**t isn't very descriptive**, so **try** to extract **again** the original code).In [here](https://bits.theorem.co/protecting-a-python-codebase/) I found a very simple code to **disassemble** the _.pyc_ binary (good luck understanding the code flow). If the _.pyc_ is from python2, use python2: -```bash +
+Disassemble a .pyc + +```python >>> import dis >>> import marshal >>> import struct @@ -158,6 +161,19 @@ True 17 RETURN_VALUE ``` +
+ +## PyInstaller raw marshal & Pyarmor v9 static unpack workflow + +- **Extract embedded marshal blobs**: `pyi-archive_viewer sample.exe` and export raw objects (e.g., a file named `vvs`). PyInstaller stores bare marshal streams that start with `0xe3` (TYPE_CODE with FLAG_REF) instead of full `.pyc` files. Prepend the correct **16-byte `.pyc` header** (magic for the embedded interpreter version + zeroed timestamp/size) so decompilers accept it. For Python 3.11.5 you can grab the magic via `imp.get_magic().hex()` and patch it with `dd`/`printf` before the marshal payload. +- **Decompile with version-aware tools**: `pycdc -c -v 3.11.5 vvs.pyc > vvs.py` or PyLingual. If only partial code is needed, you can walk the AST (e.g., `ast.NodeVisitor`) to pull specific arguments/constants. +- **Parse the Pyarmor v9 header** to recover crypto parameters: signature `PY` at `0x00`, Python major/minor at `0x09/0x0a`, protection type `0x09` when **BCC** is enabled (`0x08` otherwise), ELF start/end offsets at `0x1c/0x38`, and the 12-byte AES-CTR nonce split across `0x24..0x27` and `0x2c..0x33`. The same pattern repeats after the embedded ELF. +- **Account for Pyarmor-modified code objects**: `co_flags` has bit `0x20000000` set and an extra length-prefixed field. Disable CPython `deopt_code()` during parsing to avoid decryption failures. +- **Identify encrypted code regions**: bytecode is wrapped by `LOAD_CONST __pyarmor_enter_*__` … `LOAD_CONST __pyarmor_exit_*__`. Decrypt the enclosed blob with AES-128-CTR using the runtime key (e.g., `273b1b1373cf25e054a61e2cb8a947b8`). Derive the per-region nonce by XORing the payload-specific 12-byte XOR key (from the Pyarmor runtime) with the 12 bytes in the `__pyarmor_exit_*__` marker. After decryption, you may also see `__pyarmor_assert_*__` (encrypted strings) and `__pyarmor_bcc_*__` (compiled dispatch targets). +- **Decrypt Pyarmor “mixed” strings**: constants prefixed with `0x81` are AES-128-CTR encrypted (plaintext uses `0x01`). Use the same key and the runtime-derived string nonce (e.g., `692e767673e95c45a1e6876d`) to recover long string constants. +- **Handle BCC mode**: Pyarmor `--enable-bcc` compiles many functions to a companion ELF and leaves Python stubs that call `__pyarmor_bcc_*__`. Map those constants to ELF symbols with tooling such as `bcc_info.py`, then decompile/analyze the ELF at the reported offsets (e.g., `__pyarmor_bcc_58580__` → `bcc_180` at offset `0x4e70`). + + ## Python to Executable To start, we’re going to show you how payloads can be compiled in py2exe and PyInstaller. @@ -217,7 +233,7 @@ C:\Users\test\Desktop\test>pyinstaller --onefile hello.py ## References - [https://blog.f-secure.com/how-to-decompile-any-python-binary/](https://blog.f-secure.com/how-to-decompile-any-python-binary/) - +- [VVS Discord Stealer Using Pyarmor for Obfuscation and Detection Evasion](https://unit42.paloaltonetworks.com/vvs-stealer/) {{#include ../../../banners/hacktricks-training.md}}