How does this process exactly work?

I will try to explain

These are the steps the application takes:

1

Copy itself to specified location

Copy PyCrucible binary to location and name specified by -o or --output flag

2

Prepare the payload

1

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

2

Check for local uv binary or download if not found

  • Checks to see if there is a uv binary on the system PATH (calling which uv).

  • If there is none found on the system PATH, checks if there is binary with the name uv next to pycrucible binary.

  • If there is none found download from the latest release

3

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.

4

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.

5

Running the payload

1

Check for footer

Check to see if there is a footer present. If not it means there has not been a payload embedded.

2

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).

3

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.

4

Use uv to set up virtual environment

We create a virtual environment to contain our dependencies.

5

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.

6

Run pre-run script

Check to see if any path is provided, and if so, run the script using uv run

7

Run main script

Run the main script with uv run. Main script is specified with entrypoint or entry.

8

Run post-run script

Check to see if any path is provided, and if so, run the script using uv run

Updated on