ntmemoryapi 2.0.2__tar.gz → 2.1.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: 2.0.2
3
+ Version: 2.1.0
4
4
  Summary: Simple library for Windows to manipulate process virtual memory with stelthy syscall wraps
5
5
  Author: Xenely
6
6
  Requires-Dist: psutil>=7.1.3
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ntmemoryapi"
3
- version = "2.0.2"
3
+ version = "2.1.0"
4
4
  description = "Simple library for Windows to manipulate process virtual memory with stelthy syscall wraps"
5
5
  authors = [
6
6
  {name = "Xenely"}
@@ -12,6 +12,7 @@ import psutil
12
12
  # Local imports
13
13
  from .misc import *
14
14
  from .embed import *
15
+ from .errors import *
15
16
 
16
17
  # ==-------------------------------------------------------------------== #
17
18
  # Static and global variables, constans #
@@ -76,7 +77,7 @@ class CLIENT_ID(ctypes.Structure):
76
77
 
77
78
  _fields_ = [
78
79
  ("unique_process", ctypes.c_void_p),
79
- ("unique_thread", ctypes.c_void_p)
80
+ ("unique_thread", ctypes.c_void_p),
80
81
  ]
81
82
 
82
83
 
@@ -89,7 +90,7 @@ class OBJECT_ATTRIBUTES(ctypes.Structure):
89
90
  ("object_name", ctypes.c_void_p),
90
91
  ("attributes", ctypes.c_ulong),
91
92
  ("security_descriptor", ctypes.c_void_p),
92
- ("security_quality_of_service", ctypes.c_void_p)
93
+ ("security_quality_of_service", ctypes.c_void_p),
93
94
  ]
94
95
 
95
96
 
@@ -106,7 +107,7 @@ class MODULEENTRY32(ctypes.Structure):
106
107
  ("mod_base_size", ctypes.c_ulong),
107
108
  ("h_module", ctypes.c_void_p),
108
109
  ("sz_module", ctypes.c_char * 256),
109
- ("sz_exe_path", ctypes.c_char * 260)
110
+ ("sz_exe_path", ctypes.c_char * 260),
110
111
  ]
111
112
 
112
113
  @property
@@ -241,8 +242,8 @@ def list_processes(include_process_information: int = PROCESS_ID | PROCESS_NAME)
241
242
  """List all of the currently active system processes."""
242
243
 
243
244
  # If `include_id` and `include_name` disabled both
244
- if not include_process_information & PROCESS_ID and not include_process_information & PROCESS_NAME:
245
- raise Exception("Unable to disable ID and name including at once")
245
+ if not (include_process_information & (PROCESS_ID | PROCESS_NAME)):
246
+ raise ValueError("Unable to disable ID and name including at once")
246
247
 
247
248
  # Result list of processes
248
249
  processes = []
@@ -251,18 +252,18 @@ def list_processes(include_process_information: int = PROCESS_ID | PROCESS_NAME)
251
252
  for process in psutil.process_iter():
252
253
 
253
254
  # Save process to list
254
- process_dict = {}
255
+ process_info = {}
255
256
 
256
257
  # If process ID including required
257
258
  if include_process_information & PROCESS_ID:
258
- process_dict |= {"id": process.pid}
259
+ process_info["id"] = process.pid
259
260
 
260
261
  # If process ID including required
261
262
  if include_process_information & PROCESS_NAME:
262
- process_dict |= {"name": process.name()}
263
+ process_info["name"] = process.name()
263
264
 
264
265
  # Save process information to list
265
- processes.append(process_dict)
266
+ processes.append(process_info)
266
267
 
267
268
  return processes
268
269
 
@@ -287,10 +288,9 @@ def _get_be_buffer(soure_c_type: typing.Any) -> ctypes.BigEndianStructure:
287
288
  class Process:
288
289
  """Basic class of process, have methods to manipulate it."""
289
290
 
