injectlib 0.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. injectlib-0.0.1/LICENSE +30 -0
  2. injectlib-0.0.1/MANIFEST.in +16 -0
  3. injectlib-0.0.1/PKG-INFO +42 -0
  4. injectlib-0.0.1/README.md +84 -0
  5. injectlib-0.0.1/setup.cfg +4 -0
  6. injectlib-0.0.1/setup.py +95 -0
  7. injectlib-0.0.1/src/injectlib/__init__.py +0 -0
  8. injectlib-0.0.1/src/injectlib/api.py +90 -0
  9. injectlib-0.0.1/src/injectlib/cfuncs.py +76 -0
  10. injectlib-0.0.1/src/injectlib/channel.py +69 -0
  11. injectlib-0.0.1/src/injectlib/injector.py +89 -0
  12. injectlib-0.0.1/src/injectlib/libs/dotnet/x64/Newtonsoft.Json.dll +0 -0
  13. injectlib-0.0.1/src/injectlib/libs/dotnet/x64/bootstrap.dll +0 -0
  14. injectlib-0.0.1/src/injectlib/libs/dotnet/x64/worker_wpf.dll +0 -0
  15. injectlib-0.0.1/src/injectlib/libs/dotnet/x86/Newtonsoft.Json.dll +0 -0
  16. injectlib-0.0.1/src/injectlib/libs/dotnet/x86/bootstrap.dll +0 -0
  17. injectlib-0.0.1/src/injectlib/libs/dotnet/x86/worker_wpf.dll +0 -0
  18. injectlib-0.0.1/src/injectlib/libs/hook/x64/pywinmsg64.dll +0 -0
  19. injectlib-0.0.1/src/injectlib/libs/hook/x64/pywinmsg64u.dll +0 -0
  20. injectlib-0.0.1/src/injectlib/libs/hook/x86/pywinmsg32.dll +0 -0
  21. injectlib-0.0.1/src/injectlib/libs/hook/x86/pywinmsg32u.dll +0 -0
  22. injectlib-0.0.1/src/injectlib/libs/qt/x64/qt_srv.dll +0 -0
  23. injectlib-0.0.1/src/injectlib/sysinfo.py +61 -0
  24. injectlib-0.0.1/src/injectlib.egg-info/PKG-INFO +42 -0
  25. injectlib-0.0.1/src/injectlib.egg-info/SOURCES.txt +26 -0
  26. injectlib-0.0.1/src/injectlib.egg-info/dependency_links.txt +1 -0
  27. injectlib-0.0.1/src/injectlib.egg-info/requires.txt +1 -0
  28. injectlib-0.0.1/src/injectlib.egg-info/top_level.txt +1 -0
