Skip to main content

python injector and script runner

Project description

pyrun-injected

Run python files and scripts in python which has been injected into another process.

Why?

The usual way of running python scripts with an injected python dll wasn't able to be run on python 3.12 and above.

It seems that this was because the PyRun_SimpleString command needs to be run in the same thread as the Py_InitializeFromConfig and Py_FinalizeEx calls. Using the windows API it doesn't seem possible to execute multiple commands in the same thread.

pyrun-injected fixes this by calling all the necessary functions in one function so that we can call this function and have everything run in the same thread.

Finally, because we are writing this from scratch, we can add some extra functionality into the API for added flexibility.

To this end pyrun-injected uses PyRun_String and PyRun_File under the hood instead of PyRun_SimpleString and PyRun_SimpleFile so that we may get back any exception which is raised by calling the code, thus giving us better visibility on what went wrong if something did.

c API

pyrun-injected provides 3 functions which are useful for calling:

int pyrun_injected.dll.run_file(const char* filename):

Run the specified file name in the injected process. This will return 0 on success, and 1 on failure.

int pyrun_injected.dll.run_string(const char* string):

Run the specified string in the injected process. This will return 0 on success, and 1 on failure.

int pyrun_injected.dll.run_data(RunData* data):

Run a sequence of strings and/or files sequentially within a single session. This will return 0 on success, and 1 on failure. On failure, RunData->error will have the stacktrace written into it. See below for details.

RunData and associated structs are defined as follows:

typedef struct {
    char* error_msg;         // The actual error message we get from the traceback.
    size_t msg_length;       // The length of the error message in bytes.
    uint32_t bad_string_idx; // The index of the string that had the issue.
} ErrorData;

typedef struct {
    const char* string_value;
    uint8_t is_file;
} StringData;

typedef struct {
    uint32_t count;      // Total size of strings field.
    StringData* strings; // The actual string data to be run.
    ErrorData* error;    // Error data (if an error occurs).
} RunData;

We pass in a struct like this rather than having multiple arguments because the Windows API only allows us to pass in one argument.

python API

The python API provides a single class which simplifies injecting and calling strings and files in python.

pyrun_injected.dllinject.pyRunner(pm: pymem.Pymem):

This function takes an instance of a Pymem class as it's only constructor argument. This is because we use pymem a lot internally. The running python version and pyrun-injected will both be injected into this process.

Once initialised, this class provides just one method for running code:

def run_data(
    self,
    strings: list[StringType],
    run_in_directory: Optional[str] = None,
    inject_sys_path: bool = False,
):

where StringType is a NamedTuple defined as such:

class StringType(NamedTuple):
    value: str
    is_file: bool

This function allows you to pass in a mix of filepaths and strings to be run in the specified order. It is strongly recommended that filepaths are provided as absolute paths, unless all are in a specifi directory, in which case that path should be passed in to this function as the run_in_directory argument.

Note: It's important that all python code which is to be run which requires any other piece of code be run together. Once the code finalises after running the strings or files any data will not be persisted.

Example usage

import subprocess
import time
from pyrun_injected.dllinject import pyRunner, StringType
import pymem
import os.path as op

cwd = op.dirname(__file__)

notepad = subprocess.Popen(['notepad.exe'])
time.sleep(1)
print(f"Running on pid {notepad.pid}. Press ctrl + C to stop.")
pm = pymem.Pymem("notepad.exe")
injected = pyRunner(pm)
string = """import platform
with open("output.txt", "w") as f:
    f.write(f"hello from {platform.python_version()}")
"""
injected.run_data([StringType(string, False)], run_in_directory=cwd)
notepad.kill()