290
- # ==-------------------------------------------------------------------== #
291
- # Methods #
292
- # ==-------------------------------------------------------------------== #
293
-
291
+ # ==--------------------------------== #
292
+ # Public methods #
293
+ # ==--------------------------------== #
294
294
  def __init__(self, name_or_pid: str | int, access: int = PROCESS_ALL_ACCESS) -> None:
295
295
  """Initialize instance to manipulate process."""
296
296
 
@@ -304,12 +304,12 @@ class Process:
304
304
  self.handle, self.pid, self.name = self.__init_with_pid(name_or_pid, access)
305
305
 
306
306
  case _:
307
- raise Exception("Invalid `name_or_pid` argument value, have to be `int` or `str` type")
307
+ raise OpenProcessError("Invalid `name_or_pid` argument value, have to be `int` or `str` type")
308
308
 
309
309
  # Try create file at temp directory to load SIMD KMP .dll (Module to blazingly fast pattern scaning)
310
310
  try:
311
311
 
312
- # Write library bytes directry from python list
312
+ # Write library bytes directly from python list
313
313
  with open("%s\\simdkmp.dll" % (appdata := os.getenv("APPDATA")), "wb") as file:
314
314
  file.write(bytes(embed.kmp))
315
315
 
@@ -330,7 +330,7 @@ class Process:
330
330
 
331
331
  # Create snapshot to iterate process modules
332
332
  if (snapshot := create_tool_help32_snapshot(TH32CS_SNAPMODULE, self.pid)) == -1:
333
- raise Exception("Unable to create snapshot to iterate process modules")
333
+ raise ctypes.WinError(descr="Unable to create snapshot for `%s` PID" % self.pid)
334
334
 
335
335
  # Result list of process modules
336
336
  process_modules = []
@@ -344,7 +344,7 @@ class Process:
344
344
 
345
345
  # Retrieve first process module snapshot
346
346
  if not module32_first(snapshot, ctypes.byref(modules_entry)):
347
- raise Exception("Unable to get first process module to save to snapshot")
347
+ raise ctypes.WinError(descr="Unable to get first proces module to save to snapshot for `%s` PID" % self.pid)
348
348
 
349
349
  # Iterate all of the process modules using snapshot
350
350
  while True:
@@ -387,7 +387,7 @@ class Process:
387
387
  break
388
388
 
389
389
  else:
390
- raise Exception("NtVirtualQueryMemory failed with status: 0x%s" % hex(result)[2:].upper())
390
+ raise NtError("NtVirtualQueryMemory failed with status: 0x%s" % hex(result)[2:].upper())
391
391
 
392
392
  # Move to next memory region
393
393
  if (next_address := current_address + memory_basic_information.size) <= current_address:
@@ -424,7 +424,7 @@ class Process:
424
424
  if module.name.lower() == name.strip().lower():
425
425
  return module
426
426
 
427
- raise Exception("Module with `%s` name not found" % name)
427
+ raise ValueError("Module with `%s` name not found" % name)
428
428
 
429
429
  def get_memory_region(self, address: int) -> MEMORY_BASIC_INFORMATION:
430
430
  """Get memory region information located at given address."""
@@ -434,7 +434,7 @@ class Process:
434
434
 
435
435
  # Try to get memory region information using it's address
436
436
  if (result := _nt_virtual_query_memory(self.handle, address, 0, ctypes.byref(memory_basic_information), ctypes.sizeof(memory_basic_information), None)):
437
- raise Exception("NtVirtualQueryMemory failed with status: 0x%s" % hex(result)[2:].upper())
437
+ raise NtError("NtVirtualQueryMemory failed with status: 0x%s" % hex(result)[2:].upper())
438
438
 
439
439
  return memory_basic_information
440
440
 
@@ -446,7 +446,7 @@ class Process:
446
446
 
447
447
  # Try to query process information
448
448
  if (result := _nt_query_information_process(self.handle, 26, ctypes.byref(wow64_info), ctypes.sizeof(wow64_info), ctypes.byref(ctypes.c_ulong()))):
449
- raise Exception("NtQueryInformationProcess failed with status: 0x%s" % hex(result)[2:].upper())
449
+ raise NtError("NtQueryInformationProcess failed with status: 0x%s" % hex(result)[2:].upper())
450
450
 
