ntmemoryapi 1.1.0__tar.gz → 1.2.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: ntmemoryapi
3
- Version: 1.1.0
3
+ Version: 1.2.0
4
4
  Summary: Simple library for Windows to manipulate process virtual memory with stelthy syscall wraps
5
5
  Author: Xenely
6
6
  Requires-Python: >=3.10
@@ -9,6 +9,7 @@ Classifier: Programming Language :: Python :: 3.10
9
9
  Classifier: Programming Language :: Python :: 3.11
10
10
  Classifier: Programming Language :: Python :: 3.12
11
11
  Classifier: Programming Language :: Python :: 3.13
12
+ Requires-Dist: psutil (>=7.1.0,<8.0.0)
12
13
  Description-Content-Type: text/markdown
13
14
 
14
15
 
@@ -7,6 +7,7 @@
7
7
 
8
8
  import os
9
9
  import ctypes
10
+ import psutil
10
11
 
11
12
  # Local imports
12
13
  from .misc import *
@@ -83,35 +84,6 @@ class OBJECT_ATTRIBUTES(ctypes.Structure):
83
84
  ]
84
85
 
85
86
 
86
- class PROCESSENTRY32(ctypes.Structure):
87
- """Process entry structure for processes enumeration."""
88
-
89
- _fields_ = [
90
- ("dw_size", ctypes.c_ulong),
91
- ("cnt_usage", ctypes.c_ulong),
92
- ("th32_process_id", ctypes.c_ulong),
93
- ("th32_default_heap_id", ctypes.c_void_p),
94
- ("th32_module_id", ctypes.c_ulong),
95
- ("cnt_threads", ctypes.c_ulong),
96
- ("th32_parent_process_id", ctypes.c_ulong),
97
- ("pc_pri_class_base", ctypes.c_long),
98
- ("dw_flags", ctypes.c_ulong),
99
- ("sz_exe_file", ctypes.c_char * 260)
100
- ]
101
-
102
- @property
103
- def pid(self) -> int:
104
- """Process ID."""
105
-
106
- return self.th32_process_id
107
-
108
- @property
109
- def name(self) -> str:
110
- """Process name."""
111
-
112
- return self.sz_exe_file.decode()
113
-
114
-
115
87
  class MODULEENTRY32(ctypes.Structure):
116
88
  """Module entry structure, describes an entry from a list of the modules belonging to the specified process."""
117
89
 
