external-proc 0.1.0__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.
@@ -0,0 +1,172 @@
1
+ Metadata-Version: 2.4
2
+ Name: external_proc
3
+ Version: 0.1.0
4
+ Summary: pybind11 extension
5
+ Author: bananasss00
6
+ Author-email: bananasss00@yandex.com
7
+ Classifier: Operating System :: Microsoft :: Windows
8
+ Classifier: Programming Language :: Python :: 3.6
9
+ Classifier: Programming Language :: Python :: 3.7
10
+ Classifier: Programming Language :: Python :: 3.8
11
+ Classifier: Programming Language :: Python :: 3.9
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Requires: pybind11
17
+ Requires-Python: >=3.6,<4.0
18
+ Description-Content-Type: text/markdown
19
+ Dynamic: author
20
+ Dynamic: author-email
21
+ Dynamic: classifier
22
+ Dynamic: description
23
+ Dynamic: description-content-type
24
+ Dynamic: requires
25
+ Dynamic: requires-python
26
+ Dynamic: summary
27
+
28
+ # external_proc python module
29
+ ![Python Version](https://img.shields.io/pypi/pyversions/external-proc)
30
+ [![PYPI](https://img.shields.io/pypi/v/external-proc)](https://pypi.org/project/external-proc/)
31
+ [![Downloads](https://pepy.tech/badge/external-proc)](https://pepy.tech/project/external-proc)
32
+
33
+ ## External process memory manager
34
+
35
+ # Installation
36
+ Ensure you have at least Python 3.6+
37
+ ```
38
+ pip install external_proc
39
+ or
40
+ pip install git+https://github.com/bananasss00/external_proc.git
41
+ ```
42
+
43
+ # Usage examples
44
+ **More examples in 'tests' directory**
45
+
46
+ Open/Close process
47
+ ```python
48
+ from external_proc import *
49
+
50
+ p = ExtProcess.open(PROCESS_NAME or PROCESS_ID)
51
+ p.close()
52
+ ### or ###
53
+ with ExtProcess.ctx_open(PROCESS_NAME or PROCESS_ID) as p:
54
+ pass
55
+ ```
56
+
57
+ Read/Write values
58
+ ```python
59
+ with ExtProcess.ctx_open(process_name) as p:
60
+ # write
61
+ p.write.list_bytes(address, [0x90, 0x90])
62
+ p.write.bytes(address, b'\x90\x90')
63
+ p.write.str(address, 'string')
64
+ p.write.wstr(address, 'unicode string')
65
+ p.write.uint8(address, 1)
66
+ p.write.uint16(address, 1)
67
+ p.write.uint32(address, 1)
68
+ p.write.uint64(address, 1)
69
+ p.write.int8(address, -1)
70
+ p.write.int16(address, -1)
71
+ p.write.int32(address, -1)
72
+ p.write.int64(address, -1)
73
+ p.write.float(address, 0.01)
74
+ p.write.double(address, 0.01)
75
+ # read
76
+ v = p.read.list_bytes(address, BYTES_COUNT)
77
+ v = p.read.bytes(address, BYTES_COUNT)
78
+ v = p.read.str(address, MAX_BYTES_COUNT) # read string to first \x00
79
+ v = p.read.wstr(address, MAX_BYTES_COUNT) # read string to first \x00
80
+ v = p.read.uint8(address) # signed 1 byte value
81
+ v = p.read.uint16(address) # signed 2 byte value
82
+ v = p.read.uint32(address) # signed 4 byte value
83
+ v = p.read.uint64(address) # signed 8 byte value
84
+ v = p.read.int8(address) # unsigned 1 byte value
85
+ v = p.read.int16(address) # unsigned 2 byte value
86
+ v = p.read.int32(address) # unsigned 4 byte value
87
+ v = p.read.int64(address) # unsigned 8 byte value
88
+ v = p.read.float(address) # 4 byte
89
+ v = p.read.double(address) # 8 byte
90
+ ```
91
+
92
+ Pointers
93
+ ```python
94
+ # Pointer types:
95
+ # ListBytes
96
+ # Bytes
97
+ # Str
98
+ # Wstr
99
+ # Uint8
100
+ # Uint16
101
+ # Uint32
102
+ # Uint64
103
+ # Int8
104
+ # Int16
105
+ # Int32
106
+ # Int64
107
+ # Float
108
+ # Double
109
+ # Invalid
110
+ ptr = p.make_ptr(address, PtrType.Int32)
111
+ address = ptr.get_address() # return current address
112
+ ptr.set_value(333)
113
+ value = ptr.get_value()
114
+
115
+ # get address from multilevel pointers
116
+ ptr = p.make_ptr(0x6426E0, core.PtrType.Uint32)\
117
+ .go_ptr(0xC)\
118
+ .go_ptr(0x14)\
119
+ .go_ptr()\
120
+ .go_ptr(0x18)
121
+
122
+ # PtrTypes: ListBytes, Bytes, Str, Wstr
123
+ # require additional argument
124
+ # for get_value(BYTES_COUNT or MAX_BYTES_COUNT for strings)
125
+ ```
126
+
127
+
128
+ Simple dll injector x32/x64
129
+ ```python
130
+ with ExtProcess.ctx_open(process_name) as p:
131
+ dll_path = os.path.abspath('lib.dll')
132
+ loadlib_func = get_proc_address('kernel32', 'LoadLibraryA', x64=p.is_x64_process())
133
+ param = p.alloc()
134
+ p.write.str(param, dll_path)
135
+ with p.ctx_create_thread(loadlib, param, wait_thread=True) as th_id:
136
+ pass
137
+ ```
138
+
139
+ Signature scanner. IDA Style
140
+ ```python
141
+ exe_module = p.get_module()
142
+ client_module = p.get_module('client.dll')
143
+
144
+ # .text:00428873 8D 4D F0 lea ecx, [ebp+var_10]
145
+ # .text:00428876 E8 05 4E FE FF call 0x40D680
146
+
147
+ # E8 ? ? ? ? - it's instruction call 0x40D680
148
+ signature = "8D 4D F0 E8 ? ? ? ?"
149
+
150
+ # equal: find_pattern(signature) + 3
151
+ sig_in_all_module: Ptr = client_module.find_pattern(signature, add_offset=3)
152
+ sig_in_code_section: Ptr = client_module.section('.text').find_pattern(signature, 3)
153
+
154
+ # for read relative offset from call instruction you can simple do this
155
+ adr = sig_in_code_section.go_call_ptr().get_address()
156
+ # same for jmp, je and etc inctructions: .go_jmp_ptr(), .go_jmp_short_ptr()
157
+ ```
158
+
159
+
160
+ Shellcode injection. Using nasm(need add in to PATH environment variable directory with nasm.exe)
161
+ ```python
162
+ # CheatEngine Tutorial x64. Step 7: Code Injection: (PW=013370)
163
+ with ExtProcess.ctx_open('Tutorial-x86_64.exe') as t:
164
+ m = t.get_module()
165
+ code_decrement_health = 0x10002D4F7
166
+ new_code = t.alloc(2048, code_decrement_health) # alloc memory near 'code_decrement_health'
167
+ # for short relative jump!!!
168
+ t.virtual_protect(code_decrement_health, 7, PageFlags.PAGE_EXECUTE_READWRITE)
169
+ t.write.bytes(code_decrement_health, nasm(f'''jmp {hex(new_code)}\nnop\nnop''', 64, hex(code_decrement_health)))
170
+ t.write.bytes(new_code, nasm('''add dword [rsi+0x7E0], 0x2 ; +2 health instead -1
171
+ jmp qword 0x10002D4FE''', 64, new_code))
172
+ ```
@@ -0,0 +1,145 @@
1
+ # external_proc python module
2
+ ![Python Version](https://img.shields.io/pypi/pyversions/external-proc)
3
+ [![PYPI](https://img.shields.io/pypi/v/external-proc)](https://pypi.org/project/external-proc/)
4
+ [![Downloads](https://pepy.tech/badge/external-proc)](https://pepy.tech/project/external-proc)
5
+
6
+ ## External process memory manager
7
+
8
+ # Installation
9
+ Ensure you have at least Python 3.6+
10
+ ```
11
+ pip install external_proc
12
+ or
13
+ pip install git+https://github.com/bananasss00/external_proc.git
14
+ ```
15
+
16
+ # Usage examples
17
+ **More examples in 'tests' directory**
18
+
19
+ Open/Close process
20
+ ```python
21
+ from external_proc import *
22
+
23
+ p = ExtProcess.open(PROCESS_NAME or PROCESS_ID)
24
+ p.close()
25
+ ### or ###
26
+ with ExtProcess.ctx_open(PROCESS_NAME or PROCESS_ID) as p:
27
+ pass
28
+ ```
29
+
30
+ Read/Write values
31
+ ```python
32
+ with ExtProcess.ctx_open(process_name) as p:
33
+ # write
34
+ p.write.list_bytes(address, [0x90, 0x90])
35
+ p.write.bytes(address, b'\x90\x90')
36
+ p.write.str(address, 'string')
37
+ p.write.wstr(address, 'unicode string')
38
+ p.write.uint8(address, 1)
39
+ p.write.uint16(address, 1)
40
+ p.write.uint32(address, 1)
41
+ p.write.uint64(address, 1)
42
+ p.write.int8(address, -1)
43
+ p.write.int16(address, -1)
44
+ p.write.int32(address, -1)
45
+ p.write.int64(address, -1)
46
+ p.write.float(address, 0.01)
47
+ p.write.double(address, 0.01)
48
+ # read
49
+ v = p.read.list_bytes(address, BYTES_COUNT)
50
+ v = p.read.bytes(address, BYTES_COUNT)
51
+ v = p.read.str(address, MAX_BYTES_COUNT) # read string to first \x00
52
+ v = p.read.wstr(address, MAX_BYTES_COUNT) # read string to first \x00
53
+ v = p.read.uint8(address) # signed 1 byte value
54
+ v = p.read.uint16(address) # signed 2 byte value
55
+ v = p.read.uint32(address) # signed 4 byte value
56
+ v = p.read.uint64(address) # signed 8 byte value
57
+ v = p.read.int8(address) # unsigned 1 byte value
58
+ v = p.read.int16(address) # unsigned 2 byte value
59
+ v = p.read.int32(address) # unsigned 4 byte value
60
+ v = p.read.int64(address) # unsigned 8 byte value
61
+ v = p.read.float(address) # 4 byte
62
+ v = p.read.double(address) # 8 byte
63
+ ```
64
+
65
+ Pointers
66
+ ```python
67
+ # Pointer types:
68
+ # ListBytes
69
+ # Bytes
70
+ # Str
71
+ # Wstr
72
+ # Uint8
73
+ # Uint16
74
+ # Uint32
75
+ # Uint64
76
+ # Int8
77
+ # Int16
78
+ # Int32
79
+ # Int64
80
+ # Float
81
+ # Double
82
+ # Invalid
83
+ ptr = p.make_ptr(address, PtrType.Int32)
84
+ address = ptr.get_address() # return current address
85
+ ptr.set_value(333)
86
+ value = ptr.get_value()
87
+
88
+ # get address from multilevel pointers
89
+ ptr = p.make_ptr(0x6426E0, core.PtrType.Uint32)\
90
+ .go_ptr(0xC)\
91
+ .go_ptr(0x14)\
92
+ .go_ptr()\
93
+ .go_ptr(0x18)
94
+
95
+ # PtrTypes: ListBytes, Bytes, Str, Wstr
96
+ # require additional argument
97
+ # for get_value(BYTES_COUNT or MAX_BYTES_COUNT for strings)
98
+ ```
99
+
100
+
101
+ Simple dll injector x32/x64
102
+ ```python
103
+ with ExtProcess.ctx_open(process_name) as p:
104
+ dll_path = os.path.abspath('lib.dll')
105
+ loadlib_func = get_proc_address('kernel32', 'LoadLibraryA', x64=p.is_x64_process())
106
+ param = p.alloc()
107
+ p.write.str(param, dll_path)
108
+ with p.ctx_create_thread(loadlib, param, wait_thread=True) as th_id:
109
+ pass
110
+ ```
111
+
112
+ Signature scanner. IDA Style
113
+ ```python
114
+ exe_module = p.get_module()
115
+ client_module = p.get_module('client.dll')
116
+
117
+ # .text:00428873 8D 4D F0 lea ecx, [ebp+var_10]
118
+ # .text:00428876 E8 05 4E FE FF call 0x40D680
119
+
120
+ # E8 ? ? ? ? - it's instruction call 0x40D680
121
+ signature = "8D 4D F0 E8 ? ? ? ?"
122
+
123
+ # equal: find_pattern(signature) + 3
124
+ sig_in_all_module: Ptr = client_module.find_pattern(signature, add_offset=3)
125
+ sig_in_code_section: Ptr = client_module.section('.text').find_pattern(signature, 3)
126
+
127
+ # for read relative offset from call instruction you can simple do this
128
+ adr = sig_in_code_section.go_call_ptr().get_address()
129
+ # same for jmp, je and etc inctructions: .go_jmp_ptr(), .go_jmp_short_ptr()
130
+ ```
131
+
132
+
133
+ Shellcode injection. Using nasm(need add in to PATH environment variable directory with nasm.exe)
134
+ ```python
135
+ # CheatEngine Tutorial x64. Step 7: Code Injection: (PW=013370)
136
+ with ExtProcess.ctx_open('Tutorial-x86_64.exe') as t:
137
+ m = t.get_module()
138
+ code_decrement_health = 0x10002D4F7
139
+ new_code = t.alloc(2048, code_decrement_health) # alloc memory near 'code_decrement_health'
140
+ # for short relative jump!!!
141
+ t.virtual_protect(code_decrement_health, 7, PageFlags.PAGE_EXECUTE_READWRITE)
142
+ t.write.bytes(code_decrement_health, nasm(f'''jmp {hex(new_code)}\nnop\nnop''', 64, hex(code_decrement_health)))
143
+ t.write.bytes(new_code, nasm('''add dword [rsi+0x7E0], 0x2 ; +2 health instead -1
144
+ jmp qword 0x10002D4FE''', 64, new_code))
145
+ ```
@@ -0,0 +1,8 @@
1
+ from external_proc._external_proc import *
2
+ from external_proc.external_proc import *
3
+ import external_proc._external_proc as core
4
+
5
+
6
+ PyException = core.PyException
7
+ RequiredValueSizeArgument = core.RequiredValueSizeArgument
8
+ UnknownPtrType = core.UnknownPtrType
@@ -0,0 +1,220 @@
1
+ from typing import Tuple, Union, List, Iterator, ContextManager, Any, NoReturn, Literal
2
+ import external_proc._external_proc as core
3
+ from enum import Enum
4
+
5
+
6
+ def get_last_error() -> int:
7
+ pass
8
+
9
+ class PtrType(Enum):
10
+ ListBytes = 0
11
+ Bytes = 1
12
+ Str = 2
13
+ Wstr = 3
14
+ Uint8 = 4
15
+ Uint16 = 5
16
+ Uint32 = 6
17
+ Uint64 = 7
18
+ Int8 = 8
19
+ Int16 = 9
20
+ Int32 = 10
21
+ Int64 = 11
22
+ Float = 12
23
+ Double = 13
24
+ Invalid = 14
25
+
26
+ class Ptr:
27
+ def __init__(self, process: 'Process', ptr: int, type: PtrType):
28
+ pass
29
+
30
+ def is_valid(self) -> bool:
31
+ pass
32
+
33
+ def is_memory_readable(self) -> bool:
34
+ pass
35
+
36
+ def set_ptr_type(self, type: PtrType) -> Ptr:
37
+ pass
38
+
39
+ def get_value(self, value_size: int = 0) -> Union[str, int, bytes]:
40
+ pass
41
+
42
+ def set_value(self, value) -> bool:
43
+ pass
44
+
45
+ def get_address(self) -> int:
46
+ '''
47
+
48
+ :return: address
49
+ '''
50
+ pass
51
+
52
+ def go_ptr(self, add_offset: int = 0) -> Ptr:
53
+ pass
54
+
55
+ def go_relative_ptr(self, instruction_offset: int, instruction_size: int, relative_adr_size: Literal[1, 2, 4, 8], add_offset: int = 0) -> Ptr:
56
+ pass
57
+
58
+ def go_call_ptr(self, add_offset: int = 0) -> Ptr:
59
+ pass
60
+
61
+ def go_jmp_ptr(self, add_offset: int = 0) -> Ptr:
62
+ pass
63
+
64
+ def go_jmp_short_ptr(self, add_offset: int = 0) -> Ptr:
65
+ pass
66
+
67
+
68
+ class PeSection:
69
+ # !not have ctor!
70
+ def __init__(self):
71
+ self.base: int = None
72
+ self.size: int = None
73
+
74
+ def is_valid(self) -> bool:
75
+ pass
76
+
77
+ def find_pattern(self, signature: str, add_offset: int = 0) -> Ptr:
78
+ pass
79
+
80
+
81
+ class ProcessModule:
82
+ # !not have ctor!
83
+ def __init__(self):
84
+ self.base: int = None
85
+ self.size: int = None
86
+
87
+ def is_valid(self) -> bool:
88
+ pass
89
+
90
+ def find_pattern(self, signature: str, add_offset: int = 0) -> Ptr:
91
+ pass
92
+
93
+ def section(self, name: str) -> PeSection:
94
+ pass
95
+
96
+
97
+ class Reader:
98
+ def __init__(self, process_handle: int):
99
+ pass
100
+ def relative_offset_to_absolute(self, instruction_address: int, relative_adr_offset: int, instruction_size: int, relative_adr_size: int) -> int:
101
+ pass
102
+ def list_bytes(self, address: int, size: int) -> List[int]:
103
+ pass
104
+ def bytes(self, address: int, size: int) -> bytes:
105
+ pass
106
+ def str(self, address: int, max_size: int) -> str:
107
+ pass
108
+ def wstr(self, address: int, max_size: int) -> str:
109
+ pass
110
+ def uint8(self, address: int) -> int:
111
+ pass
112
+ def uint16(self, address: int) -> int:
113
+ pass
114
+ def uint32(self, address: int) -> int:
115
+ pass
116
+ def uint64(self, address: int) -> int:
117
+ pass
118
+ def int8(self, address: int) -> int:
119
+ pass
120
+ def int16(self, address: int) -> int:
121
+ pass
122
+ def int32(self, address: int) -> int:
123
+ pass
124
+ def int64(self, address: int) -> int:
125
+ pass
126
+ def float(self, address: int) -> float:
127
+ pass
128
+ def double(self, address: int) -> double:
129
+ pass
130
+
131
+
132
+ class Writer:
133
+ def __init__(self, process_handle: int):
134
+ pass
135
+ def list_bytes(self, address: int, bytes: list[int]) -> bool:
136
+ pass
137
+ def bytes(self, address: int, bytes: bytes) -> bool:
138
+ pass
139
+ def str(self, address: int, string: str) -> bool:
140
+ pass
141
+ def wstr(self, address: int, string: str) -> bool:
142
+ pass
143
+ def uint8(self, address: int, value: int) -> bool:
144
+ pass
145
+ def uint16(self, address: int, value: int) -> bool:
146
+ pass
147
+ def uint32(self, address: int, value: int) -> bool:
148
+ pass
149
+ def uint64(self, address: int, value: int) -> bool:
150
+ pass
151
+ def int8(self, address: int, value: int) -> bool:
152
+ pass
153
+ def int16(self, address: int, value: int) -> bool:
154
+ pass
155
+ def int32(self, address: int, value: int) -> bool:
156
+ pass
157
+ def int64(self, address: int, value: int) -> bool:
158
+ pass
159
+ def float(self, address: int, value: float) -> bool:
160
+ pass
161
+ def double(self, address: int, value: double) -> bool:
162
+ pass
163
+
164
+ class Process:
165
+ def __init__(self, process_id_or_name: Union[int, str]):
166
+ self.read: Reader = None
167
+ self.write: Writer = None
168
+ self._process_handle = None
169
+ pass
170
+ def is_valid(self) -> bool:
171
+ pass
172
+ def close(self) -> NoReturn:
173
+ pass
174
+ # @staticmethod
175
+ # def open_by_id(id: int) -> Process:
176
+ # pass
177
+ # @staticmethod
178
+ # def open_by_name(process_name: str) -> list[Process]:
179
+ # pass
180
+ @staticmethod
181
+ def get_process_id(process_name: str) -> int:
182
+ pass
183
+ @staticmethod
184
+ def get_process_ids(pprocess_name: str) -> List[int]:
185
+ pass
186
+ def open_process(self, process_id: int) -> NoReturn:
187
+ pass
188
+ def close_handle(self, handle: int) -> NoReturn:
189
+ pass
190
+ def get_module(self, name: str = '') -> ProcessModule:
191
+ '''
192
+
193
+ :param name: if empty used main module(process name)
194
+ :return: ProcessModule
195
+ '''
196
+ pass
197
+ def get_exe_name(self) -> str:
198
+ pass
199
+ def alloc(self, size: int = 4096, address: int = 0, fl_protect: int = core.PAGE_EXECUTE_READWRITE) -> int:
200
+ pass
201
+ def free(self, address: int) -> bool:
202
+ pass
203
+ def virtual_protect(self, address: int, size: int, flags: int) -> int:
204
+ pass
205
+ def create_thread(self, address: int, parameter: int = 0) -> int:
206
+ pass
207
+ def wait_for_single_object(self, handle: int):
208
+ pass
209
+ def get_pe_section(self, module_ptr: int, section_name: str) -> PeSection:
210
+ pass
211
+ def is_x64_process(self) -> bool:
212
+ pass
213
+ def find_pattern(self, scan_start: int, scan_end: int, signature: str, add_offset: int = 0) -> Ptr:
214
+ pass
215
+ def make_ptr(self, address: int, type: PtrType, value_size: int = 0) -> Ptr:
216
+ pass
217
+ def is_memory_readable(self, address: int) -> bool:
218
+ pass
219
+
220
+