451
451
  return wow64_info.value is None
452
452
 
@@ -459,7 +459,7 @@ class Process:
459
459
 
460
460
  # Try to allocate process memory
461
461
  if (result := _nt_allocate_virtual_memory(self.handle, ctypes.byref(allocation_address), 0, ctypes.byref(allocation_size), memory_type, memory_protect)):
462
- raise Exception("NtAllocateVirtualMemory failed with status: 0x%s" % hex(result)[2:].upper())
462
+ raise NtError("NtAllocateVirtualMemory failed with status: 0x%s" % hex(result)[2:].upper())
463
463
 
464
464
  return allocation_address.value or 0, allocation_size.value or 0
465
465
 
@@ -472,7 +472,7 @@ class Process:
472
472
 
473
473
  # Try to deallocate process memory
474
474
  if (result := _nt_free_virtual_memory(self.handle, ctypes.byref(allocation_address), ctypes.byref(allocation_size), memory_type)):
475
- raise Exception("NtFreeVirtualMemory failed with status: 0x%s" % hex(result)[2:].upper())
475
+ raise NtError("NtFreeVirtualMemory failed with status: 0x%s" % hex(result)[2:].upper())
476
476
 
477
477
  return allocation_size.value or 0
478
478
 
@@ -485,7 +485,7 @@ class Process:
485
485
 
486
486
  # Try to change memory protection
487
487
  if (result := _nt_protect_virtual_memory(self.handle, ctypes.byref(protect_address), ctypes.byref(protect_size), memory_protect, ctypes.byref(memory_old_protect := ctypes.c_ulong()))):
488
- raise Exception("NtProtectVirtualMemory failed with status: 0x%s" % hex(result)[2:].upper())
488
+ raise NtError("NtProtectVirtualMemory failed with status: 0x%s" % hex(result)[2:].upper())
489
489
 
490
490
  return memory_old_protect.value or 0
491
491
 
@@ -493,7 +493,7 @@ class Process:
493
493
  """Scan process and return address that validates given pattern hex byte mask, use `??` to wildcard byte, for example - "14 00 00 00 DB FF ?? ?? FF FF 00 00"."""
494
494
 
495
495
  # Validate given pattern
496
- for byte in pattern.strip().split():
496
+ for byte in pattern.lower().strip().split():
497
497
 
498
498
  # If pattern byte is not wildcard and valid
499
499
  if len(byte) == 2 and [item in "0123456789ABCDEFabcdef" for item in byte].count(True) == 2:
@@ -503,7 +503,7 @@ class Process:
503
503
  if byte == "??":
504
504
  continue
505
505
 
506
- raise Exception("Invalid pattern: `%s`" % pattern)
506
+ raise ValueError("Invalid pattern: `%s`" % pattern)
507
507
 
508
508
  # Result list of found addresses
509
509
  found_addresses = []
@@ -562,7 +562,7 @@ class Process:
562
562
 
563
563
  # If result failed
564
564
  if (result := _nt_read_virtual_memory(self.handle, address, ctypes.byref(buffer := ctypes.c_int8()), ctypes.sizeof(buffer), None)):
565
- raise Exception("NtReadVirtualMemory failed with status: 0x%s" % hex(result)[2:].upper())
565
+ raise MemoryReadError(result, address)
566
566
 
567
567
  return buffer.value
568
568
 
@@ -571,7 +571,7 @@ class Process:
571
571
 
572
572
  # If result failed
573
573
  if (result := _nt_read_virtual_memory(self.handle, address, ctypes.byref(buffer := _get_be_buffer(ctypes.c_int16)() if big_endian else ctypes.c_int16()), ctypes.sizeof(buffer), None)):
574
- raise Exception("NtReadVirtualMemory failed with status: 0x%s" % hex(result)[2:].upper())
574
+ raise MemoryReadError(result, address)
575
575
 
576
576
  return buffer.value
577
577
 
@@ -580,7 +580,7 @@ class Process:
580
580
 
581
581
  # If result failed
