Skip to content

Commit 33b4f3f

Browse files
authored
1.2.0 (#22)
* Update injector * Add python3.11 * Drop 3.6 support * Fixes
2 parents 25540ac + 922c421 commit 33b4f3f

File tree

9 files changed

+179
-178
lines changed

9 files changed

+179
-178
lines changed

.github/workflows/tests.yml

Lines changed: 25 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
name: Tests
22

33
on:
4+
workflow_dispatch:
5+
inputs:
6+
deploy:
7+
description: 'Release this branch'
8+
required: false
9+
type: boolean
410
release:
5-
types: [created]
11+
types: [ created ]
612
push:
713
pull_request:
8-
workflow_dispatch:
914

1015
jobs:
1116
test_alpine:
@@ -15,11 +20,11 @@ jobs:
1520
fail-fast: false
1621
matrix:
1722
container:
18-
- "python:3.6-alpine"
1923
- "python:3.7-alpine"
2024
- "python:3.8-alpine"
2125
- "python:3.9-alpine"
2226
- "python:3.10-alpine"
27+
- "python:3.11-alpine"
2328
steps:
2429
- name: Install packages
2530
# gcc and musl-dev needed for compiling the package
@@ -30,18 +35,11 @@ jobs:
3035
with:
3136
submodules: true
3237
- name: Install dependencies
33-
run: pip install tox tox-gh-actions tox-wheel auditwheel
34-
- name: Test sdist with tox
38+
run: pip install tox==4.6.3 tox-gh==1.2.0 auditwheel==5.1.2
39+
- name: Test with tox
3540
run: python -m tox
36-
- name: Upload sdist
37-
uses: actions/upload-artifact@v2
38-
with:
39-
name: dist
40-
path: .tox/dist/*
41-
- name: Test wheel with tox
42-
run: python -m tox --wheel
4341
- name: Audit wheel
44-
run: auditwheel repair .tox/dist/* -w audited_wheels
42+
run: auditwheel repair .tox/.pkg/dist/*.whl -w audited_wheels
4543
- name: Upload wheel
4644
uses: actions/upload-artifact@v2
4745
with:
@@ -55,74 +53,55 @@ jobs:
5553
strategy:
5654
fail-fast: false
5755
matrix:
58-
python-version: [cp36-cp36m, cp37-cp37m, cp38-cp38, cp39-cp39, cp310-cp310]
56+
python-version: [cp37-cp37m, cp38-cp38, cp39-cp39, cp310-cp310, cp311-cp311]
5957
steps:
6058
- uses: actions/checkout@v2
6159
with:
6260
submodules: true
63-
- name: Set up Python ${{ matrix.python-version }}
61+
- name: Set up Python
6462
run: |
6563
echo "/opt/python/${{ matrix.python-version }}/bin" >> $GITHUB_PATH
6664
echo $PATH
6765
- name: Install dependencies
68-
run: pip install tox tox-gh-actions tox-wheel
69-
- name: Test sdist with tox
70-
run: python -m tox
71-
- name: Upload ${{ matrix.python-version }} sdist
72-
uses: actions/upload-artifact@v2
73-
with:
74-
name: dist
75-
path: .tox/dist/*
66+
run: pip install tox==4.6.3 tox-gh==1.2.0
7667
- name: Test wheel with tox
77-
run: python -m tox --wheel
78-
- name: Audit ${{ matrix.python-version }} wheel
79-
run: auditwheel repair .tox/dist/* -w audited_wheels
80-
- name: Upload ${{ matrix.python-version }} wheel
68+
run: python -m tox
69+
- name: Audit wheel
70+
run: auditwheel repair .tox/.pkg/dist/*.whl -w audited_wheels
71+
- name: Upload wheel
8172
uses: actions/upload-artifact@v2
8273
with:
8374
name: dist
8475
path: audited_wheels/*
8576

8677
test_windows:
8778
runs-on: windows-2019
88-
env:
89-
# VIRTUALENV_PIP and VIRTUALENV_WHEEL were added so we have versions that support python3.10
90-
VIRTUALENV_PIP: 21.3
91-
VIRTUALENV_WHEEL: 0.37
9279
strategy:
9380
fail-fast: false
9481
matrix:
95-
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"]
82+
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
9683
arch: [x86, x64]
9784
steps:
9885
- uses: actions/checkout@v2
9986
with:
10087
submodules: true
101-
- name: Set up Python ${{ matrix.python-version }}
88+
- name: Set up Python
10289
uses: actions/setup-python@v2
10390
with:
10491
python-version: ${{ matrix.python-version }}
10592
architecture: ${{ matrix.arch }}
10693
- name: Install dependencies
107-
# virtualenv==20.0.33 because of this https://github.com/ContinuumIO/anaconda-issues/issues/10822#issuecomment-736650629
108-
run: python -m pip install tox tox-gh-actions tox-wheel virtualenv==20.0.33
109-
- name: Test sdist with tox
94+
run: pip install tox==4.6.3 tox-gh==1.2.0
95+
- name: Test with tox
11096
run: python -m tox
111-
- name: Upload ${{ matrix.python-version }} sdist
112-
uses: actions/upload-artifact@v2
113-
with:
114-
name: dist
115-
path: .tox/dist/*
116-
- name: Test wheel with tox
117-
run: python -m tox --wheel
118-
- name: Upload ${{ matrix.python-version }} wheel
97+
- name: Upload wheel
11998
uses: actions/upload-artifact@v2
12099
with:
121100
name: dist
122-
path: .tox/dist/*
101+
path: .tox/.pkg/dist/*
123102

124103
publish:
125-
if: github.event_name == 'release' && github.event.action == 'created'
104+
if: (github.event_name == 'release' && github.event.action == 'created') || inputs.deploy
126105
needs: [test_windows, test_manylinux, test_alpine]
127106
runs-on: ubuntu-latest
128107
steps:

pyinjector/__init__.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,15 @@
1-
from .pyinjector import inject, LibraryNotFoundException, InjectorError
1+
from .api import inject, LibraryNotFoundException, InjectorError
2+
3+
from types import ModuleType
4+
5+
6+
def legacy_pyinjector_import():
7+
# A truly disgusting hack to cover for an import mistake in hypno<1.0.1
8+
from sys import modules
9+
pyinjector = ModuleType('pyinjector.pyinjector')
10+
pyinjector.__package__ = "pyinjector"
11+
pyinjector.InjectorError = InjectorError
12+
modules[pyinjector.__name__] = pyinjector
13+
14+
15+
legacy_pyinjector_import()
Lines changed: 105 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,105 +1,105 @@
1-
import os
2-
from importlib.util import find_spec
3-
from ctypes import CDLL, Structure, POINTER, c_int32, byref, c_char_p, c_void_p, pointer
4-
from typing import AnyStr, Callable, Any, Mapping, Type, Optional
5-
6-
libinjector_path = find_spec('.libinjector', __package__).origin
7-
libinjector = CDLL(libinjector_path)
8-
9-
injector_t = type('injector_t', (Structure,), {})
10-
injector_pointer_t = POINTER(injector_t)
11-
pid_t = c_int32
12-
13-
libinjector.injector_attach.argtypes = POINTER(injector_pointer_t), pid_t
14-
libinjector.injector_attach.restype = c_int32
15-
libinjector.injector_inject.argtypes = injector_pointer_t, c_char_p, POINTER(c_void_p)
16-
libinjector.injector_inject.restype = c_int32
17-
libinjector.injector_detach.argtypes = injector_pointer_t,
18-
libinjector.injector_detach.restype = c_int32
19-
libinjector.injector_error.argtypes = ()
20-
libinjector.injector_error.restype = c_char_p
21-
22-
23-
class PyInjectorError(Exception):
24-
pass
25-
26-
27-
class LibraryNotFoundException(PyInjectorError):
28-
def __init__(self, path: bytes):
29-
self.path = path
30-
31-
def __str__(self):
32-
return f'Could not find library: {self.path}'
33-
34-
35-
class InjectorError(PyInjectorError):
36-
def __init__(self, func_name: str, ret_val: int, error_str: Optional[bytes]):
37-
self.func_name = func_name
38-
self.ret_val = ret_val
39-
self.error_str = error_str.decode()
40-
41-
def __str__(self):
42-
explanation = 'see error code definition in injector/include/injector.h' \
43-
if self.error_str is None else self.error_str
44-
return '{} returned {}: {}'.format(self.func_name, self.ret_val, explanation)
45-
46-
47-
class InjectorPermissionError(InjectorError):
48-
def __str__(self):
49-
return (super().__str__() +
50-
'\nFailed attaching to process due to permission error.\n'
51-
'This is most likely due to ptrace scope limitations applied to the kernel for security purposes.\n'
52-
'Possible solutions:\n'
53-
' - Rerun as root\n'
54-
' - Temporarily remove ptrace scope limitations using '
55-
'`echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope`\n'
56-
' - Persistently remove ptrace scope limitations by editing /etc/sysctl.d/10-ptrace.conf\n'
57-
'More details can be found here: https://stackoverflow.com/q/19215177/2907819')
58-
59-
60-
def call_c_func(func: Callable[..., int], *args: Any,
61-
exception_map: Mapping[int, Type[InjectorError]] = None) -> None:
62-
ret = func(*args)
63-
if ret != 0:
64-
exception_map = {} if exception_map is None else exception_map
65-
exception_cls = exception_map.get(ret, InjectorError)
66-
raise exception_cls(func.__name__, ret, libinjector.injector_error())
67-
68-
69-
class Injector:
70-
def __init__(self, injector_p: injector_pointer_t):
71-
self.injector_p = injector_p
72-
73-
@classmethod
74-
def attach(cls, pid: int) -> 'Injector':
75-
assert isinstance(pid, int)
76-
injector_p = injector_pointer_t()
77-
call_c_func(libinjector.injector_attach, byref(injector_p), pid,
78-
exception_map={-8: InjectorPermissionError})
79-
return cls(injector_p)
80-
81-
def inject(self, library_path: AnyStr) -> int:
82-
if isinstance(library_path, str):
83-
library_path = library_path.encode()
84-
assert isinstance(library_path, bytes)
85-
assert os.path.isfile(library_path), f'Library not found at "{library_path.decode()}"'
86-
handle = c_void_p()
87-
call_c_func(libinjector.injector_inject, self.injector_p, library_path, pointer(handle))
88-
return handle.value
89-
90-
def detach(self) -> None:
91-
call_c_func(libinjector.injector_detach, self.injector_p)
92-
93-
94-
def inject(pid: int, library_path: AnyStr) -> int:
95-
"""
96-
Inject the shared library at library_path to the process (or thread) with the given pid.
97-
Return the handle to the loaded library.
98-
"""
99-
if not os.path.isfile(library_path):
100-
raise LibraryNotFoundException(library_path)
101-
injector = Injector.attach(pid)
102-
try:
103-
return injector.inject(library_path)
104-
finally:
105-
injector.detach()
1+
import os
2+
from importlib.util import find_spec
3+
from ctypes import CDLL, Structure, POINTER, c_int32, byref, c_char_p, c_void_p, pointer
4+
from typing import AnyStr, Callable, Any, Mapping, Type, Optional
5+
6+
libinjector_path = find_spec('.libinjector', __package__).origin
7+
libinjector = CDLL(libinjector_path)
8+
9+
injector_t = type('injector_t', (Structure,), {})
10+
injector_pointer_t = POINTER(injector_t)
11+
pid_t = c_int32
12+
13+
libinjector.injector_attach.argtypes = POINTER(injector_pointer_t), pid_t
14+
libinjector.injector_attach.restype = c_int32
15+
libinjector.injector_inject.argtypes = injector_pointer_t, c_char_p, POINTER(c_void_p)
16+
libinjector.injector_inject.restype = c_int32
17+
libinjector.injector_detach.argtypes = injector_pointer_t,
18+
libinjector.injector_detach.restype = c_int32
19+
libinjector.injector_error.argtypes = ()
20+
libinjector.injector_error.restype = c_char_p
21+
22+
23+
class PyInjectorError(Exception):
24+
pass
25+
26+
27+
class LibraryNotFoundException(PyInjectorError):
28+
def __init__(self, path: bytes):
29+
self.path = path
30+
31+
def __str__(self):
32+
return f'Could not find library: {self.path}'
33+
34+
35+
class InjectorError(PyInjectorError):
36+
def __init__(self, func_name: str, ret_val: int, error_str: Optional[bytes]):
37+
self.func_name = func_name
38+
self.ret_val = ret_val
39+
self.error_str = error_str.decode()
40+
41+
def __str__(self):
42+
explanation = 'see error code definition in injector/include/injector.h' \
43+
if self.error_str is None else self.error_str
44+
return '{} returned {}: {}'.format(self.func_name, self.ret_val, explanation)
45+
46+
47+
class InjectorPermissionError(InjectorError):
48+
def __str__(self):
49+
return (super().__str__() +
50+
'\nFailed attaching to process due to permission error.\n'
51+
'This is most likely due to ptrace scope limitations applied to the kernel for security purposes.\n'
52+
'Possible solutions:\n'
53+
' - Rerun as root\n'
54+
' - Temporarily remove ptrace scope limitations using '
55+
'`echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope`\n'
56+
' - Persistently remove ptrace scope limitations by editing /etc/sysctl.d/10-ptrace.conf\n'
57+
'More details can be found here: https://stackoverflow.com/q/19215177/2907819')
58+
59+
60+
def call_c_func(func: Callable[..., int], *args: Any,
61+
exception_map: Mapping[int, Type[InjectorError]] = None) -> None:
62+
ret = func(*args)
63+
if ret != 0:
64+
exception_map = {} if exception_map is None else exception_map
65+
exception_cls = exception_map.get(ret, InjectorError)
66+
raise exception_cls(func.__name__, ret, libinjector.injector_error())
67+
68+
69+
class Injector:
70+
def __init__(self, injector_p: injector_pointer_t):
71+
self.injector_p = injector_p
72+
73+
@classmethod
74+
def attach(cls, pid: int) -> 'Injector':
75+
assert isinstance(pid, int)
76+
injector_p = injector_pointer_t()
77+
call_c_func(libinjector.injector_attach, byref(injector_p), pid,
78+
exception_map={-8: InjectorPermissionError})
79+
return cls(injector_p)
80+
81+
def inject(self, library_path: AnyStr) -> int:
82+
if isinstance(library_path, str):
83+
library_path = library_path.encode()
84+
assert isinstance(library_path, bytes)
85+
assert os.path.isfile(library_path), f'Library not found at "{library_path.decode()}"'
86+
handle = c_void_p()
87+
call_c_func(libinjector.injector_inject, self.injector_p, library_path, pointer(handle))
88+
return handle.value
89+
90+
def detach(self) -> None:
91+
call_c_func(libinjector.injector_detach, self.injector_p)
92+
93+
94+
def inject(pid: int, library_path: AnyStr) -> int:
95+
"""
96+
Inject the shared library at library_path to the process (or thread) with the given pid.
97+
Return the handle to the loaded library.
98+
"""
99+
if not os.path.isfile(library_path):
100+
raise LibraryNotFoundException(library_path)
101+
injector = Injector.attach(pid)
102+
try:
103+
return injector.inject(library_path)
104+
finally:
105+
injector.detach()

setup.cfg

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
[options]
22
zip_safe = False
3-
python_requires = >=3.6
3+
python_requires = >=3.7
44
packages = pyinjector
55

66
[metadata]
77
name = pyinjector
8-
version = 1.1.1
8+
version = 1.2.0
99
description = A tool/library allowing dynamic library injection into running processes
1010
author = Maor Kleinberger
1111
author_email = kmaork@gmail.com
@@ -19,9 +19,9 @@ classifiers =
1919
License :: OSI Approved :: MIT License
2020
Programming Language :: Python :: 3
2121
Programming Language :: Python :: 3 :: Only
22-
Programming Language :: Python :: 3.6
2322
Programming Language :: Python :: 3.7
2423
Programming Language :: Python :: 3.8
2524
Programming Language :: Python :: 3.9
2625
Programming Language :: Python :: 3.10
26+
Programming Language :: Python :: 3.11
2727
Topic :: Software Development :: Libraries :: Python Modules

0 commit comments

Comments
 (0)