ntmemoryapi 1.0.0__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.
- ntmemoryapi/__init__.py +918 -0
- ntmemoryapi/embed.py +1130 -0
- ntmemoryapi/misc.py +102 -0
- ntmemoryapi-1.0.0.dist-info/METADATA +14 -0
- ntmemoryapi-1.0.0.dist-info/RECORD +6 -0
- ntmemoryapi-1.0.0.dist-info/WHEEL +4 -0
ntmemoryapi/misc.py
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# +-------------------------------------+
|
|
2
|
+
# | ~ Author : Xenely ~ |
|
|
3
|
+
# +=====================================+
|
|
4
|
+
# | GitHub: https://github.com/Xenely14 |
|
|
5
|
+
# | Discord: xenely |
|
|
6
|
+
# +-------------------------------------+
|
|
7
|
+
|
|
8
|
+
import ctypes
|
|
9
|
+
import struct
|
|
10
|
+
import typing
|
|
11
|
+
import ctypes.wintypes
|
|
12
|
+
|
|
13
|
+
# ==-------------------------------------------------------------------== #
|
|
14
|
+
# DLL functions #
|
|
15
|
+
# ==-------------------------------------------------------------------== #
|
|
16
|
+
|
|
17
|
+
# DLL libraries loading
|
|
18
|
+
_kernel32 = ctypes.windll.kernel32
|
|
19
|
+
|
|
20
|
+
# DLL libraries functions loading
|
|
21
|
+
_LoadLibraryA = _kernel32.LoadLibraryA
|
|
22
|
+
_GetProcAddress = _kernel32.GetProcAddress
|
|
23
|
+
_VirtualProtect = _kernel32.VirtualProtect
|
|
24
|
+
|
|
25
|
+
# Define of DLL libraries functions return type
|
|
26
|
+
_LoadLibraryA.restype = ctypes.wintypes.LPVOID
|
|
27
|
+
_GetProcAddress.restype = ctypes.wintypes.LPVOID
|
|
28
|
+
_VirtualProtect.restype = ctypes.wintypes.BOOL
|
|
29
|
+
|
|
30
|
+
# Define of DLL libraries functions argument types
|
|
31
|
+
_LoadLibraryA .argtypes = [ctypes.wintypes.LPCSTR]
|
|
32
|
+
_GetProcAddress.argtypes = [ctypes.wintypes.LPVOID, ctypes.wintypes.LPCSTR]
|
|
33
|
+
_VirtualProtect.argtypes = [ctypes.wintypes.LPVOID, ctypes.c_size_t, ctypes.wintypes.DWORD, ctypes.POINTER(ctypes.wintypes.DWORD)]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# ==-------------------------------------------------------------------== #
|
|
37
|
+
# Functions #
|
|
38
|
+
# ==-------------------------------------------------------------------== #
|
|
39
|
+
def syscall(nt_function_name: str, *, result_type: typing.Any, arguments_types: list[typing.Any], module: bytes = b"ntdll.dll") -> ctypes.WINFUNCTYPE:
|
|
40
|
+
"""Finds function in DLL module by it name, retrieves it's syscall ID, wraps it into raw function buffer and casts to `WINFUNCTYPE` to make call shadowed."""
|
|
41
|
+
|
|
42
|
+
# Module loading
|
|
43
|
+
if not (module_handle := _LoadLibraryA(module)):
|
|
44
|
+
raise Exception("Unable to load module `%s`" % module.decode())
|
|
45
|
+
|
|
46
|
+
# Retrieve nt-function pointer
|
|
47
|
+
if not (nt_function := _GetProcAddress(module_handle, nt_function_name.encode())):
|
|
48
|
+
raise Exception("Function `%s` not found" % nt_function_name)
|
|
49
|
+
|
|
50
|
+
offset = 0
|
|
51
|
+
syscall_id = None
|
|
52
|
+
|
|
53
|
+
# Retrieve syscall ID from nt-function pointer
|
|
54
|
+
while True:
|
|
55
|
+
|
|
56
|
+
# Syscall ID not found
|
|
57
|
+
if offset > 0x16:
|
|
58
|
+
break
|
|
59
|
+
|
|
60
|
+
# Retrieve syscall ID from memory
|
|
61
|
+
if ctypes.cast(nt_function + offset, ctypes.POINTER(ctypes.c_ubyte)).contents.value == 0xB8:
|
|
62
|
+
syscall_id = ctypes.cast(nt_function + offset + 1, ctypes.POINTER(ctypes.c_ushort)).contents.value
|
|
63
|
+
break
|
|
64
|
+
|
|
65
|
+
offset += 1
|
|
66
|
+
|
|
67
|
+
# Syscall ID not found
|
|
68
|
+
if syscall_id is None:
|
|
69
|
+
raise Exception("Syscall ID for function `%s` not found" % nt_function_name)
|
|
70
|
+
|
|
71
|
+
# Convert syscall ID to hex-bytes list
|
|
72
|
+
syscall_id_bytes = [hex(item)[2:] if len(hex(item)[2:]) == 2 else "0" + hex(item)[2:] for item in struct.pack("<h", syscall_id)]
|
|
73
|
+
|
|
74
|
+
# NOTE: I actually don't know why does this code require access `gs` segment.
|
|
75
|
+
# I've just used this repo as reference: https://github.com/opcode86/SysCaller
|
|
76
|
+
#
|
|
77
|
+
# mov rax, gs:[0x60]
|
|
78
|
+
# mov r10, rcx
|
|
79
|
+
# mov eax, <syscall id>,
|
|
80
|
+
# syscall
|
|
81
|
+
# ret
|
|
82
|
+
shellcode = bytes.fromhex("""
|
|
83
|
+
65 48 8B 04 25 60 00
|
|
84
|
+
00 00
|
|
85
|
+
4C 8B D1
|
|
86
|
+
B8 %s %s 00 00
|
|
87
|
+
0F 05
|
|
88
|
+
C3
|
|
89
|
+
""" % tuple([*syscall_id_bytes]))
|
|
90
|
+
|
|
91
|
+
# Allocate buffer for function machine code
|
|
92
|
+
buffer = (ctypes.c_uint8 * len(shellcode))()
|
|
93
|
+
shellcode_buffer = ctypes.cast(buffer, ctypes.c_void_p)
|
|
94
|
+
|
|
95
|
+
# Copy shellcode into function machine code buffer
|
|
96
|
+
ctypes.memmove(shellcode_buffer, ctypes.create_string_buffer(shellcode, len(shellcode)), len(shellcode))
|
|
97
|
+
|
|
98
|
+
# Update of function machine code buffer memory protection to make it executable
|
|
99
|
+
ctypes.windll.kernel32.VirtualProtect(shellcode_buffer, len(shellcode), 0x40, ctypes.wintypes.LPDWORD(ctypes.wintypes.DWORD()))
|
|
100
|
+
|
|
101
|
+
# Return wrapped syscall function
|
|
102
|
+
return ctypes.cast(shellcode_buffer, ctypes.WINFUNCTYPE(result_type, *arguments_types))
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: ntmemoryapi
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Simple library for Windows to manipulate process virtual memory with stelthy syscall wraps
|
|
5
|
+
Author: Xenely
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
ntmemoryapi/__init__.py,sha256=K8YAkx1OKyniDeEkv0u2Ydf89mOE5lL9kDFLkCWDMGo,38893
|
|
2
|
+
ntmemoryapi/embed.py,sha256=CQXFDPwHZDoouMSxveng8YL_PWjyhQsw1akdUEjXnCk,113455
|
|
3
|
+
ntmemoryapi/misc.py,sha256=pG_O8EzddXRNADTYfDPOMUiHwKrxeGGMeJhlAV1xkRQ,4168
|
|
4
|
+
ntmemoryapi-1.0.0.dist-info/METADATA,sha256=sy0rvsFy4r4lyH8-sTtV2sERFaTNoLhV_Q4lJBT6Z0Q,488
|
|
5
|
+
ntmemoryapi-1.0.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
6
|
+
ntmemoryapi-1.0.0.dist-info/RECORD,,
|