582
582
  if (result := _nt_read_virtual_memory(self.handle, address, ctypes.byref(buffer := _get_be_buffer(ctypes.c_int32)() if big_endian else ctypes.c_int32()), ctypes.sizeof(buffer), None)):
583
- raise Exception("NtReadVirtualMemory failed with status: 0x%s" % hex(result)[2:].upper())
583
+ raise MemoryReadError(result, address)
584
584
 
585
585
  return buffer.value
586
586
 
@@ -589,7 +589,7 @@ class Process:
589
589
 
590
590
  # If result failed
591
591
  if (result := _nt_read_virtual_memory(self.handle, address, ctypes.byref(buffer := _get_be_buffer(ctypes.c_int64)() if big_endian else ctypes.c_int64()), ctypes.sizeof(buffer), None)):
592
- raise Exception("NtReadVirtualMemory failed with status: 0x%s" % hex(result)[2:].upper())
592
+ raise MemoryReadError(result, address)
593
593
 
594
594
  return buffer.value
595
595
 
@@ -598,7 +598,7 @@ class Process:
598
598
 
599
599
  # If result failed
600
600
  if (result := _nt_read_virtual_memory(self.handle, address, ctypes.byref(buffer := ctypes.c_uint8()), ctypes.sizeof(buffer), None)):
601
- raise Exception("NtReadVirtualMemory failed with status: 0x%s" % hex(result)[2:].upper())
601
+ raise MemoryReadError(result, address)
602
602
 
603
603
  return buffer.value
604
604
 
@@ -607,7 +607,7 @@ class Process:
607
607
 
608
608
  # If result failed
609
609
  if (result := _nt_read_virtual_memory(self.handle, address, ctypes.byref(buffer := _get_be_buffer(ctypes.c_uint16)() if big_endian else ctypes.c_uint16()), ctypes.sizeof(buffer), None)):
610
- raise Exception("NtReadVirtualMemory failed with status: 0x%s" % hex(result)[2:].upper())
610
+ raise MemoryReadError(result, address)
611
611
 
612
612
  return buffer.value
613
613
 
@@ -616,7 +616,7 @@ class Process:
616
616
 
617
617
  # If result failed
618
618
  if (result := _nt_read_virtual_memory(self.handle, address, ctypes.byref(buffer := _get_be_buffer(ctypes.c_uint32)() if big_endian else ctypes.c_uint32()), ctypes.sizeof(buffer), None)):
619
- raise Exception("NtReadVirtualMemory failed with status: 0x%s" % hex(result)[2:].upper())
619
+ raise MemoryReadError(result, address)
620
620
 
621
621
  return buffer.value
622
622
 
@@ -625,7 +625,7 @@ class Process:
625
625
 
626
626
  # If result failed
627
627
  if (result := _nt_read_virtual_memory(self.handle, address, ctypes.byref(buffer := _get_be_buffer(ctypes.c_uint64)() if big_endian else ctypes.c_uint64()), ctypes.sizeof(buffer), None)):
628
- raise Exception("NtReadVirtualMemory failed with status: 0x%s" % hex(result)[2:].upper())
628
+ raise MemoryReadError(result, address)
629
629
 
630
630
  return buffer.value
631
631
 
@@ -634,7 +634,7 @@ class Process:
634
634
 
635
635
  # If result failed
636
636
  if (result := _nt_read_virtual_memory(self.handle, address, ctypes.byref(buffer := _get_be_buffer(ctypes.c_float)() if big_endian else ctypes.c_float()), ctypes.sizeof(buffer), None)):
637
- raise Exception("NtReadVirtualMemory failed with status: 0x%s" % hex(result)[2:].upper())
637
+ raise MemoryReadError(result, address)
638
638
 
639
639
  return buffer.value
640
640
 
@@ -643,7 +643,7 @@ class Process:
643
643
 
644
644
  # If result failed
645
645
  if (result := _nt_read_virtual_memory(self.handle, address, ctypes.byref(buffer := _get_be_buffer(ctypes.c_double)() if big_endian else ctypes.c_double()), ctypes.sizeof(buffer), None)):