@@ -254,61 +226,43 @@ _nt_protect_virtual_memory = syscall("NtProtectVirtualMemory", result_type=ctype
254
226
  # ==-------------------------------------------------------------------== #
255
227
  # Functions #
256
228
  # ==-------------------------------------------------------------------== #
257
- def list_processes(include_id: bool = True, include_name: bool = True) -> list[dict[str, int | str]]:
229
+ def list_processes(include_id: bool = True, include_name: bool = True, include_username: bool = True, current_username_only: bool = True) -> list[dict[str, int | str]]:
258
230
  """List all of the currently active system processes."""
259
231
 
260
232
  # If `include_id` and `include_name` disabled both
261
233
  if not include_id and not include_name:
262
234
  raise Exception("Unable to disable ID and name including at once")
263
235
 
264
- # Process snapshot functions
265
- close_handle = ctypes.windll.kernel32.CloseHandle
266
- process32_next = ctypes.windll.kernel32.Process32Next
267
- process32_first = ctypes.windll.kernel32.Process32First
268
- create_tool_help32_snapshot = ctypes.windll.kernel32.CreateToolhelp32Snapshot
269
-
270
- # Create snapshot to iterate processes
271
- if (snapshot := create_tool_help32_snapshot(TH32CS_SNAPPROCESS, 0)) == -1:
272
- raise Exception("Unable to create snapshot to iterate processes")
236
+ # Current process username
237
+ current_username = psutil.Process().username()
273
238
 
274
239
  # Result list of processes
275
240
  processes = list()
276
241
 
277
- # Process enumeration
278
- try:
279
-
280
- # Process entry to iterate processes
281
- process_entry = PROCESSENTRY32()
282
- process_entry.dw_size = ctypes.sizeof(PROCESSENTRY32)
283
-
284
- # Retrieve first process snapshot
285
- if not process32_first(snapshot, ctypes.byref(process_entry)):
286
- raise Exception("Unable to get first process to save to snapshot")
242
+ # Process iteration
243
+ for process in psutil.process_iter():
287
244
 
288
- # Iterate all of the processes using snapshot
289
- while True:
290
-
291
- # Save process to list
292
- process_dict = dict()
245
+ # If process started not from current username
246
+ if current_username_only and process.username() != current_username:
247
+ continue
293
248
 
294
- # If process ID including required
295
- if include_id:
296
- process_dict |= {"id": process_entry.pid}
249
+ # Save process to list
250
+ process_dict = dict()
297
251
 
298
- # If process ID including required
299
- if include_name:
300
- process_dict |= {"name": process_entry.name}
252
+ # If process ID including required
253
+ if include_id:
254
+ process_dict |= {"id": process.pid}
301
255
 
302
- processes.append(process_dict)
303
-
304
- # Snapshot is over
305
- if not process32_next(snapshot, ctypes.byref(process_entry)):
306
- break
256
+ # If process ID including required
257
+ if include_name:
258
+ process_dict |= {"name": process.name()}
307
259
 
308
- finally:
260
+ # If process username including required
261
+ if include_username:
262
+ process_dict |= {"username": process.username()}
309
263
 
310
- # Close snapshot handle
311
- close_handle(snapshot)
264
+ # Save process information to list
265
+ processes.append(process_dict)
312
266
 
313
267
  return processes
314
268
 
@@ -323,17 +277,17 @@ class Process:
323
277
  # Methods #
324
278
  # ==-------------------------------------------------------------------== #
325
279
 
326
- def __init__(self, pid_or_name: int | str, access: int = PROCESS_ALL_ACCESS) -> None:
280
+ def __init__(self, pid_or_name: int | str, access: int = PROCESS_ALL_ACCESS, current_username_only: bool = True) -> None:
327
281
  """Initialize instance to manipulate process."""
328
282
 
329
283
  # Open process by it's ID or it's name
330
284
  match pid_or_name:
331
285
 
332
286
  case pid if type(pid_or_name) is int:
333
- self.handle, self.name, self.pid = self.__init_with_pid(pid, access)
287
+ self.handle, self.name, self.pid = self.__init_with_pid(pid, access, current_username_only)
334
288
 
335
289
  case name if type(pid_or_name) is str:
336
- self.handle, self.name, self.pid = self.__init_with_name(name, access)
290
+ self.handle, self.name, self.pid = self.__init_with_name(name, access, current_username_only)
337
291
 
338
292
  case _:
339
293
  raise Exception("Invalid `pid_or_name` argument value, have to be `int` or `str` type")
@@ -874,11 +828,11 @@ class Process:
874
828
  # ==-------------------------------------------------------------------== #
875
829
  # Private methods #
876
830
  # ==-------------------------------------------------------------------== #
877
- def __init_with_pid(self, pid: int, access: int, process_name: str | None = None) -> int:
831
+ def __init_with_pid(self, pid: int, access: int, current_username_only: bool, process_name: str | None = None) -> int:
878
832
  """Open process handle by it's ID with desired access."""
879
833
 
880
834
  # Iterate all of the processes if name not defined
881
- for process in list_processes():
835
+ for process in list_processes(current_username_only):
882
836
 
883
837
  # If process have a reqired name
884
838
  if process["id"] == pid:
@@ -908,14 +862,14 @@ class Process:
908
862
 
909
863
  return handle.value, process_name, pid
910
864
 
911
- def __init_with_name(self, name: str, access: int) -> int:
865
+ def __init_with_name(self, name: str, access: int, current_username_only: bool) -> int:
912
866
  """Open process hanle by it's name with desired access."""
913
867
 
914
868
  # Iterate all of the processes using snapshot
915
- for process in list_processes():
869
+ for process in list_processes(current_username_only):
916
870
 
917
871
  # If process have a reqired name
918
872
  if process["name"].lower() == name.strip().lower():
919
- return self.__init_with_pid(process["id"], access, process["name"])
873
+ return self.__init_with_pid(process["id"], access, current_username_only, process["name"])
920
874
 
921
875
  raise Exception("Process with `%s` name not found" % name)
@@ -1,14 +1,18 @@
1
1
  [project]
2
2
  name = "ntmemoryapi"
3
- version = "1.1.0"
3
+ version = "1.2.0"
4
4
  description = "Simple library for Windows to manipulate process virtual memory with stelthy syscall wraps"
5
5
  authors = [
6
6
  {name = "Xenely"}
7
7
  ]
8
8
  readme = "README.md"
9
9
  requires-python = ">=3.10"
10
- dependencies = []
10
+ dependencies = [
11
+ "psutil (>=7.1.0,<8.0.0)"
12
+ ]
11
13
 
12
14
  [build-system]
13
- requires = ["poetry-core>=2.0.0,<3.0.0"]
14
15
  build-backend = "poetry.core.masonry.api"
16
+ requires = [
17
+ "poetry-core>=2.0.0,<3.0.0"
18
+ ]
File without changes