@@ -0,0 +1,30 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2026 Vasily Ryabov, Ilya Naumov, Boris Galochkin, Alexander Makarov
4
+ https://github.com/pywinauto/injectlib/graphs/contributors
5
+ All rights reserved.
6
+
7
+ Redistribution and use in source and binary forms, with or without
8
+ modification, are permitted provided that the following conditions are met:
9
+
10
+ * Redistributions of source code must retain the above copyright notice, this
11
+ list of conditions and the following disclaimer.
12
+
13
+ * Redistributions in binary form must reproduce the above copyright notice,
14
+ this list of conditions and the following disclaimer in the documentation
15
+ and/or other materials provided with the distribution.
16
+
17
+ * Neither the name of the copyright holder nor the names of its
18
+ contributors may be used to endorse or promote products derived from
19
+ this software without specific prior written permission.
20
+
21
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,16 @@
1
+ include src/injectlib/libs/dotnet/x86/bootstrap.dll
2
+ include src/injectlib/libs/dotnet/x86/Newtonsoft.Json.dll
3
+ include src/injectlib/libs/dotnet/x86/worker_wpf.dll
4
+
5
+ include src/injectlib/libs/dotnet/x64/bootstrap.dll
6
+ include src/injectlib/libs/dotnet/x64/Newtonsoft.Json.dll
7
+ include src/injectlib/libs/dotnet/x64/worker_wpf.dll
8
+
9
+
10
+ include src/injectlib/libs/hook/x86/pywinmsg32.dll
11
+ include src/injectlib/libs/hook/x86/pywinmsg32u.dll
12
+
13
+ include src/injectlib/libs/hook/x64/pywinmsg64.dll
14
+ include src/injectlib/libs/hook/x64/pywinmsg64u.dll
15
+
16
+ include src/injectlib/libs/qt/x64/qt_srv.dll
@@ -0,0 +1,42 @@
1
+ Metadata-Version: 2.4
2
+ Name: injectlib
3
+ Version: 0.0.1
4
+ Summary: A set of Python modules to inject DLLs into applications for the Microsoft Windows
5
+ Home-page: https://github.com/pywinauto/injectlib
6
+ Author: Vasily Ryabov, Ilya Naumov, Boris Galochkin, Alexander Makarov
7
+ Author-email: vasily.v.ryabov@gmail.com
8
+ License: BSD 3-clause
9
+ Keywords: windows gui .net inject testing test desktop dll wpf qt
10
+ Platform: win32
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: BSD License
15
+ Classifier: Operating System :: Microsoft :: Windows
16
+ Classifier: Programming Language :: Python
17
+ Classifier: Programming Language :: Python :: 3.7
18
+ Classifier: Programming Language :: Python :: 3.8
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: Implementation :: CPython
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Classifier: Topic :: Software Development :: Testing
25
+ Requires-Python: >=3.7
26
+ License-File: LICENSE
27
+ Requires-Dist: pywin32
28
+ Dynamic: author
29
+ Dynamic: author-email
30
+ Dynamic: classifier
31
+ Dynamic: description
32
+ Dynamic: home-page
33
+ Dynamic: keywords
34
+ Dynamic: license
35
+ Dynamic: license-file
36
+ Dynamic: platform
37
+ Dynamic: requires-dist
38
+ Dynamic: requires-python
39
+ Dynamic: summary
40
+
41
+
42
+ It allows to inject DLls into applications for the Microsoft Windows.
@@ -0,0 +1,84 @@
1
+ # injectlib
2
+
3
+ injectlib is a Python package that allows you to inject DLLs into running
4
+ processes on Windows (32 or 64-bit).
5
+
6
+ This can be useful for various tasks, such as debugging or adding
7
+ functionality to existing applications.
8
+
9
+ This is initially created for desktop GUI automation purpose
10
+ (project pywinauto), because an injected DLL can access GUI widgets' text
11
+ properties with much better precision and coverage than standard OS APIs like
12
+ MS UI Automation API or Win32 API. Other use cases are potentially possible at
13
+ your own risk according to the law and the project license.
14
+
15
+ It contains:
16
+
17
+ * initial DLL to be injected which is written in C,
18
+ * server-side DLL that can exchange data between injected DLL (server) and
19
+ Python process (client),
20
+ * managed DLL which is able to get text properties of WPF applications,
21
+ * DLL which is able to get text properties of Qt applications,
22
+ * Python code to initiate the injection,
23
+ * and client Python code for data exchange with an injected DLL.
24
+
25
+ Link to PyPi: <https://pypi.org/project/injectlib/>
26
+
27
+ ## How to use
28
+
29
+ python.exe example_injector.py \<Process name\> \<path to dll\>
30
+
31
+ ## Development
32
+
33
+ 1. Clone repository: <https://github.com/pywinauto/injectlib.git>
34
+ 2. Create new features or improve exiting (for the injectlib package)
35
+ 3. After work run setup.py from project root to check standalone
36
+
37
+ python.exe setup.py bdist_wheel
38
+
39
+ ## Requirements
40
+
41
+ ### For use as package
42
+
43
+ * Python >= 3.7
44
+ * pywin32 >= 306
45
+
46
+ ### For development purpose
47
+
48
+ * setuptools >= 65.5.1
49
+ * wheel >= 0.38.4
50
+ * .NET Framework Targeting Pack >= 4.8
51
+ * .NET Compiler Platform
52
+ * MSBuild
53
+ * MSVC >= 143
54
+ * cmake >= 3.26.3
55
+ * Qt >= 5.15.2, < 6
56
+
57
+ **NOTE**: You may use PyCharm + Visual Studio with C++/C# components for
58
+ development
59
+
60
+ ### Building Qt DLL
61
+
62
+ This package compiles C++ binaries that link against **Qt 5** (>=5.15.2, <6).
63
+ Qt is not bundled and must be installed separately before building.
64
+
65
+ - **Windows** download options:
66
+ - download via [Qt Online Installer](https://www.qt.io/download) and select the MSVC 2019 64-bit component. Registration required. Installation might be banned for some countries
67
+ - via mirrors, for example, https://mirror.yandex.ru/mirrors/qt.io. Base package for Qt 5.15.2 can be found [here](https://mirror.yandex.ru/mirrors/qt.io/online/qtsdkrepository/windows_x86/desktop/qt5_5152/qt.qt5.5152.win64_msvc2019_64/5.15.2-0-202011130602qtbase-Windows-Windows_10-MSVC2019-Windows-Windows_10-X86_64.7z). No registration required.
68
+
69
+ Once installed, point CMake to your Qt installation by setting `CMAKE_PREFIX_PATH`:
70
+
71
+ ```bash
72
+ # Windows (adjust version/compiler as needed)
73
+ set CMAKE_PREFIX_PATH=C:/Qt/5.15.2/msvc2019_64
74
+ ```
75
+
76
+ If CMake still cannot find Qt, verify the path contains a `lib/cmake/Qt5` subdirectory.
77
+
78
+ ## License
79
+
80
+ This software is open-source under the BSD 3-Clause License.
81
+
82
+ See the LICENSE file in this repository.
83
+
84
+ Dependencies are licensed by their own licenses.
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,95 @@
1
+ """Install and build injectlib distributions"""
2
+
3
+ import os
4
+ import shutil
5
+ import subprocess
6
+ import sys
7
+ from setuptools import setup
8
+ from setuptools.command.sdist import sdist
9
+ from setuptools.dist import Distribution
10
+
11
+
12
+ x86_cmake_arch_name, x64_cmake_arch_name = 'Win32', 'x64'
13
+ x86_package_arch_name, x64_package_arch_name = 'x86', 'x64'
14
+
15
+ is_64bit = sys.maxsize > 2**32
16
+ if is_64bit:
17
+ arch_names_map = { x64_cmake_arch_name: x64_package_arch_name }
18
+ else:
19
+ arch_names_map = { x86_cmake_arch_name: x86_package_arch_name }
20
+
21
+ build_dirname = 'build_'
22
+ build_dll_dirs = ['./backends/dotnet/', './backends/hook/', './backends/qt/']
23
+ package_dll_dirs = ['./src/injectlib/libs/dotnet/', './src/injectlib/libs/hook/', './src/injectlib/libs/qt/']
24
+ cmake_dirs = build_dll_dirs
25
+
26
+
27
+ class SdistWithDlls(sdist):
28
+ """Custom build command that compiles DLLs before packaging Python files."""
29
+
30
+ def run(self):
31
+ # cmake build for DLLs
32
+ for arch in arch_names_map:
33
+ for cmake_dir in cmake_dirs:
34
+ build_dir = cmake_dir + build_dirname + arch
35
+
36
+ os.makedirs(build_dir, exist_ok=True)
37
+
38
+ subprocess.check_call(['cmake', '-B ' + build_dir, '-S ' + cmake_dir, '-A ' + arch])
39
+ subprocess.check_call(['cmake', '--build', build_dir, '--config', 'Release'])
40
+
41
+ # copy DLLs to the package
42
+ for arch in arch_names_map:
43
+ for build_dll_dir, package_dll_dir in zip(build_dll_dirs, package_dll_dirs):
44
+ for root, _, files in os.walk(build_dll_dir + build_dirname + arch):
45
+ for file in files:
46
+ if file.endswith('.dll'):
47
+ src_file_path = os.path.join(root, file)
48
+ dest_file_path = os.path.join(package_dll_dir + arch_names_map.get(arch), file)
49
+ os.makedirs(os.path.dirname(dest_file_path), exist_ok=True)
50
+ shutil.copy(src_file_path, dest_file_path)
51
+ super().run()
52
+
53
+ # mark the package is not pure Python code
54
+ class BinaryDistribution(Distribution):
55
+ def is_pure(self):
56
+ return False
57
+
58
+
59
+ setup(name='injectlib',
60
+ version='0.0.1',
61
+ description='A set of Python modules to inject DLLs into applications for the Microsoft Windows',
62
+ keywords="windows gui .net inject testing test desktop dll wpf qt",
63
+ url="https://github.com/pywinauto/injectlib",
64
+ author='Vasily Ryabov, Ilya Naumov, Boris Galochkin, Alexander Makarov',
65
+ author_email='vasily.v.ryabov@gmail.com',
66
+ long_description="""
67
+ It allows to inject DLls into applications for the Microsoft Windows.
68
+ """,
69
+ platforms=['win32'],
70
+
71
+ packages=["injectlib"],
72
+ package_dir={"": "src"},
73
+ include_package_data=True,
74
+
75
+ license="BSD 3-clause",
76
+ classifiers=[
77
+ 'Development Status :: 5 - Production/Stable',
78
+ 'Environment :: Console',
79
+ 'Intended Audience :: Developers',
80
+ 'License :: OSI Approved :: BSD License',
81
+ 'Operating System :: Microsoft :: Windows',
82
+ 'Programming Language :: Python',
83
+ 'Programming Language :: Python :: 3.7',
84
+ 'Programming Language :: Python :: 3.8',
85
+ 'Programming Language :: Python :: 3.9',
86
+ 'Programming Language :: Python :: 3.10',
87
+ 'Programming Language :: Python :: 3.11',
88
+ 'Programming Language :: Python :: Implementation :: CPython',
89
+ 'Topic :: Software Development :: Libraries :: Python Modules',
90
+ 'Topic :: Software Development :: Testing',
91
+ ],
92
+ install_requires=['pywin32'],
93
+ python_requires='>=3.7',
94
+ cmdclass={'sdist': SdistWithDlls},
95
+ )
File without changes
@@ -0,0 +1,90 @@
1
+ import json
2
+ import logging
3
+
4
+ from .injector import Injector
5
+ from .channel import Pipe
6
+
7
+ logger = logging.getLogger(__package__)
8
+
9
+ # backend exit codes enum
10
+ OK = 0
11
+ PARSE_ERROR = 1
12
+ UNSUPPORTED_ACTION = 2
13
+ MISSING_PARAM = 3
14
+ RUNTIME_ERROR = 4
15
+ NOT_FOUND = 5
16
+ UNSUPPORTED_TYPE = 6
17
+ INVALID_VALUE = 7
18
+
19
+
20
+ class InjectedBaseError(Exception):
21
+ """Base class for exceptions based on errors returned from injected DLL side"""
22
+
23
+
24
+ class InjectedUnsupportedActionError(InjectedBaseError):
25
+ """The specified action is not supported"""
26
+
27
+
28
+ class InjectedRuntimeError(InjectedBaseError):
29
+ """Runtime exception during code execution inside injected target"""
30
+
31
+
32
+ class InjectedNotFoundError(InjectedBaseError):
33
+ """Requested item not found: control element, property, ..."""
34
+
35
+
36
+ class Singleton(type):
37
+ """
38
+ Singleton metaclass implementation from StackOverflow
39
+
40
+ http://stackoverflow.com/q/6760685/3648361
41
+ """
42
+
43
+ _instances = {}
44
+
45
+ def __call__(cls, *args, **kwargs):
46
+ if cls not in cls._instances:
47
+ cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
48
+ return cls._instances[cls]
49
+
50
+
51
+ class ConnectionManager(object, metaclass=Singleton):
52
+ def __init__(self):
53
+ self._pipes = {}
54
+
55
+ def _get_pipe(self, pid):
56
+ if pid not in self._pipes:
57
+ self._pipes[pid] = self._create_pipe(pid)
58
+ return self._pipes[pid]
59
+
60
+ def _create_pipe(self, pid):
61
+ pipe_name = 'process_{}'.format(pid)
62
+ pipe = Pipe(pipe_name)
63
+ if pipe.connect(n_attempts=1):
64
+ logger.info('Pipe {} found, looks like dll has been injected already'.format(pipe_name))
65
+ return pipe
66
+ else:
67
+ logger.info('Pipe {} not found, injecting dll to the process'.format(pipe_name))
68
+ Injector(pid, 'dotnet', 'bootstrap')
69
+ pipe.connect()
70
+ return pipe
71
+
72
+ def call_action(self, action_name, pid, **params):
73
+ command = {'action': action_name}
74
+ command.update(params)
75
+
76
+ reply = self._get_pipe(pid).transact(json.dumps(command))
77
+ reply = json.loads(reply)
78
+
79
+ reply_code = reply['status_code']
80
+
81
+ if reply_code == UNSUPPORTED_ACTION:
82
+ raise InjectedUnsupportedActionError(reply['message'])
83
+ elif reply_code == RUNTIME_ERROR:
84
+ raise InjectedRuntimeError(reply['message'])
85
+ elif reply_code == NOT_FOUND:
86
+ raise InjectedNotFoundError(reply['message'])
87
+ elif reply_code != OK:
88
+ raise InjectedBaseError()
89
+
90
+ return reply
@@ -0,0 +1,76 @@
1
+ """Some functions already exists in pywinauto, but for correctly
2
+ injector work needs full redefinition with ctypes compatible
3
+ """
4
+
5
+ import win32con
6
+ from ctypes import Structure, sizeof, alignment
7
+ from ctypes import c_char_p, c_wchar_p
8
+ from ctypes import POINTER
9
+ from ctypes import windll
10
+ from ctypes.wintypes import BOOL, DWORD, HANDLE, LPVOID, LPCVOID
11
+
12
+
13
+ class SECURITY_ATTRIBUTES(Structure):
14
+ _fields_ = [
15
+ ('nLength', DWORD),
16
+ ('lpSecurityDescriptor', LPVOID),
17
+ ('bInheritHandle', BOOL),
18
+ ]
19
+
20
+
21
+ assert sizeof(SECURITY_ATTRIBUTES) == 12 or sizeof(SECURITY_ATTRIBUTES) == 24, sizeof(SECURITY_ATTRIBUTES)
22
+ assert alignment(SECURITY_ATTRIBUTES) == 4 or alignment(SECURITY_ATTRIBUTES) == 8, alignment(SECURITY_ATTRIBUTES)
23
+
24
+ PAGE_READWRITE = win32con.PAGE_READWRITE
25
+ WAIT_TIMEOUT = win32con.WAIT_TIMEOUT
26
+ PROCESS_ALL_ACCESS = win32con.PROCESS_ALL_ACCESS
27
+ VIRTUAL_MEM = (win32con.MEM_RESERVE | win32con.MEM_COMMIT)
28
+ LPCSTR = LPCTSTR = c_char_p
29
+ LPWTSTR = c_wchar_p
30
+ LPDWORD = PDWORD = POINTER(DWORD)
31
+ LPTHREAD_START_ROUTINE = LPVOID
32
+ LPSECURITY_ATTRIBUTES = POINTER(SECURITY_ATTRIBUTES)
33
+
34
+ OpenProcess = windll.kernel32.OpenProcess
35
+ OpenProcess.restype = HANDLE
36
+ OpenProcess.argtypes = (DWORD, BOOL, DWORD)
37
+
38
+ VirtualAllocEx = windll.kernel32.VirtualAllocEx
39
+ VirtualAllocEx.restype = LPVOID
40
+ VirtualAllocEx.argtypes = (HANDLE, LPVOID, DWORD, DWORD, DWORD)
41
+
42
+ ReadProcessMemory = windll.kernel32.ReadProcessMemory
43
+ ReadProcessMemory.restype = BOOL
44
+ ReadProcessMemory.argtypes = (HANDLE, LPCVOID, LPVOID, DWORD, DWORD)
45
+
46
+ WriteProcessMemory = windll.kernel32.WriteProcessMemory
47
+ WriteProcessMemory.restype = BOOL
48
+ WriteProcessMemory.argtypes = (HANDLE, LPVOID, LPCVOID, DWORD, DWORD)
49
+
50
+ CreateRemoteThread = windll.kernel32.CreateRemoteThread
51
+ CreateRemoteThread.restype = HANDLE
52
+ CreateRemoteThread.argtypes = (HANDLE, LPSECURITY_ATTRIBUTES, DWORD, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD)
53
+
54
+ GetModuleHandleA = windll.kernel32.GetModuleHandleA
55
+ GetModuleHandleA.restype = HANDLE
56
+ GetModuleHandleA.argtypes = (LPCTSTR,)
57
+
58
+ LoadLibraryA = windll.kernel32.LoadLibraryA
59
+ LoadLibraryA.restype = HANDLE
60
+ LoadLibraryA.argtypes = (LPCTSTR,)
61
+
62
+ GetModuleHandleW = windll.kernel32.GetModuleHandleW
63
+ GetModuleHandleW.restype = HANDLE
64
+ GetModuleHandleW.argtypes = (LPWTSTR,)
65
+
66
+ LoadLibraryW = windll.kernel32.LoadLibraryW
67
+ LoadLibraryW.restype = HANDLE
68
+ LoadLibraryW.argtypes = (LPWTSTR,)
69
+
70
+ GetProcAddress = windll.kernel32.GetProcAddress
71
+ GetProcAddress.restype = LPVOID
72
+ GetProcAddress.argtypes = (HANDLE, LPCTSTR)
73
+
74
+ WaitForSingleObject = windll.kernel32.WaitForSingleObject
75
+ WaitForSingleObject.restype = DWORD
76
+ WaitForSingleObject.argtypes = (HANDLE, DWORD)
@@ -0,0 +1,69 @@
1
+ import pywintypes
2
+ import time
3
+ import win32file
4
+ import win32pipe
5
+ import winerror
6
+ import logging
7
+
8
+ logger = logging.getLogger(__package__)
9
+
10
+
11
+ class InjectedBrokenPipeError(Exception):
12
+ pass
13
+
14
+
15
+ class Pipe(object):
16
+ def __init__(self, name):
17
+ self.name = name
18
+ self.handle = None
19
+
20
+ def connect(self, n_attempts=30, delay=1):
21
+ for i in range(n_attempts):
22
+ try:
23
+ self.handle = win32file.CreateFile(
24
+ r'\\.\pipe\{}'.format(self.name),
25
+ win32file.GENERIC_READ | win32file.GENERIC_WRITE,
26
+ 0,
27
+ None,
28
+ win32file.OPEN_EXISTING,
29
+ 0,
30
+ None
31
+ )
32
+ win32pipe.SetNamedPipeHandleState(
33
+ self.handle,
34
+ win32pipe.PIPE_READMODE_MESSAGE | win32pipe.PIPE_WAIT,
35
+ None,
36
+ None,
37
+ )
38
+ logger.info('Connected to the pipe {}'.format(self.name))
39
+ break
40
+ except pywintypes.error as e:
41
+ if e.args[0] == winerror.ERROR_FILE_NOT_FOUND:
42
+ logger.warning('Attempt {}/{}: failed to connect to the pipe {}'.format(i + 1, n_attempts,
43
+ self.name))
44
+ time.sleep(delay)
45
+ else:
46
+ raise InjectedBrokenPipeError('Unexpected pipe error: {}'.format(e))
47
+ if self.handle is not None:
48
+ return True
49
+ return False
50
+
51
+ def transact(self, string):
52
+ try:
53
+ # TODO get preferred encoding from application
54
+ self.write(string, 'utf-8')
55
+ resp = win32file.ReadFile(self.handle, 64 * 1024)
56
+ return resp[1].decode('utf-8')
57
+ except pywintypes.error as e:
58
+ if e.args[0] == winerror.ERROR_BROKEN_PIPE:
59
+ raise InjectedBrokenPipeError("Broken pipe")
60
+ else:
61
+ raise InjectedBrokenPipeError('Unexpected pipe error: {}'.format(e))
62
+
63
+ def close(self):
64
+ win32file.CloseHandle(self.handle)
65
+
66
+ def write(self, string, encoding='utf-8'):
67
+ """Write string with the specified encoding to the named pipe."""
68
+ win32file.WriteFile(self.handle, string.encode(encoding))
69
+ win32file.FlushFileBuffers(self.handle)
@@ -0,0 +1,89 @@
1
+ import ctypes
2
+ import locale
3
+ import os
4
+
5
+ from . import sysinfo
6
+ from . import cfuncs
7
+
8
+
9
+ class Injector(object):
10
+ """Class for injections dll"""
11
+
12
+ def __init__(self, pid, backend_name, dll_name, is_unicode=False):
13
+ """Constructor inject dll (one application - one class instance)."""
14
+ self.is_unicode = is_unicode
15
+ self.pid = pid
16
+ if not sysinfo.is_x64_python() == sysinfo.is64_bitprocess(self.pid):
17
+ raise RuntimeError("Application and Python must be both 32-bit or both 64-bit")
18
+ self.h_process = self._get_process_handle(self.pid)
19
+
20
+ self.dll_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),
21
+ 'libs', backend_name,
22
+ 'x{}'.format("64" if sysinfo.is64_bitprocess(self.pid) else "86"),
23
+ '{}.dll'.format(dll_name)).encode('utf-16' if self.is_unicode
24
+ else locale.getpreferredencoding())
25
+ self._inject_dll_to_process()
26
+
27
+ @staticmethod
28
+ def _get_process_handle(pid):
29
+ return cfuncs.OpenProcess(cfuncs.PROCESS_ALL_ACCESS, False, pid)
30
+
31
+ def _create_remote_thread_with_timeout(self, proc_address, arg_address, timeout_ms=1000,
32
+ call_err_text="", timeout_err_text=""):
33
+ thread_handle = cfuncs.CreateRemoteThread(self.h_process, None, 0, proc_address, arg_address, 0, None)
34
+ if not thread_handle:
35
+ raise RuntimeError(call_err_text)
36
+ # TODO: add timeout to pywinauto timings and replace
37
+ ret = cfuncs.WaitForSingleObject(thread_handle, ctypes.wintypes.DWORD(timeout_ms))
38
+ if ret == cfuncs.WAIT_TIMEOUT:
39
+ raise TimeoutError(timeout_err_text)
40
+
41
+ def _inject_dll_to_process(self):
42
+ # Get dll path length
43
+ c_dll_path = ctypes.create_unicode_buffer(self.dll_path) \
44
+ if self.is_unicode else ctypes.create_string_buffer(self.dll_path)
45
+
46
+ # Allocate space for DLL path
47
+ arg_address = cfuncs.VirtualAllocEx(self.h_process, 0, ctypes.sizeof(c_dll_path),
48
+ cfuncs.VIRTUAL_MEM, cfuncs.PAGE_READWRITE)
49
+
50
+ # Write DLL path to allocated space
51
+ if not cfuncs.WriteProcessMemory(self.h_process, arg_address,
52
+ ctypes.byref(c_dll_path), ctypes.sizeof(c_dll_path), 0):
53
+ raise AttributeError("Couldn't write data to process memory, check python access.")
54
+
55
+ # Resolve LoadLibraryA(W) Address
56
+ h_kernel32 = cfuncs.GetModuleHandleW(b"kernel32.dll") \
57
+ if self.is_unicode else cfuncs.GetModuleHandleA(b"kernel32.dll")
58
+ h_loadlib = cfuncs.GetProcAddress(h_kernel32, b"LoadLibraryW" if self.is_unicode else b"LoadLibraryA")
59
+
60
+ # Now call createRemoteThread with entry point set to LoadLibraryA(W) and pointer to DLL path as param
61
+ self._create_remote_thread_with_timeout(h_loadlib, arg_address, 1000,
62
+ "Couldn't create remote thread, application and Python must be "
63
+ "both 32-bit or both 64-bit", "Inject time out")
64
+
65
+ def _get_dll_proc_address(self, proc_name):
66
+ lib = cfuncs.LoadLibraryW(self.dll_path) if self.is_unicode else cfuncs.LoadLibraryA(self.dll_path)
67
+ return cfuncs.GetProcAddress(lib, proc_name)
68
+
69
+ def remote_call_void_func(self, func_name):
70
+ proc_address = self._get_dll_proc_address(func_name)
71
+
72
+ if not cfuncs.CreateRemoteThread(self.h_process, None, 0, proc_address, 0, 0, None):
73
+ raise RuntimeError("Couldn't create remote thread, dll not injected, inject and try again!")
74
+
75
+ def remote_call_int_param_func(self, func_name, param):
76
+ # Resolve param type for different applications
77
+ a = ctypes.c_int64(param) if sysinfo.is64_bitprocess(self.pid) else ctypes.c_int32(param)
78
+
79
+ arg_address = cfuncs.VirtualAllocEx(self.h_process, 0, ctypes.sizeof(a),
80
+ cfuncs.VIRTUAL_MEM, cfuncs.PAGE_READWRITE)
81
+ if not cfuncs.WriteProcessMemory(self.h_process, arg_address, ctypes.byref(a), ctypes.sizeof(a), 0):
82
+ raise AttributeError("Couldn't write data to process memory, check python access.")
83
+
84
+ proc_address = self._get_dll_proc_address(func_name)
85
+
86
+ self._create_remote_thread_with_timeout(proc_address, arg_address, 1000,
87
+ "Couldn't create remote thread, dll not injected, "
88
+ "inject it and try again!",
89
+ "{0}(int) function call time out".format(func_name))
@@ -0,0 +1,61 @@
1
+ """Simple module for checking whether Python and Windows are 32-bit or 64-bit"""
2
+ import sys
3
+ import os
4
+ import platform
5
+ import ctypes
6
+ import win32process
7
+ import win32api
8
+ import win32con
9
+
10
+
11
+ def os_arch():
12
+ architecture_map = {
13
+ 'x86': 'x86',
14
+ 'i386': 'x86',
15
+ 'i486': 'x86',
16
+ 'i586': 'x86',
17
+ 'i686': 'x86',
18
+ 'x64': 'x86_64',
19
+ 'AMD64': 'x86_64',
20
+ 'amd64': 'x86_64',
21
+ 'em64t': 'x86_64',
22
+ 'EM64T': 'x86_64',
23
+ 'x86_64': 'x86_64',
24
+ 'IA64': 'ia64',
25
+ 'ia64': 'ia64'
26
+ }
27
+ if sys.platform == 'win32':
28
+ architecture_var = os.environ.get('PROCESSOR_ARCHITEW6432', '')
29
+ if architecture_var == '':
30
+ architecture_var = os.environ.get('PROCESSOR_ARCHITECTURE', '')
31
+ return architecture_map.get(architecture_var, 'Unknown')
32
+ else:
33
+ return architecture_map.get(platform.machine(), '')
34
+
35
+
36
+ def python_bitness():
37
+ return ctypes.sizeof(ctypes.POINTER(ctypes.c_int)) * 8
38
+
39
+
40
+ def is_x64_python():
41
+ return python_bitness() == 64
42
+
43
+
44
+ def is_x64_os():
45
+ return os_arch() in ['x86_64', 'ia64']
46
+
47
+
48
+ def is64_bitprocess(process_id):
49
+ """Return True if the specified process is a 64-bit one
50
+
51
+ Return False if it is only a 32-bit process running under Wow64.
52
+ Always return False for x86.
53
+ """
54
+
55
+ if is_x64_os():
56
+ phndl = win32api.OpenProcess(win32con.MAXIMUM_ALLOWED, 0, process_id)
57
+ if not phndl:
58
+ raise OSError(f'OpenProcess is failed for PID = {process_id}')
59
+ return not win32process.IsWow64Process(phndl)
60
+
61
+ return False
@@ -0,0 +1,42 @@
1
+ Metadata-Version: 2.4
2
+ Name: injectlib
3
+ Version: 0.0.1
4
+ Summary: A set of Python modules to inject DLLs into applications for the Microsoft Windows
5
+ Home-page: https://github.com/pywinauto/injectlib
6
+ Author: Vasily Ryabov, Ilya Naumov, Boris Galochkin, Alexander Makarov
7
+ Author-email: vasily.v.ryabov@gmail.com
8
+ License: BSD 3-clause
9
+ Keywords: windows gui .net inject testing test desktop dll wpf qt
10
+ Platform: win32
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: BSD License
15
+ Classifier: Operating System :: Microsoft :: Windows
16
+ Classifier: Programming Language :: Python
17
+ Classifier: Programming Language :: Python :: 3.7
18
+ Classifier: Programming Language :: Python :: 3.8
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: Implementation :: CPython
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Classifier: Topic :: Software Development :: Testing
25
+ Requires-Python: >=3.7
26
+ License-File: LICENSE
27
+ Requires-Dist: pywin32
28
+ Dynamic: author
29
+ Dynamic: author-email
30
+ Dynamic: classifier
31
+ Dynamic: description
32
+ Dynamic: home-page
33
+ Dynamic: keywords
34
+ Dynamic: license
35
+ Dynamic: license-file
36
+ Dynamic: platform
37
+ Dynamic: requires-dist
38
+ Dynamic: requires-python
39
+ Dynamic: summary
40
+
41
+
42
+ It allows to inject DLls into applications for the Microsoft Windows.
@@ -0,0 +1,26 @@
1
+ LICENSE
2
+ MANIFEST.in
3
+ README.md
4
+ setup.py
5
+ src/injectlib/__init__.py
6
+ src/injectlib/api.py
7
+ src/injectlib/cfuncs.py
8
+ src/injectlib/channel.py
9
+ src/injectlib/injector.py
10
+ src/injectlib/sysinfo.py
11
+ src/injectlib.egg-info/PKG-INFO
12
+ src/injectlib.egg-info/SOURCES.txt
13
+ src/injectlib.egg-info/dependency_links.txt
14
+ src/injectlib.egg-info/requires.txt
15
+ src/injectlib.egg-info/top_level.txt
16
+ src/injectlib/libs/dotnet/x64/Newtonsoft.Json.dll
17
+ src/injectlib/libs/dotnet/x64/bootstrap.dll
18
+ src/injectlib/libs/dotnet/x64/worker_wpf.dll
19
+ src/injectlib/libs/dotnet/x86/Newtonsoft.Json.dll
20
+ src/injectlib/libs/dotnet/x86/bootstrap.dll
21
+ src/injectlib/libs/dotnet/x86/worker_wpf.dll
22
+ src/injectlib/libs/hook/x64/pywinmsg64.dll
23
+ src/injectlib/libs/hook/x64/pywinmsg64u.dll
24
+ src/injectlib/libs/hook/x86/pywinmsg32.dll
25
+ src/injectlib/libs/hook/x86/pywinmsg32u.dll
26
+ src/injectlib/libs/qt/x64/qt_srv.dll
@@ -0,0 +1 @@
1
+ pywin32
@@ -0,0 +1 @@
1
+ injectlib