646
- raise Exception("NtReadVirtualMemory failed with status: 0x%s" % hex(result)[2:].upper())
646
+ raise MemoryReadError(result, address)
647
647
 
648
648
  return buffer.value
649
649
 
@@ -652,7 +652,7 @@ class Process:
652
652
 
653
653
  # If result failed
654
654
  if (result := _nt_read_virtual_memory(self.handle, address, ctypes.byref(buffer := _get_be_buffer(ctypes.c_int8 * size)() if big_endian else (ctypes.c_int8 * size)()), ctypes.sizeof(buffer), None)):
655
- raise Exception("NtReadVirtualMemory failed with status: 0x%s" % hex(result)[2:].upper())
655
+ raise MemoryReadError(result, address)
656
656
 
657
657
  return bytes(buffer)
658
658
 
@@ -661,7 +661,7 @@ class Process:
661
661
 
662
662
  # If result failed
663
663
  if (result := _nt_read_virtual_memory(self.handle, address, ctypes.byref(buffer), ctypes.sizeof(buffer), None)):
664
- raise Exception("NtReadVirtualMemory failed with status: 0x%s" % hex(result)[2:].upper())
664
+ raise MemoryReadError(result, address)
665
665
 
666
666
  return buffer
667
667
 
@@ -670,42 +670,42 @@ class Process:
670
670
 
671
671
  # If result failed
672
672
  if (result := _nt_write_virtual_memory(self.handle, address, ctypes.byref(buffer := ctypes.c_int8(value)), ctypes.sizeof(buffer), None)):
673
- raise Exception("NtWriteVirtualMemory failed with status: 0x%s" % hex(result)[2:].upper())
673
+ raise MemoryWriteError(result, address)
674
674
 
675
675
  def write_int16(self, address: int, value: int, big_endian: bool = False) -> None:
676
676
  """Write 2 byte signed integer value at given address."""
677
677
 
678
678
  # If result failed
679
679
  if (result := _nt_write_virtual_memory(self.handle, address, ctypes.byref(buffer := _get_be_buffer(ctypes.c_int16(value)) if big_endian else ctypes.c_int16(value)), ctypes.sizeof(buffer), None)):
680
- raise Exception("NtWriteVirtualMemory failed with status: 0x%s" % hex(result)[2:].upper())
680
+ raise MemoryWriteError(result, address)
681
681
 
682
682
  def write_int32(self, address: int, value: int, big_endian: bool = False) -> None:
683
683
  """Write 4 byte signed integer value at given address."""
684
684
 
685
685
  # If result failed
686
686
  if (result := _nt_write_virtual_memory(self.handle, address, ctypes.byref(buffer := _get_be_buffer(ctypes.c_int32(value)) if big_endian else ctypes.c_int32(value)), ctypes.sizeof(buffer), None)):
687
- raise Exception("NtWriteVirtualMemory failed with status: 0x%s" % hex(result)[2:].upper())
687
+ raise MemoryWriteError(result, address)
688
688
 
689
689
  def write_int64(self, address: int, value: int, big_endian: bool = False) -> None:
690
690
  """Write 8 byte signed integer value at given address."""
691
691
 
692
692
  # If result failed
693
693
  if (result := _nt_write_virtual_memory(self.handle, address, ctypes.byref(buffer := _get_be_buffer(ctypes.c_int64(value)) if big_endian else ctypes.c_int64(value)), ctypes.sizeof(buffer), None)):
694
- raise Exception("NtWriteVirtualMemory failed with status: 0x%s" % hex(result)[2:].upper())
694
+ raise MemoryWriteError(result, address)
695
695
 
696
696
  def write_uint8(self, address: int, value: int) -> None:
697
697
  """Write 1 byte unsigned integer value at given address."""
698
698
 
699
699
  # If result failed
700
700
  if (result := _nt_write_virtual_memory(self.handle, address, ctypes.byref(buffer := ctypes.c_uint8(value)), ctypes.sizeof(buffer), None)):
701
- raise Exception("NtWriteVirtualMemory failed with status: 0x%s" % hex(result)[2:].upper())
701
+ raise MemoryWriteError(result, address)
702
702
 
