These are the steps the application takes:
Copy itself to specified location
Copy PyCrucible binary to location and name specified by -o
or --output
flag
Prepare the payload
Collect source files
Iterates your python directory, collecting all the files specified in include/exclude settings in configuration.
Compress everything found into a .zip
archive
Check for local uv binary or download if not found
-
Checks to see if there is a
uv
binary on the system PATH (callingwhich uv
). -
If there is none found on the system PATH, checks if there is binary with the name
uv
next topycrucible
binary. -
If there is none found download from the latest release
Prepare the footer
Footer is just a small peace of information (in my case 16 bytes).
It contains the offset where the payload should begin, a custom byte-string (also known as magic string) and a size (or length) of payload.
Offset is specified by 8 bytes
Magic string is specified by 4 bytes
Length is specified by 4 bytes
Only 4 bytes for length could make problems.
It could overflow for bigger sizes of payloads.
This is planning to be fixed in the upcoming v0.3.0 version.
Embed the payload and the footer to its own copy
This is where the “magic” is happening.
PyCrucible opens its copied binary in append mode. It appends the payload and a footer to its bytes array making a sandwich of layers.
PyCrucible | Payload | Footer
Everything is basically just bytes. Images, music, videos or text files.
These are all in the end just bytes represented in arrays.
Running the payload
Check for footer
Check to see if there is a footer present. If not it means there has not been a payload embedded.
Read the footer
As the footer is exactly 16 bytes and stored at the end of the binary, we know exactly what to read to get the footer.
Now we read the footer to determine where to start looking for payload (offset) and exactly how much to read (its length).
Extract the payload to a directory
Create a directory (in temporary location or next to binary).
Extract the payload (your python project and uv
binary) to a directory.
Use uv to set up virtual environment
We create a virtual environment to contain our dependencies.
Use uv to read the requirements from supplied files and download what it needs
uv
is really fast in this process, the only limiting factor is internet speed.
It downloads python interpreter and all dependencies listed.
There is a update coming that will enable “offline“ mode.
Run pre-run script
Check to see if any path is provided, and if so, run the script using uv run
Run main script
Run the main script with uv run
. Main script is specified with entrypoint
or entry
.
Run post-run script
Check to see if any path is provided, and if so, run the script using uv run