hacktricks/forensics/basic-forensic-methodology/specific-software-file-type.../.pyc.md

251 lines
10 KiB
Markdown
Raw Normal View History

2022-04-28 18:01:33 +02:00
<details>
<summary><strong>Support HackTricks and get benefits!</strong></summary>
Do you work in a **cybersecurity company**? Do you want to see your **company advertised in HackTricks**? or do you want to have access the **latest version of the PEASS or download HackTricks in PDF**? Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family)
Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com)
**Join the** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/carlospolopm)**.**
**Share your hacking tricks submitting PRs to the** [**hacktricks github repo**](https://github.com/carlospolop/hacktricks)**.**
</details>
2022-05-01 14:41:36 +02:00
# From Compiled Binary to .pyc
2021-11-30 17:46:07 +01:00
From an **ELF** compiled binary you can **get the .pyc** with:
2021-11-06 16:07:00 +01:00
```bash
pyi-archive_viewer <binary>
# The list of python modules will be given like here:
[(0, 230, 311, 1, 'm', 'struct'),
(230, 1061, 1792, 1, 'm', 'pyimod01_os_path'),
(1291, 4071, 8907, 1, 'm', 'pyimod02_archive'),
(5362, 5609, 13152, 1, 'm', 'pyimod03_importers'),
(10971, 1473, 3468, 1, 'm', 'pyimod04_ctypes'),
(12444, 816, 1372, 1, 's', 'pyiboot01_bootstrap'),
(13260, 696, 1053, 1, 's', 'pyi_rth_pkgutil'),
(13956, 1134, 2075, 1, 's', 'pyi_rth_multiprocessing'),
(15090, 445, 672, 1, 's', 'pyi_rth_inspect'),
(15535, 2514, 4421, 1, 's', 'binary_name'),
...
? X binary_name
to filename? /tmp/binary.pyc
```
2021-11-30 17:46:07 +01:00
In an **python exe binary** compiled you can **get the .pyc** by running:
2021-11-06 16:07:00 +01:00
```bash
python pyinstxtractor.py executable.exe
```
2022-05-01 14:41:36 +02:00
# From .pyc to python code
2021-11-06 16:07:00 +01:00
2021-11-30 17:46:07 +01:00
For the **.pyc** data ("compiled" python) you should start trying to **extract** the **original** **python** **code**:
2020-12-20 20:43:00 +01:00
```bash
uncompyle6 binary.pyc > decompiled.py
```
**Be sure** that the binary has the **extension** "**.pyc**" (if not, uncompyle6 is not going to work)
2021-11-30 17:46:07 +01:00
While executing **uncompyle6** you might find the **following errors**:
2021-11-06 16:07:00 +01:00
2022-05-01 14:41:36 +02:00
## Error: Unknown magic number 227
2021-11-06 16:07:00 +01:00
```bash
/kali/.local/bin/uncompyle6 /tmp/binary.pyc
Unknown magic number 227 in /tmp/binary.pyc
```
2021-11-30 17:46:07 +01:00
In order to fix this you need to **add the correct magic number** at the begging of the generated fil.
2021-11-06 16:07:00 +01:00
**Magic numbers vary with the python version**, to get the magic number of **python3.8** you will need to **open a python3.8** terminal and execute:
```
>> import imp
>> imp.get_magic().hex()
'550d0d0a'
```
2021-11-30 17:46:07 +01:00
The **magic number** in this case for python3.8 is **`0x550d0d0a`**, then, to fix this error you will need to **add** at the **begging** of the **.pyc file** the following bytes: `0x0d550a0d000000000000000000000000`
2021-11-06 16:07:00 +01:00
2021-11-30 17:46:07 +01:00
**Once** you have **added** that magic header, the **error should be fixed.**
2021-11-06 16:07:00 +01:00
This is how a correctly added **.pyc python3.8 magic header** will looks like:
```bash
hexdump 'binary.pyc' | head
0000000 0d55 0a0d 0000 0000 0000 0000 0000 0000
0000010 00e3 0000 0000 0000 0000 0000 0000 0000
0000020 0700 0000 4000 0000 7300 0132 0000 0064
0000030 0164 006c 005a 0064 0164 016c 015a 0064
```
2022-05-01 14:41:36 +02:00
## Error: Decompiling generic errors
2021-11-06 16:07:00 +01:00
2021-11-30 17:46:07 +01:00
**Other errors** like: `class 'AssertionError'>; co_code should be one of the types (<class 'str'>, <class 'bytes'>, <class 'list'>, <class 'tuple'>); is type <class 'NoneType'>` may appear.
2021-11-06 16:07:00 +01:00
2021-11-30 17:46:07 +01:00
This probably means that you **haven't added correctly** the magic number or that you haven't **used** the **correct magic number**, so make **sure you use the correct one** (or try a new one).
2021-11-06 16:07:00 +01:00
Check the previous error documentation.
2022-05-01 14:41:36 +02:00
# Automatic Tool
2021-11-28 18:35:01 +01:00
2022-04-06 00:24:52 +02:00
The tool [https://github.com/countercept/python-exe-unpacker](https://github.com/countercept/python-exe-unpacker) glues together several tools available to the community that **helps researcher to unpack and decompile executable** written in python (py2exe and pyinstaller).
2021-11-28 18:35:01 +01:00
Several YARA rules are available to determine if the executable is written in python (This script also confirms if the executable is created with either py2exe or pyinstaller).
2022-05-01 14:41:36 +02:00
## ImportError: File name: 'unpacked/malware\_3.exe/**pycache**/archive.cpython-35.pyc' doesn't exist
2021-11-28 18:35:01 +01:00
Currently with unpy2exe or pyinstxtractor the Python bytecode file we get might not be complete and in turn it **cant be recognized by uncompyle6 to get the plain Python source code**. This is caused by a missing Python **bytecode version number**. Therefore we included a prepend option; this will include a Python bytecode version number into it and help to ease the process of decompiling. When we try to use uncompyle6 to decompile the .pyc file it returns an error. However, **once we use the prepend option we can see that the Python source code has been decompiled successfully**.
```
test@test: uncompyle6 unpacked/malware_3.exe/archive.py
Traceback (most recent call last):
……………………….
ImportError: File name: 'unpacked/malware_3.exe/__pycache__/archive.cpython-35.pyc' doesn't exist
```
```
test@test:python python_exe_unpack.py -p unpacked/malware_3.exe/archive
[*] On Python 2.7
[+] Magic bytes is already appeneded.
# Successfully decompiled file
[+] Successfully decompiled.
```
2022-05-01 14:41:36 +02:00
# Analyzing python assembly
2021-11-30 17:46:07 +01:00
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 **dissasemble** the _.pyc_ binary (good luck understanding the code flow). If the _.pyc_ is from python2, use python2:
2020-12-20 20:43:00 +01:00
```bash
>>> import dis
>>> import marshal
>>> import struct
>>> import imp
>>>
>>> with open('hello.pyc', 'r') as f: # Read the binary file
... magic = f.read(4)
... timestamp = f.read(4)
... code = f.read()
...
>>>
>>> # Unpack the structure content and un-marshal the code
>>> magic = struct.unpack('<H', magic[:2])
>>> timestamp = struct.unpack('<I', timestamp)
>>> code = marshal.loads(code)
>>> magic, timestamp, code
((62211,), (1425911959,), <code object <module> at 0x7fd54f90d5b0, file "hello.py", line 1>)
>>>
>>> # Verify if magic number corresponds with the current python version
>>> struct.unpack('<H', imp.get_magic()[:2]) == magic
True
>>>
>>> # Disassemble the code object
>>> dis.disassemble(code)
1 0 LOAD_CONST 0 (<code object hello_world at 0x7f31b7240eb0, file "hello.py", line 1>)
3 MAKE_FUNCTION 0
6 STORE_NAME 0 (hello_world)
9 LOAD_CONST 1 (None)
12 RETURN_VALUE
>>>
>>> # Also disassemble that const being loaded (our function)
>>> dis.disassemble(code.co_consts[0])
2 0 LOAD_CONST 1 ('Hello {0}')
3 LOAD_ATTR 0 (format)
6 LOAD_FAST 0 (name)
9 CALL_FUNCTION 1
12 PRINT_ITEM
13 PRINT_NEWLINE
14 LOAD_CONST 0 (None)
17 RETURN_VALUE
```
2021-11-28 18:30:37 +01:00
2022-05-01 14:41:36 +02:00
# Python to Executable
2021-11-28 18:30:37 +01:00
To start off were going to show you how payloads can be compiled in py2exe and PyInstaller.
2022-05-01 14:41:36 +02:00
## To create a payload using py2exe:
2021-11-28 18:30:37 +01:00
1. Install the py2exe package from [http://www.py2exe.org/](http://www.py2exe.org)
2. For the payload (in this case, we will name it hello.py), use a script like the one in Figure 1. The option “bundle\_files” with the value of 1 will bundle everything including Python interpreter into one exe.
3. Once the script is ready, we will issue the command “python setup.py py2exe”. This will create the executable, just like in Figure 2.
```
from distutils.core import setup
import py2exe, sys, os
sys.argv.append('py2exe')
setup(
options = {'py2exe': {'bundle_files': 1}},
#windows = [{'script': "hello.py"}],
console = [{'script': "hello.py"}],
zipfile = None,
)
```
```
C:\Users\test\Desktop\test>python setup.py py2exe
running py2exe
*** searching for required modules ***
*** parsing results ***
*** finding dlls needed ***
*** create binaries ***
*** byte compile python files ***
*** copy extensions ***
*** copy dlls ***
copying C:\Python27\lib\site-packages\py2exe\run.exe -> C:\Users\test\Desktop\test\dist\hello.exe
Adding python27.dll as resource to C:\Users\test\Desktop\test\dist\hello.exe
```
2022-05-01 14:41:36 +02:00
## To create a payload using PyInstaller:
2021-11-28 18:30:37 +01:00
1. Install PyInstaller using pip (pip install pyinstaller).
2. After that, we will issue the command “pyinstaller onefile hello.py” (a reminder that hello.py is our payload). This will bundle everything into one executable.
```
C:\Users\test\Desktop\test>pyinstaller --onefile hello.py
108 INFO: PyInstaller: 3.3.1
108 INFO: Python: 2.7.14
108 INFO: Platform: Windows-10-10.0.16299
………………………………
5967 INFO: checking EXE
5967 INFO: Building EXE because out00-EXE.toc is non existent
5982 INFO: Building EXE from out00-EXE.toc
5982 INFO: Appending archive to EXE C:\Users\test\Desktop\test\dist\hello.exe
6325 INFO: Building EXE from out00-EXE.toc completed successfully.
```
2022-05-01 14:41:36 +02:00
# References
2021-11-28 18:35:01 +01:00
* [https://blog.f-secure.com/how-to-decompile-any-python-binary/](https://blog.f-secure.com/how-to-decompile-any-python-binary/)
2022-04-28 18:01:33 +02:00
<details>
<summary><strong>Support HackTricks and get benefits!</strong></summary>
Do you work in a **cybersecurity company**? Do you want to see your **company advertised in HackTricks**? or do you want to have access the **latest version of the PEASS or download HackTricks in PDF**? Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family)
Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com)
**Join the** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/carlospolopm)**.**
**Share your hacking tricks submitting PRs to the** [**hacktricks github repo**](https://github.com/carlospolop/hacktricks)**.**
</details>