703
703
  def write_uint16(self, address: int, value: int, big_endian: bool = False) -> None:
704
704
  """Write 2 byte unsigned integer value at given address."""
705
705
 
706
706
  # If result failed
707
707
  if (result := _nt_write_virtual_memory(self.handle, address, ctypes.byref(buffer := _get_be_buffer(ctypes.c_uint16(value)) if big_endian else ctypes.c_uint16(value)), ctypes.sizeof(buffer), None)):
708
- raise Exception("NtWriteVirtualMemory failed with status: 0x%s" % hex(result)[2:].upper())
708
+ raise MemoryWriteError(result, address)
709
709
 
710
710
  def write_uint32(self, address: int, value: int, big_endian: bool = False) -> None:
711
711
  """Write 4 byte unsigned integer value at given address."""
@@ -719,35 +719,35 @@ class Process:
719
719
 
720
720
  # If result failed
721
721
  if (result := _nt_write_virtual_memory(self.handle, address, ctypes.byref(buffer := _get_be_buffer(ctypes.c_uint64(value)) if big_endian else ctypes.c_uint64(value)), ctypes.sizeof(buffer), None)):
722
- raise Exception("NtWriteVirtualMemory failed with status: 0x%s" % hex(result)[2:].upper())
722
+ raise MemoryWriteError(result, address)
723
723
 
724
724
  def write_float32(self, address: int, value: float | int, big_endian: bool = False) -> float:
725
725
  """Write 4 byte floating-point digit value at given address."""
726
726
 
727
727
  # If result failed
728
728
  if (result := _nt_write_virtual_memory(self.handle, address, ctypes.byref(buffer := _get_be_buffer(ctypes.c_float(value)) if big_endian else ctypes.c_float(value)), ctypes.sizeof(buffer), None)):
729
- raise Exception("NtWriteVirtualMemory failed with status: 0x%s" % hex(result)[2:].upper())
729
+ raise MemoryWriteError(result, address)
730
730
 
731
731
  def write_float64(self, address: int, value: float | int, big_endian: bool = False) -> float:
732
732
  """Write 8 byte floating-point digit value at given address."""
733
733
 
734
734
  # If result failed
735
735
  if (result := _nt_write_virtual_memory(self.handle, address, ctypes.byref(buffer := _get_be_buffer(ctypes.c_double(value)) if big_endian else ctypes.c_double(value)), ctypes.sizeof(buffer), None)):
736
- raise Exception("NtWriteVirtualMemory failed with status: 0x%s" % hex(result)[2:].upper())
736
+ raise MemoryWriteError(result, address)
737
737
 
738
738
  def write_bytes(self, address: int, value: bytes, big_endian: bool = False) -> None:
739
739
  """Write bytes array of variadic size at given address."""
740
740
 
741
741
  # If result failed
742
742
  if (result := _nt_write_virtual_memory(self.handle, address, value[::-1] if big_endian else value, len(value), None)):
743
- raise Exception("NtReadVirtualMemory failed with status: 0x%s" % hex(result)[2:].upper())
743
+ raise MemoryWriteError(result, address)
744
744
 
745
745
  def write_buffer(self, address: int, buffer: typing.Any) -> None:
746
746
  """Write size of buffer byte value at given address. Buffer have to be able passed at `ctypes.byref` and `ctype.sizeof`."""
747
747
 
748
748
  # If result failed
749
749
  if (result := _nt_write_virtual_memory(self.handle, address, ctypes.byref(buffer), ctypes.sizeof(buffer), None)):
750
- raise Exception("NtReadVirtualMemory failed with status: 0x%s" % hex(result)[2:].upper())
750
+ raise MemoryWriteError(result, address)
751
751
 
752
752
  def close(self) -> None:
753
753
  """Close opened process using it's handle, have to be called once on stop interacting with process."""
@@ -755,9 +755,9 @@ class Process:
755
755
  # Close process
756
756
  _nt_close(self.handle)
757
757
 
