-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathInjector.py
More file actions
283 lines (203 loc) · 8.97 KB
/
Injector.py
File metadata and controls
283 lines (203 loc) · 8.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
#! /usr/bin/python
"""
Performs DLL injection on a Windows process. Methods are
provided to support two techniques, either injection of the
library path into the process and execution using LoadLibraryA,
or injection of the entire DLL itself.
"""
from ctypes import *
from ctypes.wintypes import *
from sys import stderr
import os
class Injector:
# Import the required Windows DLLs
# PSAPI.DLL
# psapi = windll.psapi
# Kernel32.DLL
__kernel = windll.kernel32
# Flags
# PROCESS_QUERY_INFORMATION = 0x0400
# PROCESS_VM_READ = 0x0010
# __MEM_COMMIT = 0x00001000
# __PAGE_EXECUTE_WRITECOPY = 0x80
def get_proc_handle(self, pid):
"""
Returns a handle to the process
specified by the process ID
:param pid: The process ID
:return: A handle to the process, if it can
be obtained
"""
# Obtain a handle to the process with the
# specified ID
h_process = self.__kernel.OpenProcess(self.__kernel.PROCESS_QUERY_INFORMATION |
self.__kernel.PROCESS_VM_READ |
self.__kernel.PROCESS_CREATE_THREAD |
self.__kernel.PROCESS_VM_OPERATION |
self.__kernel.PROCESS_VM_WRITE |,
False, pid)
if not h_process:
print("Could not obtain process handle!", file=stderr)
# TODO Raise an exception here
return h_process
def get_dll_handle(self, dll_path):
"""
Returns a handle to the DLL specified by the
DLL path string
:param dll_path: The path of the DLL
:return: A handle to the DLL, if it can be obtained
"""
# TODO Check that a valid path has been supplied
# Open a handle to the DLL to be injected
h_dll = self.__kernel.CreateFileA(dll_path,
self.__kernel.GENERIC_READ,
0,
None,
self.__kernel.OPEN_EXISTING,
self.__kernel.FILE_ATTRIBUTE_NORMAL,
None);
return h_dll
def write_path_into_process_memory(self, h_process, dll_path):
"""
Writes the specified DLL path to the process memory, after
allocating enough memory.
:param h_process: A handle to the process to
which we are writing
:param dll_path: The DLL path that is to be written
to the process memory
:return: Either success (nonzero) or failure (zero)
"""
# Establish the length of the DLL path
# TODO Check that a valid path has been supplied
__dw_size = c_size_t(len(dll_path))
__base_address = \
self.__kernel.VirtualAllocEx(h_process, 0,
self.__dw_size,
self.__kernel.MEM_COMMIT,
self.__kernel.PAGE_EXECUTE_WRITECOPY)
if __base_address:
# Establish the length of the DLL path
__dw_size = c_size_t(len(dll_path))
# Set up output parameter to hold number of bytes written
__num_bytes_written = c_size_t()
__success = self.__kernel.WriteProcessMemory(h_process, 0,
dll_path, __dw_size,
byref(__num_bytes_written))
# This will only succeed if we wrote the entire DLL
if __num_bytes_written != len(dll_path):
__success = 0
print("Could not write all path bytes to process address space",
file=stderr)
else:
__success == 0
return __success
def write_dll_into_process_memory(self, h_process, dll_path):
"""
Writes the specified DLL to the process memory.
:param h_process: A handle to the process to
which we are writing
:param dll_path: The path of the DLL that is to be written
to the process memory
:return: Either success (nonzero) or failure (zero)
"""
# TODO Check that a valid path has been supplied
h_dll = self.get_dll_handle(dll_path)
if h_dll:
# Establish the size of the DLL
dll_size = os.path.getsize(h_dll);
__dw_size = c_size_t(dll_size)
__base_address = \
self.__kernel.VirtualAllocEx(h_process, 0,
self.__dw_size,
self.__kernel.MEM_COMMIT,
self.__kernel.PAGE_EXECUTE_WRITECOPY)
if __base_address:
# Read DLL into a buffer before copying to remote
# process
# TODO
# Copy into process memory
# First, set up output parameter to hold number of bytes written
__num_bytes_written = c_size_t()
# TODO
# This will only succeed if we wrote the entire DLL
if __num_bytes_written != dll_size:
__success = 0
print("Could not write all DLL bytes to process address space",
file=stderr)
else:
__success = 0
return __success
def start_new_thread(self, h_process, base_address):
""""""
# Resolve the location of the LoadLibraryA function
h_kernel = self.__kernel.GetModuleHandleA("kernel32.dll")
load_lib_addr = self.__kernel.GetProcAddress(h_kernel, "LoadLibraryA")
# Set thread flag for immediate execution,
# i.e. do not create in suspended state
__dw_creation_flags = DWORD(0)
# Create a thread with default security attributes,
# default thread stack size, ,
__h_thread = self.__kernel.CreateRemoteThread(h_process, None,
0, load_lib_addr,
base_address,
__dw_creation_flags,
None)
if not __h_thread:
print("Could not obtain thread handle!", file=stderr)
# TODO Raise an exception here
return __h_thread
def release(self, h_process):
"""
Release the process handle.
:param h_process: The handle to be released
:return: Either success (nonzero) or failure (zero)
"""
return self.__kernel.CloseHandle(h_process)
def inject_using_path(self, pid, dll_path):
"""
Loads the path of the DLL to be injected into the
target process, then causes the target to load that
DLL from the specified path
:param pid: The process ID of the process into
which we are injecting
:param dll_path: The path of the DLL that we are going
to inject
:return: Zero for unsuccessful, non-zero for success
"""
success = 0
# Obtain a handle to the process we wish to examine
h_process = self.get_proc_handle(pid)
# Allocate enough memory in the process
# to accommodate the DLL
base_address = self.allocate_process_memory(h_process, dll_path)
if base_address:
# Write the DLL to the allocated memory
success = self.write_process_memory(h_process, dll_path)
if success:
# Create remote thread within injected process
# and start executing the DLL
self.start_new_thread(h_process, base_address)
# Release the handle
success = self.release(h_process)
if not success:
print("Could not release handle")
return success
def inject_directly(self, pid, dll_path):
"""
Directly loads the DLL into the target process
before executing it.
:param pid: The process ID of the process into
which we are injecting
:param dll_path: The path of the DLL that we are going
to inject
:return: Zero for unsuccessful, non-zero for success
"""
# TODO
if __name__ == "__main__":
# ID of the process into which we are injecting
pid = 100
# Path to DLL to be injected
# TODO Find suitable DLL to inject
dll_path = "c:\\"
injector = Injector()
injector.inject_using_path(pid, dll_path)