injectlib 0.0.1__py2.py3-none-any.whl

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.
injectlib/__init__.py ADDED
File without changes
injectlib/api.py ADDED
@@ -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
injectlib/cfuncs.py ADDED
@@ -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)
injectlib/channel.py ADDED
@@ -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)
injectlib/injector.py ADDED
@@ -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))
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
injectlib/sysinfo.py ADDED
@@ -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,22 @@
1
+ injectlib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ injectlib/api.py,sha256=JjHgMkUptTZ50MD9iZyYLO6SgmdypAIIs9Kemc-EyVk,2620
3
+ injectlib/cfuncs.py,sha256=Q4xgmRJwrcFF44QXg3ASP1IyUdzTJY0Buabq0lPeJLs,2700
4
+ injectlib/channel.py,sha256=DUGmQAEPWypptNgmI9YTBqkWpVN51hoRCuIq-Vij-sA,2487
5
+ injectlib/injector.py,sha256=qvSd7SBCHbBu8rzuNcupVYy29vAdGRwCEB7Q8agID8U,4854
6
+ injectlib/sysinfo.py,sha256=yNGGlU1GYWiavJWpo41DZyB1jfXl-63zTeRBZGoAEe4,1641
7
+ injectlib/libs/dotnet/x64/Newtonsoft.Json.dll,sha256=tiSUnfiw46YVP9-3MKfG9JkLZZLuDZIuF4hDPSdmEPM,701992
8
+ injectlib/libs/dotnet/x64/bootstrap.dll,sha256=C7Wzdc5IZCThvCVqK43heK6XjJnWQjIu8nh52ilcyH8,33280
9
+ injectlib/libs/dotnet/x64/worker_wpf.dll,sha256=FIyXcT1AAnoVCOzSYE6plM58qSzawoFWi4Oo7stxR78,44032
10
+ injectlib/libs/dotnet/x86/Newtonsoft.Json.dll,sha256=tiSUnfiw46YVP9-3MKfG9JkLZZLuDZIuF4hDPSdmEPM,701992
11
+ injectlib/libs/dotnet/x86/bootstrap.dll,sha256=gIZm6b0SRUSrta-2cMeBtaq5uHkhqf-Z4cmqj5zw5f4,26112
12
+ injectlib/libs/dotnet/x86/worker_wpf.dll,sha256=O37VXoHzxUK3YSdfBIsFyTJMrgbx2bGy2pgbuJ_-EiQ,44544
13
+ injectlib/libs/hook/x64/pywinmsg64.dll,sha256=kzQoE6evywmIOhI7On--ntISTKBgHVRplfQNJ9kpqmA,20480
14
+ injectlib/libs/hook/x64/pywinmsg64u.dll,sha256=0Yi3QsnbZJkEKLk8tzgWZEHtTL4LRZqtScd4rGcnVGg,45056
15
+ injectlib/libs/hook/x86/pywinmsg32.dll,sha256=G1JidmQK4wNDHDeF5DtgjERg_tmMyIaDWmTpvy2IHmA,36864
16
+ injectlib/libs/hook/x86/pywinmsg32u.dll,sha256=4vbB3lQXGny6zy9P-6hSyMzSPT8NAv1ERew_KsJ2Tfg,36864
17
+ injectlib/libs/qt/x64/qt_srv.dll,sha256=7EAldJ48u2uTtzR3A501yXU943UJvHVj4CeqCcGfbRI,76288
18
+ injectlib-0.0.1.dist-info/licenses/LICENSE,sha256=WzT-MnvTQkd_NDKvfKi7ZiDYosFzqKfEt_rWh7oxPg4,1650
19
+ injectlib-0.0.1.dist-info/METADATA,sha256=5SeppRdVeLQzS5oV6PcGc4zggKfK0vOw5LKxUk28uy4,1562
20
+ injectlib-0.0.1.dist-info/WHEEL,sha256=TdQ5LtNwLuxTCjgxN51AgdU5w-KkB9ttmLbzjTH02pg,109
21
+ injectlib-0.0.1.dist-info/top_level.txt,sha256=_cnZuwXRGkD8hyZ8IT3_9k6_k8DZQe4fQejUz1KaBUM,10
22
+ injectlib-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,6 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py2-none-any
5
+ Tag: py3-none-any
6
+
@@ -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 @@
1
+ injectlib