758
- # ==-------------------------------------------------------------------== #
759
- # Private methods #
760
- # ==-------------------------------------------------------------------== #
758
+ # ==--------------------------------== #
759
+ # Private methods #
760
+ # ==--------------------------------== #
761
761
  def __init_with_pid(self, pid: int, access: int, listed_processes: list[dict[str, int | str]] | None = None) -> tuple[int, int, str]:
762
762
  """Open process handle by it's ID with desired access."""
763
763
 
@@ -771,7 +771,7 @@ class Process:
771
771
  break
772
772
 
773
773
  else:
774
- raise Exception("Process with `%s` ID not found" % pid)
774
+ raise OpenProcessError("Process with `%s` ID not found" % pid)
775
775
 
776
776
  # Prepare arguments
777
777
  object_attributes = OBJECT_ATTRIBUTES()
@@ -782,13 +782,7 @@ class Process:
782
782
 
783
783
  # Try to open process using it's ID
784
784
  if (result := _nt_open_process(ctypes.byref(handle := ctypes.c_void_p()), access, ctypes.byref(object_attributes), ctypes.byref(client_id))):
785
-
786
- # If result failed due process ID not found
787
- if result == 0xC000000B:
788
- raise Exception("Process with `%s` ID not found" % pid)
789
-
790
- else:
791
- raise Exception("NtOpenProcess failed with status: 0x%s" % hex(result)[2:].upper())
785
+ raise NtError("NtOpenProcess failed with status: 0x%s" % hex(result)[2:].upper())
792
786
 
793
787
  return handle.value, pid, process_name
794
788
 
@@ -802,4 +796,4 @@ class Process:
802
796
  if process["name"].lower() == name.strip().lower():
803
797
  return self.__init_with_pid(process["id"], access, listed_processes)
804
798
 
805
- raise Exception("Process with `%s` name not found" % name)
799
+ raise OpenProcessError("Process with `%s` name not found" % name)
@@ -0,0 +1,103 @@
1
+ # +-------------------------------------+
2
+ # | ~ Author : Xenely ~ |
3
+ # +=====================================+
4
+ # | GitHub: https://github.com/Xenely14 |
5
+ # | Discord: xenely |
6
+ # +-------------------------------------+
7
+
8
+ # ==-------------------------------------------------------------------== #
9
+ # Classes #
10
+ # ==-------------------------------------------------------------------== #
11
+ class NtError(Exception):
12
+ """Exception that raises on `nt` functions calls fails."""
13
+
14
+ # ==--------------------------------== #
15
+ # Public methods #
16
+ # ==--------------------------------== #
17
+ def __init__(self, message: str, status: int | None) -> None:
18
+ """Initialize instance of `nt` error."""
19
+
20
+ # Save initializer arguments as an attributes
21
+ self.message = message
22
+ self.status = status
23
+
24
+ # Call initializer of parrent class
25
+ super().__init__(message)
26
+
27
+ def __str__(self) -> str:
28
+ """Overload triggered on `str` cast calls"""
29
+
30
+ # If error status is defined
31
+ if self.status is not None:
32
+ return "Nt function failed with `%s` status: %s" % (self.get_hex_status(), self.message)
33
+
34
+ # If error status is not defined
35
+ return "Nt function failed: %s" % self.message
36
+
37
+ def get_hex_status(self, hex_prefix: str | None = "0x") -> str:
38
+ """Get error `nt`status in hex string view."""
39
+
40
+ return "%s%08x" % (hex_prefix if hex_prefix is not None else "", self.status)
41
+
42
+
43
+ class OpenProcessError(NtError):
44
+ """Exception that raises on process open fail."""
45
+
46
+ # ==--------------------------------== #
47
+ # Public methods #
48
+ # ==--------------------------------== #
49
+ def __init__(self, message: str, status: int | None = None) -> None:
50
+ """Initialize instance of `nt` error."""
51
+
52
+ # Call initializer of parrent class
53
+ super().__init__(message, status)
54
+
55
+ def __str__(self) -> str:
56
+ """Overload triggered on `str` cast calls."""
57
+
58
+ # If error status is defined
59
+ if self.status is not None:
60
+ return "Unable to open process due `nt` function failed with `%s` status: %s" % (self.get_hex_status(), self.message)
61
+
62
+ # If error status is not defined
63
+ return "Unable to open process: %s" % self.message
64
+
65
+
66
+ class MemoryReadError(NtError):
67
+ """Exception that raises on virtual memory read fail."""
68
+
69
+ # ==--------------------------------== #
70
+ # Public methods #
71
+ # ==--------------------------------== #
72
+ def __init__(self, status: int, address: int):
73
+
74
+ # Save initializer arguments as an attributes
75
+ self.address = address
76
+
77
+ # Call initializer of parrent class
78
+ super().__init__(None, status)
79
+
80
+ def __str__(self) -> str:
81
+ """Overload triggered on `str` cast calls"""
82
+
83
+ return "Unalble to read memory at `0x%08x` address, `nt` function failed with `%s` status" % (self.address, self.get_hex_status())
84
+
85
+
86
+ class MemoryWriteError(NtError):
87
+ """Exception that raises on virtual memory read fail."""
88
+
89
+ # ==--------------------------------== #
90
+ # Public methods #
91
+ # ==--------------------------------== #
92
+ def __init__(self, status: int, address: int):
93
+
94
+ # Save initializer arguments as an attributes
95
+ self.address = address
96
+
97
+ # Call initializer of parrent class
98
+ super().__init__(None, status)
99
+
100
+ def __str__(self) -> str:
101
+ """Overload triggered on `str` cast calls"""
102
+
103
+ return "Unalble to write memory at `0x%08x` address, `nt` function failed with `%s` status" % (self.address, self.get_hex_status())
@@ -46,6 +46,9 @@ class DirectSyscallWrapper:
46
46
  # Table containing all syscall wrappers allocations
