feat(plugins): add source-aware evidence and recording timelines
This commit is contained in:
1 parent
72ff342605
commit
ef7af9988e
61 files changed
+3847
-108
No files matched your search
@@ -0,0 +1,86 @@
|
||||
"""Own Windows capture processes even when the task worker is forcibly terminated."""
|
||||
|
||||
import ctypes
|
||||
from ctypes import wintypes
|
||||
|
||||
|
||||
class CaptureProcessJob:
|
||||
"""A non-inheritable job handle: Windows kills captures when its owner exits."""
|
||||
|
||||
def __init__(self):
|
||||
class BasicLimits(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("process_time", ctypes.c_int64),
|
||||
("job_time", ctypes.c_int64),
|
||||
("flags", wintypes.DWORD),
|
||||
("minimum_working_set", ctypes.c_size_t),
|
||||
("maximum_working_set", ctypes.c_size_t),
|
||||
("active_process_limit", wintypes.DWORD),
|
||||
("affinity", ctypes.c_size_t),
|
||||
("priority", wintypes.DWORD),
|
||||
("scheduling", wintypes.DWORD),
|
||||
]
|
||||
|
||||
class IoCounters(ctypes.Structure):
|
||||
_fields_ = [
|
||||
(name, ctypes.c_uint64)
|
||||
for name in (
|
||||
"read_ops",
|
||||
"write_ops",
|
||||
"other_ops",
|
||||
"read_bytes",
|
||||
"write_bytes",
|
||||
"other_bytes",
|
||||
)
|
||||
]
|
||||
|
||||
class ExtendedLimits(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("basic", BasicLimits),
|
||||
("io", IoCounters),
|
||||
("process_memory", ctypes.c_size_t),
|
||||
("job_memory", ctypes.c_size_t),
|
||||
("peak_process_memory", ctypes.c_size_t),
|
||||
("peak_job_memory", ctypes.c_size_t),
|
||||
]
|
||||
|
||||
self._api = ctypes.WinDLL("kernel32", use_last_error=True)
|
||||
for name, arguments, result in (
|
||||
("CreateJobObjectW", [wintypes.LPVOID, wintypes.LPCWSTR], wintypes.HANDLE),
|
||||
(
|
||||
"SetInformationJobObject",
|
||||
[wintypes.HANDLE, ctypes.c_int, wintypes.LPVOID, wintypes.DWORD],
|
||||
wintypes.BOOL,
|
||||
),
|
||||
("OpenProcess", [wintypes.DWORD, wintypes.BOOL, wintypes.DWORD], wintypes.HANDLE),
|
||||
("AssignProcessToJobObject", [wintypes.HANDLE, wintypes.HANDLE], wintypes.BOOL),
|
||||
("CloseHandle", [wintypes.HANDLE], wintypes.BOOL),
|
||||
):
|
||||
function = getattr(self._api, name)
|
||||
function.argtypes, function.restype = arguments, result
|
||||
self._handle = self._api.CreateJobObjectW(None, None)
|
||||
if not self._handle:
|
||||
raise ctypes.WinError(ctypes.get_last_error())
|
||||
limits = ExtendedLimits()
|
||||
limits.basic.flags = 0x00002000 # JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
|
||||
if not self._api.SetInformationJobObject(
|
||||
self._handle, 9, ctypes.byref(limits), ctypes.sizeof(limits)
|
||||
):
|
||||
error = ctypes.get_last_error()
|
||||
self.close()
|
||||
raise ctypes.WinError(error)
|
||||
|
||||
def assign(self, pid: int):
|
||||
process = self._api.OpenProcess(0x0100 | 0x0001, False, pid)
|
||||
if not process:
|
||||
raise ctypes.WinError(ctypes.get_last_error())
|
||||
try:
|
||||
if not self._api.AssignProcessToJobObject(self._handle, process):
|
||||
raise ctypes.WinError(ctypes.get_last_error())
|
||||
finally:
|
||||
self._api.CloseHandle(process)
|
||||
|
||||
def close(self):
|
||||
if self._handle:
|
||||
self._api.CloseHandle(self._handle)
|
||||
self._handle = None
|
||||
Reference in new issue
Block a user