Source code for libpince.typedefs

# -*- coding: utf-8 -*-
"""
Copyright (C) 2016-2017 Korcan Karaokçu <korcankaraokcu@gmail.com>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""

# IMPORTANT: Any constant involving only PINCE.py should be declared in PINCE.py

import collections.abc, queue, sys


[docs] class CONST_TIME: GDB_INPUT_SLEEP = sys.float_info.min
[docs] class PATHS: GDB = "/bin/gdb" # Use utils.get_default_gdb_path() TMP = "/tmp/PINCE/" # Use utils.get_tmp_path() IPC = "/dev/shm/PINCE_IPC/" # Use utils.get_ipc_path() FROM_PINCE = "/from_PINCE" # Use utils.get_from_pince_file() TO_PINCE = "/to_PINCE" # Use utils.get_to_pince_file()
[docs] class USER_PATHS: # Use utils.get_user_path() to make use of these CONFIG = ".config/" ROOT = CONFIG + "PINCE/" GDBINIT = ROOT + "gdbinit" GDBINIT_AA = ROOT + "gdbinit_after_attach" PINCEINIT = ROOT + "pinceinit.py" PINCEINIT_AA = ROOT + "pinceinit_after_attach.py"
[docs] @staticmethod def get_init_files(): return ( USER_PATHS.GDBINIT, USER_PATHS.GDBINIT_AA, USER_PATHS.PINCEINIT, USER_PATHS.PINCEINIT_AA, )
[docs] class INFERIOR_STATUS: RUNNING = 1 STOPPED = 2
[docs] class INFERIOR_ARCH: ARCH_32 = 1 ARCH_64 = 2
[docs] class INJECTION_METHOD: DLOPEN = 1 ADVANCED = 2
[docs] class BREAKPOINT_TYPE: HARDWARE = 1 SOFTWARE = 2
[docs] class WATCHPOINT_TYPE: WRITE_ONLY = 1 READ_ONLY = 2 BOTH = 3
[docs] class BREAKPOINT_ON_HIT: BREAK = 1 FIND_CODE = 2 FIND_ADDR = 3 TRACE = 4
[docs] class BREAKPOINT_MODIFY: CONDITION = 1 ENABLE = 2 DISABLE = 3 ENABLE_ONCE = 4 ENABLE_COUNT = 5 ENABLE_DELETE = 6
[docs] class STEP_MODE: SINGLE_STEP = 1 STEP_OVER = 2
[docs] class TRACE_STATUS: IDLE = 1 TRACING = 2 CANCELED = 3 FINISHED = 4
[docs] class STOP_REASON: PAUSE = 1 DEBUG = 2
[docs] class ATTACH_RESULT: ATTACH_SELF = 1 SUCCESSFUL = 2 PROCESS_NOT_VALID = 3 ALREADY_DEBUGGING = 4 ALREADY_TRACED = 5 PERM_DENIED = 6
[docs] class TOGGLE_ATTACH: ATTACHED = 1 DETACHED = 2
[docs] class REGISTERS: GENERAL_32 = ["eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp", "eip"] GENERAL_64 = [ "rax", "rbx", "rcx", "rdx", "rsi", "rdi", "rbp", "rsp", "rip", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", ] SEGMENT = ["cs", "ss", "ds", "es", "fs", "gs"] FLAG = ["cf", "pf", "af", "zf", "sf", "tf", "if", "df", "of"]
[docs] class FLOAT: ST = ["st" + str(i) for i in range(8)] XMM_32 = ["xmm" + str(i) for i in range(8)] XMM_64 = ["xmm" + str(i) for i in range(16)]
[docs] class FREEZE_TYPE: DEFAULT = 0 INCREMENT = 1 DECREMENT = 2
[docs] class VALUE_REPR: UNSIGNED = 0 SIGNED = 1 HEX = 2
[docs] class VALUE_INDEX: # Beginning of the integer indexes, new integer indexes should be added between 0 and 3 INT8 = 0 INT16 = 1 INT32 = 2 INT64 = 3 # Ending of the integer indexes FLOAT32 = 4 FLOAT64 = 5 # Beginning of the string indexes, new string indexes should be added between 6 and 9 STRING_ASCII = 6 STRING_UTF8 = 7 STRING_UTF16 = 8 STRING_UTF32 = 9 # Ending of the string indexes AOB = 10 # Array of Bytes
[docs] @staticmethod def is_integer(value_index: int): return VALUE_INDEX.INT8 <= value_index <= VALUE_INDEX.INT64
[docs] @staticmethod def is_float(value_index: int): return VALUE_INDEX.FLOAT32 <= value_index <= VALUE_INDEX.FLOAT64
[docs] @staticmethod def is_number(value_index: int): return VALUE_INDEX.INT8 <= value_index <= VALUE_INDEX.FLOAT64
[docs] @staticmethod def is_string(value_index: int): return VALUE_INDEX.STRING_ASCII <= value_index <= VALUE_INDEX.STRING_UTF32
[docs] @staticmethod def has_length(value_index: int): return VALUE_INDEX.STRING_ASCII <= value_index <= VALUE_INDEX.AOB
[docs] class SCAN_INDEX: INT_ANY = 0 INT8 = 1 INT16 = 2 INT32 = 3 INT64 = 4 FLOAT_ANY = 5 FLOAT32 = 6 FLOAT64 = 7 ANY = 8 STRING = 9 AOB = 10 # Array of Bytes
# GDB already provides breakpoint info in english, no need to make these translatable on_hit_to_text_dict = { BREAKPOINT_ON_HIT.BREAK: "Break", BREAKPOINT_ON_HIT.FIND_CODE: "Find Code", BREAKPOINT_ON_HIT.FIND_ADDR: "Find Address", BREAKPOINT_ON_HIT.TRACE: "Trace", } # Represents the texts at indexes in the address table # TODO: This class is mostly an UI helper, maybe integrate it into the the UI completely in the future? index_to_text_dict = collections.OrderedDict( [ (VALUE_INDEX.INT8, "Int8"), (VALUE_INDEX.INT16, "Int16"), (VALUE_INDEX.INT32, "Int32"), (VALUE_INDEX.INT64, "Int64"), (VALUE_INDEX.FLOAT32, "Float32"), (VALUE_INDEX.FLOAT64, "Float64"), (VALUE_INDEX.STRING_ASCII, "String_ASCII"), (VALUE_INDEX.STRING_UTF8, "String_UTF8"), (VALUE_INDEX.STRING_UTF16, "String_UTF16"), (VALUE_INDEX.STRING_UTF32, "String_UTF32"), (VALUE_INDEX.AOB, "ByteArray"), ] ) text_to_index_dict = collections.OrderedDict() for key in index_to_text_dict: text_to_index_dict[index_to_text_dict[key]] = key scanmem_result_to_index_dict = collections.OrderedDict( [ ("I8", VALUE_INDEX.INT8), ("I8u", VALUE_INDEX.INT8), ("I8s", VALUE_INDEX.INT8), ("I16", VALUE_INDEX.INT16), ("I16u", VALUE_INDEX.INT16), ("I16s", VALUE_INDEX.INT16), ("I32", VALUE_INDEX.INT32), ("I32u", VALUE_INDEX.INT32), ("I32s", VALUE_INDEX.INT32), ("I64", VALUE_INDEX.INT64), ("I64u", VALUE_INDEX.INT64), ("I64s", VALUE_INDEX.INT64), ("F32", VALUE_INDEX.FLOAT32), ("F64", VALUE_INDEX.FLOAT64), ("string", VALUE_INDEX.STRING_UTF8), ("bytearray", VALUE_INDEX.AOB), ] ) # Represents the texts at indexes in scan combobox # TODO: Same as index_to_text_dict, consider integrating into UI completely scan_index_to_text_dict = collections.OrderedDict( [ (SCAN_INDEX.INT_ANY, "Int(any)"), (SCAN_INDEX.INT8, "Int8"), (SCAN_INDEX.INT16, "Int16"), (SCAN_INDEX.INT32, "Int32"), (SCAN_INDEX.INT64, "Int64"), (SCAN_INDEX.FLOAT_ANY, "Float(any)"), (SCAN_INDEX.FLOAT32, "Float32"), (SCAN_INDEX.FLOAT64, "Float64"), (SCAN_INDEX.ANY, "Any(int, float)"), (SCAN_INDEX.STRING, "String"), (VALUE_INDEX.AOB, "ByteArray"), ] ) # Used in scan_data_type option of scanmem scan_index_to_scanmem_dict = collections.OrderedDict( [ (SCAN_INDEX.INT_ANY, "int"), (SCAN_INDEX.INT8, "int8"), (SCAN_INDEX.INT16, "int16"), (SCAN_INDEX.INT32, "int32"), (SCAN_INDEX.INT64, "int64"), (SCAN_INDEX.FLOAT_ANY, "float"), (SCAN_INDEX.FLOAT32, "float32"), (SCAN_INDEX.FLOAT64, "float64"), (SCAN_INDEX.ANY, "number"), (SCAN_INDEX.STRING, "string"), (VALUE_INDEX.AOB, "bytearray"), ] ) # TODO: Same as index_to_text_dict, consider integrating into UI completely
[docs] class SCAN_TYPE: EXACT = 0 INCREASED = 1 INCREASED_BY = 2 DECREASED = 3 DECREASED_BY = 4 LESS = 5 MORE = 6 BETWEEN = 7 CHANGED = 8 UNCHANGED = 9 UNKNOWN = 10 NOT = 11
[docs] @staticmethod def get_list(scan_mode, value_type): if scan_mode == SCAN_MODE.NEW: if value_type == SCAN_INDEX.STRING or value_type == SCAN_INDEX.AOB: list = [ SCAN_TYPE.EXACT, SCAN_TYPE.UNKNOWN, ] else: list = [ SCAN_TYPE.EXACT, SCAN_TYPE.NOT, SCAN_TYPE.LESS, SCAN_TYPE.MORE, SCAN_TYPE.BETWEEN, SCAN_TYPE.UNKNOWN, ] else: if value_type == SCAN_INDEX.STRING or value_type == SCAN_INDEX.AOB: list = [SCAN_TYPE.EXACT] else: list = [ SCAN_TYPE.EXACT, SCAN_TYPE.NOT, SCAN_TYPE.INCREASED, SCAN_TYPE.INCREASED_BY, SCAN_TYPE.DECREASED, SCAN_TYPE.DECREASED_BY, SCAN_TYPE.LESS, SCAN_TYPE.MORE, SCAN_TYPE.BETWEEN, SCAN_TYPE.CHANGED, SCAN_TYPE.UNCHANGED, ] return list
[docs] class SCAN_MODE: NEW = 0 ONGOING = 1
[docs] class SCAN_SCOPE: BASIC = 1 NORMAL = 2 FULL_RW = 3 FULL = 4
[docs] class ENDIANNESS: HOST = 0 LITTLE = 1 BIG = 2
string_index_to_encoding_dict = { VALUE_INDEX.STRING_UTF8: ["utf-8", "surrogateescape"], VALUE_INDEX.STRING_UTF16: ["utf-16", "replace"], VALUE_INDEX.STRING_UTF32: ["utf-32", "replace"], VALUE_INDEX.STRING_ASCII: ["ascii", "replace"], } string_index_to_multiplier_dict = { VALUE_INDEX.STRING_UTF8: 2, VALUE_INDEX.STRING_UTF16: 4, VALUE_INDEX.STRING_UTF32: 8, } # first value is the length and the second one is the type # Check gdbutils for an exemplary usage index_to_valuetype_dict = { VALUE_INDEX.INT8: [1, "B"], VALUE_INDEX.INT16: [2, "H"], VALUE_INDEX.INT32: [4, "I"], VALUE_INDEX.INT64: [8, "Q"], VALUE_INDEX.FLOAT32: [4, "f"], VALUE_INDEX.FLOAT64: [8, "d"], VALUE_INDEX.STRING_ASCII: [None, None], VALUE_INDEX.STRING_UTF8: [None, None], VALUE_INDEX.STRING_UTF16: [None, None], VALUE_INDEX.STRING_UTF32: [None, None], VALUE_INDEX.AOB: [None, None], } # Check gdbutils for an exemplary usage index_to_struct_pack_dict = { VALUE_INDEX.INT8: "B", VALUE_INDEX.INT16: "H", VALUE_INDEX.INT32: "I", VALUE_INDEX.INT64: "Q", VALUE_INDEX.FLOAT32: "f", VALUE_INDEX.FLOAT64: "d", } # Format: {tag:tag_description} tag_to_string = collections.OrderedDict( [ ("MemoryRW", "Memory Read/Write"), ("ValueType", "Value Type"), ("Injection", "Injection"), ("Debug", "Debugging"), ("BreakWatchpoints", "Breakpoints&Watchpoints"), ("Threads", "Threads"), ("Registers", "Registers"), ("Stack", "Stack&StackTrace"), ("Assembly", "Disassemble&Assemble"), ("GDBExpressions", "GDB Expressions"), ("GDBCommunication", "GDB Communication"), ("Tools", "Tools"), ("Utilities", "Utilities"), ("Processes", "Processes"), ("GUI", "GUI"), ("ConditionsLocks", "Conditions&Locks"), ("GDBInformation", "GDB Information"), ("InferiorInformation", "Inferior Information"), ] ) # size-->int, any other field-->str tuple_breakpoint_info = collections.namedtuple( "tuple_breakpoint_info", "number breakpoint_type disp enabled address size on_hit hit_count enable_count condition", ) # start, end-->int, perms-->str, file_name-->str tuple_region_info = collections.namedtuple("tuple_region_info", "start end perms file_name") # all fields-->str/None tuple_examine_expression = collections.namedtuple("tuple_examine_expression", "all address symbol") # all fields-->bool gdb_output_mode = collections.namedtuple("gdb_output_mode", "async_output command_output command_info")
[docs] class GDBInitializeException(Exception): def __init__(self, message="GDB not initialized"): super(GDBInitializeException, self).__init__(message)
[docs] class Frozen: def __init__(self, value, freeze_type=FREEZE_TYPE.DEFAULT): self.value = value self.freeze_type = freeze_type self.enabled = False
[docs] class ValueType: def __init__( self, value_index=VALUE_INDEX.INT32, length=10, zero_terminate=True, value_repr=VALUE_REPR.UNSIGNED, endian=ENDIANNESS.HOST, ): """ Args: value_index (int): Determines the type of data. Can be a member of VALUE_INDEX length (int): Length of the data. Only used when the value_index is STRING or AOB zero_terminate (bool): If False, ",NZT" will be appended to the text representation Only used when value_index is STRING. Ignored otherwise. "NZT" stands for "Non-Zero Terminate" value_repr (int): Determines how the data is represented. Can be a member of VALUE_REPR endian (int): Determines the endianness. Can be a member of ENDIANNESS """ self.value_index = value_index self.length = length self.zero_terminate = zero_terminate self.value_repr = value_repr self.endian = endian
[docs] def serialize(self): return ( self.value_index, self.length, self.zero_terminate, self.value_repr, self.endian, )
[docs] def text(self): """Returns the text representation according to its members Returns: str: A str generated by given parameters Examples: value_index=VALUE_INDEX.STRING_UTF16, length=15, zero_terminate=False--▼ returned str="String_UTF16[15],NZT" value_index=VALUE_INDEX.AOB, length=42-->returned str="AoB[42]" """ returned_string = index_to_text_dict[self.value_index] if VALUE_INDEX.is_string(self.value_index): returned_string += f"[{self.length}]" if not self.zero_terminate: returned_string += ",NZT" elif self.value_index == VALUE_INDEX.AOB: returned_string += f"[{self.length}]" if VALUE_INDEX.is_integer(self.value_index): if self.value_repr == VALUE_REPR.SIGNED: returned_string += "(s)" elif self.value_repr == VALUE_REPR.HEX: returned_string += "(h)" if self.endian == ENDIANNESS.LITTLE: returned_string += "<L>" elif self.endian == ENDIANNESS.BIG: returned_string += "<B>" return returned_string
[docs] class PointerChainResult: def __init__(self): self.pointer_chain: list[int] = []
[docs] def get_pointer_by_index(self, index) -> int | None: if index >= len(self.pointer_chain): return None return self.pointer_chain[index]
[docs] def get_final_address(self) -> int | None: return self.pointer_chain[-1] if self.pointer_chain else None
[docs] def get_final_address_as_hex(self) -> str | None: """ Returns the hex representation of this pointer chain's final/destination address """ return hex(self.pointer_chain[-1]) if self.pointer_chain else None
[docs] class PointerChainRequest: def __init__(self, base_address: str | int, offsets_list: list[int] = None): """ Args: base_address (str, int): The base address of where this pointer chain starts from. Can be str expression or int. offsets_list (list): List of offsets to reach the final pointed data. Can be None for no offsets. Last offset in list won't be dereferenced to emulate CE behaviour. """ self.base_address: str | int = base_address self.offsets_list: list[int] = [] if not offsets_list else offsets_list
[docs] def serialize(self) -> tuple[str | int, list[int]]: return self.base_address, self.offsets_list
[docs] def get_base_address_as_str(self) -> str: """ Returns the text representation of this pointer's base address """ return hex(self.base_address) if type(self.base_address) != str else self.base_address
[docs] class RegisterQueue: def __init__(self): self.queue_list = []
[docs] def register_queue(self): new_queue = queue.Queue() self.queue_list.append(new_queue) return new_queue
[docs] def broadcast_message(self, message): for item in self.queue_list: item.put(message)
[docs] def delete_queue(self, queue_instance): try: self.queue_list.remove(queue_instance) except ValueError: pass
[docs] class KeyboardModifiersTupleDict(collections.abc.Mapping): def __init__(self, OrderedDict_like_list): new_dict = {} for keycomb, value in OrderedDict_like_list: new_dict[keycomb] = value self._storage = new_dict def __getitem__(self, keycomb): return self._storage[keycomb] def __iter__(self): return iter(self._storage) def __len__(self): return len(self._storage)