47
47
  registred_syscalls_table = dict()
48
48
 
49
+ # ==--------------------------------== #
50
+ # Public methods #
51
+ # ==--------------------------------== #
49
52
  def __init__(self) -> None:
50
53
  """Creates wrapper instance to wrap syscalls."""
51
54
 
@@ -70,11 +73,11 @@ class DirectSyscallWrapper:
70
73
 
71
74
  # Module loading
72
75
  if not (module_handle := _LoadLibraryA(search_module)):
73
- raise Exception("Unable to load module `%s`" % search_module.decode())
76
+ raise ctypes.WinError(descr="Unable to load module `%s`" % search_module.decode())
74
77
 
75
78
  # Retrieve function pointer
76
79
  if not (serach_function := _GetProcAddress(module_handle, function_name.encode())):
77
- raise Exception("Function `%s` not found" % function_name)
80
+ raise ctypes.WinError(descr="Function `%s` not found" % function_name)
78
81
 
79
82
  # Syscall id
80
83
  syscall_id = None
@@ -90,7 +93,7 @@ class DirectSyscallWrapper:
90
93
 
91
94
  # If syscall ID not found
92
95
  if syscall_id is None:
93
- raise Exception("Syscall ID for function `%s` not found" % function_name)
96
+ raise ValueError("Syscall ID for function `%s` not found" % function_name)
94
97
 
95
98
  # Convert syscall ID to hex-bytes list
96
99
  syscall_id_bytes = [hex(item)[2:] if len(hex(item)[2:]) == 2 else "0" + hex(item)[2:] for item in bytes(ctypes.c_ushort(syscall_id))]
@@ -111,7 +114,7 @@ class DirectSyscallWrapper:
111
114
 
112
115
  # Allocate buffer for function machine code
113
116
  if not (shellcode_buffer := _VirtualAlloc(0, len(shellcode), 0x1000 | 0x2000, 0x04)):
114
- raise Exception("Unable to alloate memory for shellcode")
117
+ raise ctypes.WinError(descr="Unable to alloate memory for shellcode")
115
118
 
116
119
  # Save allocated buffer into wrapped syscalls table
117
120
  self.registred_syscalls_table[id(self)][function_name] = shellcode_buffer
File without changes