The above will start notepad, and then inject python and run the string in it. You should see the output.txt file be produced in the same directory as the file with the version of python used.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyrun_injected-0.2.0.tar.gz (9.9 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

pyrun_injected-0.2.0-cp313-cp313-win_amd64.whl (16.3 kB view details)

Uploaded CPython 3.13Windows x86-64

pyrun_injected-0.2.0-cp312-cp312-win_amd64.whl (16.3 kB view details)

Uploaded CPython 3.12Windows x86-64

pyrun_injected-0.2.0-cp311-cp311-win_amd64.whl (16.3 kB view details)

Uploaded CPython 3.11Windows x86-64

pyrun_injected-0.2.0-cp310-cp310-win_amd64.whl (16.3 kB view details)

Uploaded CPython 3.10Windows x86-64

pyrun_injected-0.2.0-cp39-cp39-win_amd64.whl (16.3 kB view details)

Uploaded CPython 3.9Windows x86-64

File details

Details for the file pyrun_injected-0.2.0.tar.gz.

File metadata

  • Download URL: pyrun_injected-0.2.0.tar.gz
  • Upload date:
  • Size: 9.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for pyrun_injected-0.2.0.tar.gz
Algorithm Hash digest
SHA256 46388968f789544318c7b23ab66c7187b8758e485c908f70dff996d0cc2e0db0
MD5 ea9f10724c8df3185c9640970d9d11a1
BLAKE2b-256 e4cc5d2ba23144e61daa187ad33368e16ca69bf6192ed187de1d9321c1f4a9b3

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyrun_injected-0.2.0.tar.gz:

Publisher: pipeline.yml on monkeyman192/pyrun_injected

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyrun_injected-0.2.0-cp313-cp313-win_amd64.whl.

File metadata

File hashes

Hashes for pyrun_injected-0.2.0-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 dfe9bef35d819319fac73aa08cf9833c99f1f634325486ef457a60ec1d0bef4c
MD5 463fb95957acabe31549712e70f9812c
BLAKE2b-256 646d090d650393863b432a3b2518a9abd8e47b63e3bcf33a94d3a8713449784c

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyrun_injected-0.2.0-cp313-cp313-win_amd64.whl:

Publisher: pipeline.yml on monkeyman192/pyrun_injected

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyrun_injected-0.2.0-cp312-cp312-win_amd64.whl.

File metadata

File hashes

Hashes for pyrun_injected-0.2.0-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 fe0a483426beeee7ab1506c67ddf50571bcf115dc436d2828a055e8f6b3d996a
MD5 e1387e6f80ac735dbcbe659d45dadf6f
BLAKE2b-256 67b0b03ee1d97123f7bad5791b32ec05df6e32e4dd2e2f45fe5584bf5ceef7cc

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyrun_injected-0.2.0-cp312-cp312-win_amd64.whl:

Publisher: pipeline.yml on monkeyman192/pyrun_injected

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyrun_injected-0.2.0-cp311-cp311-win_amd64.whl.

File metadata

File hashes

Hashes for pyrun_injected-0.2.0-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 62b1903322e652ecee662008da6644690af6d0469bcbf212638ee32f5e3741ea
MD5 6f518f3e4e2f3a48e30344c13b37084a
BLAKE2b-256 e9bc179b4aae44dd090aac3a43ac060cffdfc6ae06df83051197fa24243a7b5e

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyrun_injected-0.2.0-cp311-cp311-win_amd64.whl:

Publisher: pipeline.yml on monkeyman192/pyrun_injected

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyrun_injected-0.2.0-cp310-cp310-win_amd64.whl.

File metadata

File hashes

Hashes for pyrun_injected-0.2.0-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 c2f61181dde95b02eff1d9df2962c6264a5e8f2d66f1f70b1bb40124f2f96219
MD5 7c15f4177a34008dc56ac51f9442e992
BLAKE2b-256 e6fb8df173ec16b5bb46c1802ae630461a91852be55f6497bbb0fd706670f37d

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyrun_injected-0.2.0-cp310-cp310-win_amd64.whl:

Publisher: pipeline.yml on monkeyman192/pyrun_injected

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyrun_injected-0.2.0-cp39-cp39-win_amd64.whl.

File metadata

File hashes

Hashes for pyrun_injected-0.2.0-cp39-cp39-win_amd64.whl
Algorithm Hash digest
SHA256 e9c76de1413c9b6619a8b9debfb3e5df7c6a215502808e58eb281db67a817d2b
MD5 cb0f789ca1032ca4a7d55866aa46b2bb
BLAKE2b-256 4d4ec64200e92f7d37f7a492dde796ace68b0c7ead5247ff43d8c16961b0d7ff

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyrun_injected-0.2.0-cp39-cp39-win_amd64.whl:

Publisher: pipeline.yml on monkeyman192/pyrun_injected

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page