Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
ubruhin committed Mar 17, 2024
1 parent d781005 commit 6ae6de4
Showing 1 changed file with 29 additions and 30 deletions.
59 changes: 29 additions & 30 deletions server/funq_server/runner_win.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
# knowledge of the CeCILL v2.1 license and that you accept its terms.

from funq_server.runner import RunnerInjector
from ctypes import windll, wintypes, byref
from ctypes import wintypes, byref
import ctypes
import time

Expand All @@ -42,7 +42,7 @@
#
# - https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-best-practices # noqa: E501
# - https://blog.nettitude.com/uk/dll-injection-part-two
# - https://stackoverflow.com/questions/17392721/error-invalid-parameter-error-57-when-calling-createremotethread-with-python-3-2/17524073#17524073
# - https://stackoverflow.com/questions/17392721/error-invalid-parameter-error-57-when-calling-createremotethread-with-python-3-2/17524073#17524073 # noqa: E501
# - https://stackoverflow.com/questions/27332509/createremotethread-on-loadlibrary-and-get-the-hmodule-back # noqa: E501
# - https://github.com/numaru/injector

Expand All @@ -66,7 +66,7 @@ def start_subprocess(self):
# too early, it does not work 100% reliable (in rare cases, the
# process freezes or crashes). When slightly delaying the injection,
# it seems to work more reliable. One seconds seems to be a safe
# choice to also make it reliable if the system is very busy. #
# choice to also make it reliable if the system is very busy.
# Hopefully someone finds a better way some day (without delay)...
time.sleep(1.0)

Expand Down Expand Up @@ -146,41 +146,40 @@ def _inject_dll(self, pid, dll_path):

# Start the injection.
size = (len(dll_path) + 1) * ctypes.sizeof(wintypes.WCHAR)
process_handle = None
path_address = None
thread_handle = None
h_process = None
adr_path = None
h_thread = None
try:
# Get handle to the running process.
process_handle = kernel32.OpenProcess(
h_process = kernel32.OpenProcess(
PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION |
PROCESS_VM_WRITE, False, pid)
if process_handle is None:
self._raise_windows_error("OpenProcess()", process_handle)
if h_process is None:
self._raise_windows_error("OpenProcess()", h_process)

# Allocate memory for the DLL path.
path_address = kernel32.VirtualAllocEx(
process_handle, None, size, MEM_COMMIT | MEM_RESERVE,
adr_path = kernel32.VirtualAllocEx(
h_process, None, size, MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE)
if path_address is None:
self._raise_windows_error("VirtualAllocEx()", path_address)
if adr_path is None:
self._raise_windows_error("VirtualAllocEx()", adr_path)

# Write DLL path into the allocated memory region.
success = kernel32.WriteProcessMemory(
process_handle, path_address, dll_path, size, None)
h_process, adr_path, dll_path, size, None)
if not success:
self._raise_windows_error("WriteProcessMemory()", success)

# Create and start new thread in the process. The entry point of the
# new thread is LoadLibraryW() with our DLL path as argument.
thread_handle = kernel32.CreateRemoteThread(
process_handle, None, 0, kernel32.LoadLibraryW, path_address,
0, None)
if thread_handle is None:
self._raise_windows_error("CreateRemoteThread()", thread_handle)
# Create and start new thread in the process. The entry point of
# the new thread is LoadLibraryW() with our DLL path as argument.
h_thread = kernel32.CreateRemoteThread(
h_process, None, 0, kernel32.LoadLibraryW, adr_path, 0, None)
if h_thread is None:
self._raise_windows_error("CreateRemoteThread()", h_thread)

# Wait (with 10s timeout) until the thread exited, i.e. our DLL
# injection either succeeded or failed.
error = kernel32.WaitForSingleObject(thread_handle, 10000)
error = kernel32.WaitForSingleObject(h_thread, 10000)
if error:
self._raise_windows_error("WaitForSingleObject()", error)

Expand All @@ -189,25 +188,25 @@ def _inject_dll(self, pid, dll_path):
# successfully or not.
libfunq_handle = wintypes.DWORD(0)
success = kernel32.GetExitCodeThread(
thread_handle, byref(libfunq_handle))
h_thread, byref(libfunq_handle))
if not success:
self._raise_windows_error("GetExitCodeThread()", success)
if not libfunq_handle:
self._raise_windows_error("LoadLibraryW()", libfunq_handle)
finally:
if path_address is not None:
success = kernel32.VirtualFreeEx(process_handle, path_address,
0, MEM_RELEASE)
if adr_path is not None:
success = kernel32.VirtualFreeEx(h_process, adr_path, 0,
MEM_RELEASE)
if not success:
self._raise_windows_error("VirtualFreeEx()", success)

if thread_handle is not None:
success = kernel32.CloseHandle(thread_handle)
if h_thread is not None:
success = kernel32.CloseHandle(h_thread)
if not success:
self._raise_windows_error("CloseHandle()", success)

if process_handle is not None:
success = kernel32.CloseHandle(process_handle)
if h_process is not None:
success = kernel32.CloseHandle(h_process)
if not success:
self._raise_windows_error("CloseHandle()", success)

Expand Down

0 comments on commit 6ae6de4

Please sign in to comment.