Final touches

This commit is contained in:
elicn
2022-06-08 17:25:22 +03:00
parent 8b233f99fe
commit 4ac282dfc1

View File

@@ -1,4 +1,4 @@
# Unicorn Python bindings by elicn # New and improved Unicorn Python bindings by elicn
# based on Nguyen Anh Quynnh's work # based on Nguyen Anh Quynnh's work
from __future__ import annotations from __future__ import annotations
@@ -6,11 +6,13 @@ from typing import Any, Callable, Iterator, Mapping, MutableMapping, Optional, S
import ctypes import ctypes
import weakref import weakref
# import functools
from . import unicorn_const as uc from . import unicorn_const as uc
from .arch.types import * from .arch.types import *
__version__ = f'{uc.UC_VERSION_MAJOR}.{uc.UC_VERSION_MINOR}.{uc.UC_VERSION_PATCH}'
class _uc_mem_region(ctypes.Structure): class _uc_mem_region(ctypes.Structure):
_fields_ = ( _fields_ = (
('begin', ctypes.c_uint64), ('begin', ctypes.c_uint64),
@@ -177,8 +179,6 @@ def __set_lib_prototypes(lib: ctypes.CDLL) -> None:
uclib = __load_uc_lib() uclib = __load_uc_lib()
__set_lib_prototypes(uclib) __set_lib_prototypes(uclib)
__version__ = f'{uc.UC_VERSION_MAJOR}.{uc.UC_VERSION_MINOR}.{uc.UC_VERSION_PATCH}'
# native hook callback signatures # native hook callback signatures
HOOK_INTR_CFUNC = ctypes.CFUNCTYPE(None, uc_engine, ctypes.c_uint32, ctypes.c_void_p) HOOK_INTR_CFUNC = ctypes.CFUNCTYPE(None, uc_engine, ctypes.c_uint32, ctypes.c_void_p)
@@ -289,6 +289,7 @@ class UcCleanupManager:
def __init__(self): def __init__(self):
self._refs = {} self._refs = {}
def register(self, obj: Uc): def register(self, obj: Uc):
ref = UcRef(obj, self._finalizer) ref = UcRef(obj, self._finalizer)
ref._uch = obj._uch ref._uch = obj._uch
@@ -296,6 +297,7 @@ class UcCleanupManager:
self._refs[id(ref)] = ref self._refs[id(ref)] = ref
def _finalizer(self, ref: UcRef) -> None: def _finalizer(self, ref: UcRef) -> None:
# note: this method must be completely self-contained and cannot have any references # note: this method must be completely self-contained and cannot have any references
# to anything else in this module. # to anything else in this module.
@@ -482,6 +484,13 @@ class Uc(RegStateManager):
def __init__(self, arch: int, mode: int) -> None: def __init__(self, arch: int, mode: int) -> None:
"""Initialize a Unicorn engine instance.
Args:
arch: emulated architecture identifier (see UC_ARCH_* constants)
mode: emulated processor mode (see UC_MODE_* constants)
"""
self._arch = arch self._arch = arch
self._mode = mode self._mode = mode
@@ -493,7 +502,7 @@ class Uc(RegStateManager):
self._uch = None self._uch = None
raise UcError(status) raise UcError(status)
# we have to keep a reference to the callbacks so they do not het gc-ed # we have to keep a reference to the callbacks so they do not get gc-ed
# see: https://docs.python.org/3/library/ctypes.html#callback-functions # see: https://docs.python.org/3/library/ctypes.html#callback-functions
self._callbacks: MutableMapping[int, ctypes._FuncPointer] = {} self._callbacks: MutableMapping[int, ctypes._FuncPointer] = {}
self._mmio_callbacks: MutableMapping[Tuple[int, int], Tuple[Optional[ctypes._FuncPointer], Optional[ctypes._FuncPointer]]] = {} self._mmio_callbacks: MutableMapping[Tuple[int, int], Tuple[Optional[ctypes._FuncPointer], Optional[ctypes._FuncPointer]]] = {}
@@ -527,7 +536,7 @@ class Uc(RegStateManager):
begin : emulation starting address begin : emulation starting address
until : emulation ending address until : emulation ending address
timeout : limit emulation to a certain amount of time (milliseconds) timeout : limit emulation to a certain amount of time (milliseconds)
count : limit emulation to a certain amount of intstructions count : limit emulation to a certain amount of instructions
Raises: Raises:
`UcError` : in case emulation could not be started properly `UcError` : in case emulation could not be started properly
@@ -562,6 +571,7 @@ class Uc(RegStateManager):
def _do_reg_read(self, reg_id: int, reg_obj) -> int: def _do_reg_read(self, reg_id: int, reg_obj) -> int:
"""Private register read implementation. """Private register read implementation.
Do not call directly.
""" """
return uclib.uc_reg_read(self._uch, reg_id, reg_obj) return uclib.uc_reg_read(self._uch, reg_id, reg_obj)
@@ -569,6 +579,7 @@ class Uc(RegStateManager):
def _do_reg_write(self, reg_id: int, reg_obj) -> int: def _do_reg_write(self, reg_id: int, reg_obj) -> int:
"""Private register write implementation. """Private register write implementation.
Do not call directly.
""" """
return uclib.uc_reg_write(self._uch, reg_id, reg_obj) return uclib.uc_reg_write(self._uch, reg_id, reg_obj)
@@ -782,7 +793,7 @@ class Uc(RegStateManager):
"""Hook emulated events of a certain type. """Hook emulated events of a certain type.
Args: Args:
htype : event type(s) to hook htype : event type(s) to hook (see UC_HOOK_* constants)
callback : a method to call each time the hooked event occurs callback : a method to call each time the hooked event occurs
user_data : an additional context to pass to the callback when it is called user_data : an additional context to pass to the callback when it is called
begin : address where hook scope starts begin : address where hook scope starts
@@ -1057,7 +1068,7 @@ class Uc(RegStateManager):
) )
def ctl_get_exits(self): def ctl_get_exits(self) -> Sequence[int]:
l = self.ctl_get_exits_cnt() l = self.ctl_get_exits_cnt()
arr = (ctypes.c_uint64 * l)() arr = (ctypes.c_uint64 * l)()
@@ -1156,6 +1167,7 @@ class UcContext(RegStateManager):
def __getstate__(self): def __getstate__(self):
return bytes(self), self.size, self.arch, self.mode return bytes(self), self.size, self.arch, self.mode
def __setstate__(self, state) -> None: def __setstate__(self, state) -> None:
context, size, arch, mode = state context, size, arch, mode = state
@@ -1171,6 +1183,7 @@ class UcContext(RegStateManager):
def __bytes__(self) -> bytes: def __bytes__(self) -> bytes:
return ctypes.string_at(self.context, self.size) return ctypes.string_at(self.context, self.size)
def __del__(self) -> None: def __del__(self) -> None:
# We need this property since we shouldn't free it if the object is constructed from pickled bytes. # We need this property since we shouldn't free it if the object is constructed from pickled bytes.
if self._to_free: if self._to_free: