-
-
Notifications
You must be signed in to change notification settings - Fork 21
Expand file tree
/
Copy pathsyscall_handler.py
More file actions
81 lines (65 loc) · 4 KB
/
syscall_handler.py
File metadata and controls
81 lines (65 loc) · 4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#
# This file is part of libdebug Python library (https://github.com/libdebug/libdebug).
# Copyright (c) 2024-2025 Roberto Alessandro Bertolini, Gabriele Digregorio. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for details.
#
from __future__ import annotations
from dataclasses import dataclass, field
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from collections.abc import Callable
from libdebug.debugger.internal_debugger import InternalDebugger
from libdebug.state.thread_context import ThreadContext
@dataclass(eq=False)
class SyscallHandler:
"""Handle a syscall executed by the target process.
Attributes:
syscall_number (int): The syscall number to handle.
on_enter_user (Callable[[ThreadContext, SyscallHandler], None]): The callback defined by the user to execute when the syscall is entered.
on_exit_user (Callable[[ThreadContext, SyscallHandler], None]): The callback defined by the user to execute when the syscall is exited.
on_enter_pprint (Callable[[ThreadContext, int, Any], None]): The callback defined by the pretty print to execute when the syscall is entered.
on_exit_pprint (Callable[[int | tuple[int, int]], None]): The callback defined by the pretty print to execute when the syscall is exited.
recursive (bool): Whether, when the syscall is hijacked with another one, the syscall handler associated with the new syscall should be considered as well. Defaults to False.
enabled (bool): Whether the syscall will be handled or not.
hit_count (int): The number of times the syscall has been handled.
"""
syscall_number: int
on_enter_user: Callable[[ThreadContext, SyscallHandler], None]
on_exit_user: Callable[[ThreadContext, SyscallHandler], None]
on_enter_pprint: Callable[[ThreadContext, int, Any], None] = field(repr=False)
on_exit_pprint: Callable[[int | tuple[int, int]], None] = field(repr=False)
recursive: bool = False
hit_count: int = 0
_enabled: bool = field(default=True, init=False, repr=True)
_has_entered: bool = field(default=False, init=False, repr=False)
_skip_exit: bool = field(default=False, init=False, repr=False)
_internal_debugger: InternalDebugger = field(default=None, init=True, repr=False)
@property
def enabled(self: SyscallHandler) -> bool:
"""Returns whether the syscall handler is enabled or not."""
self._internal_debugger._ensure_process_stopped()
return self._enabled
@enabled.setter
def enabled(self: SyscallHandler, value: bool) -> None:
"""Sets whether the syscall handler is enabled or not."""
self._internal_debugger._ensure_process_stopped()
self._enabled = value
self._has_entered = False
def enable(self: SyscallHandler) -> None:
"""Handle the syscall."""
self.enabled = True
def disable(self: SyscallHandler) -> None:
"""Unhandle the syscall."""
self.enabled = False
def hit_on(self: SyscallHandler, thread_context: ThreadContext) -> bool:
"""Returns whether the syscall handler has been hit on the given thread context."""
self._internal_debugger._ensure_process_stopped()
return self._enabled and thread_context.syscall_number == self.syscall_number
def hit_on_enter(self: SyscallHandler, thread_context: ThreadContext) -> bool:
"""Returns whether the syscall handler has been hit during the syscall entry on the given thread context."""
self._internal_debugger._ensure_process_stopped()
return self._enabled and thread_context.syscall_number == self.syscall_number and self._has_entered
def hit_on_exit(self: SyscallHandler, thread_context: ThreadContext) -> bool:
"""Returns whether the syscall handler has been hit during the syscall exit on the given thread context."""
self._internal_debugger._ensure_process_stopped()
return self._enabled and thread_context.syscall_number == self.syscall_number and not self._has_entered