old htb folders
This commit is contained in:
2023-08-29 21:53:22 +02:00
parent 62ab804867
commit 82b0759f1e
21891 changed files with 6277643 additions and 0 deletions

View File

@@ -0,0 +1,37 @@
"""
archinfo is a collection of classes that contain architecture-specific information.
It is useful for cross-architecture tools (such as pyvex).
"""
__version__ = "9.2.35"
if bytes is str:
raise Exception("This module is designed for python 3 only. Please install an older version to use python 2.")
# NewType Declaration, see https://docs.python.org/3/library/typing.html#newtype
from typing import NewType
RegisterOffset = NewType("RegisterOffset", int)
TmpVar = NewType("TmpVar", int)
# This causes too much issues as a NewType, sot is a simple alias instead
# This means that is still legal to pass any str where a RegisterName is expected.
# The downside is that PyCharm will show the type as `str` when displaying the signature
RegisterName = str
# pylint: disable=wildcard-import
from .arch import *
from .defines import defines
from .arch_amd64 import ArchAMD64
from .arch_x86 import ArchX86
from .arch_arm import ArchARM, ArchARMEL, ArchARMHF, ArchARMCortexM
from .arch_aarch64 import ArchAArch64
from .arch_avr import ArchAVR8
from .arch_ppc32 import ArchPPC32
from .arch_ppc64 import ArchPPC64
from .arch_mips32 import ArchMIPS32
from .arch_mips64 import ArchMIPS64
from .arch_soot import ArchSoot
from .archerror import ArchError
from .arch_s390x import ArchS390X

View File

@@ -0,0 +1,909 @@
import logging
from typing import Dict, List, Tuple
import struct as _struct
import platform as _platform
import re
from .archerror import ArchError
from . import RegisterOffset, RegisterName
from .tls import TLSArchInfo
import copy
l = logging.getLogger("archinfo.arch")
l.addHandler(logging.NullHandler())
try:
import pyvex as _pyvex
except ImportError:
_pyvex = None
try:
import unicorn as _unicorn
except ImportError:
_unicorn = None
try:
import capstone as _capstone
except ImportError:
_capstone = None
try:
import keystone as _keystone
except ImportError:
_keystone = None
class Endness: # pylint: disable=no-init
"""Endness specifies the byte order for integer values
:cvar LE: little endian, least significant byte is stored at lowest address
:cvar BE: big endian, most significant byte is stored at lowest address
:cvar ME: Middle-endian. Yep.
"""
LE = "Iend_LE"
BE = "Iend_BE"
ME = "Iend_ME"
class Register:
"""
A collection of information about a register. Each different architecture
has its own list of registers, which is the base for all other
register-related collections.
It is, just like for Arch object, assumed that the information is compatible
with PyVEX.
:ivar str name: The name of the register
:ivar int size: The size of the register (in bytes)
:ivar int vex_offset: The VEX offset used to identify this register
:ivar str vex_name: The name libVEX uses to identify the register
:ivar list subregisters: The list of subregisters in the form (name, offset from vex_offset, size)
:ivar tuple alias_names: The list of possible alias names
:ivar bool general_purpose: Whether this is a general purpose register
:ivar bool floating_point: Whether this is a floating-point register
:ivar bool vector: Whether this is a vector register
:ivar bool argument: Whether this is an argument register
:ivar bool persistent: Whether this is a persistent register
:ivar tuple default_value: The offset of the instruction pointer in the register file
:ivar int, str linux_entry_value: The offset of the instruction pointer in the register file
:ivar bool concretize_unique: Whether this register should be concretized, if unique, at the end of each block
:ivar bool concrete: Whether this register should be considered during the synchronization of the concrete execution
of the process
:ivar bool artificial: Whether this register is an artificial register added by VEX IR or other ILs.
"""
def __init__(
self,
name,
size,
vex_offset=None,
vex_name=None,
subregisters=None,
alias_names=None,
general_purpose=False,
floating_point=False,
vector=False,
argument=False,
persistent=False,
default_value=None,
linux_entry_value=None,
concretize_unique=False,
concrete=True,
artificial=False,
):
self.name = name # type: RegisterName
self.size = size # type: int
self.vex_offset = vex_offset # type: RegisterOffset
self.vex_name = vex_name
self.subregisters = (
[] if subregisters is None else subregisters
) # type: List[Tuple[RegisterName, RegisterOffset, int]]
self.alias_names = () if alias_names is None else alias_names
self.general_purpose = general_purpose
self.floating_point = floating_point
self.vector = vector
self.argument = argument
self.persistent = persistent
self.default_value = default_value
self.linux_entry_value = linux_entry_value
self.concretize_unique = concretize_unique
self.concrete = concrete
self.artificial = artificial
def __repr__(self):
return f"<Register {self.name}>"
class Arch:
"""
A collection of information about a given architecture. This class should be subclasses for each different
architecture, and then that subclass should be registered with the ``register_arch`` method.
A good number of assumptions are made that code is being processed under the VEX IR - for instance, it is expected
the register file offsets are expected to match code generated by PyVEX.
Arches may be compared with == and !=.
:ivar str name: The name of the arch
:ivar int bits: The number of bits in a word
:ivar str vex_arch: The VEX enum name used to identify this arch
:ivar str qemu_name: The name used by QEMU to identify this arch
:ivar str ida_processor: The processor string used by IDA to identify this arch
:ivar str triplet: The triplet used to identify a linux system on this arch
:ivar int max_inst_bytes: The maximum number of bytes in a single instruction
:ivar int ip_offset: The offset of the instruction pointer in the register file
:ivar int sp_offset: The offset of the stack pointer in the register file
:ivar int bp_offset: The offset of the base pointer in the register file
:ivar int lr_offset: The offset of the link register (return address) in the register file
:ivar int ret_offset: The offset of the return value register in the register file
:ivar bool vex_conditional_helpers: Whether libVEX will generate code to process the conditional flags for this
arch using ccalls
:ivar int syscall_num_offset: The offset in the register file where the syscall number is stored
:ivar bool call_pushes_ret: Whether this arch's call instruction causes a stack push
:ivar int stack_change: The change to the stack pointer caused by a push instruction
:ivar str memory_endness: The endness of memory, as a VEX enum
:ivar str register_endness: The endness of registers, as a VEX enum. Should usually be same as above
:ivar str instruction_endness: The endness of instructions stored in memory.
In other words, this controls whether instructions are stored endian-flipped compared to their description
in the ISA manual, and should be flipped when lifted. Iend_BE means "don't flip"
NOTE: Only used for non-libVEX lifters.
:ivar dict sizeof: A mapping from C type to variable size in bits
:ivar cs_arch: The Capstone arch value for this arch
:ivar cs_mode: The Capstone mode value for this arch
:ivar ks_arch: The Keystone arch value for this arch
:ivar ks_mode: The Keystone mode value for this arch
:ivar uc_arch: The Unicorn engine arch value for this arch
:ivar uc_mode: The Unicorn engine mode value for this arch
:ivar uc_const: The Unicorn engine constants module for this arch
:ivar uc_prefix: The prefix used for variables in the Unicorn engine constants module
:ivar list function_prologs: A list of regular expressions matching the bytes for common function prologues
:ivar list function_epilogs: A list of regular expressions matching the bytes for common function epilogues
:ivar str ret_instruction: The bytes for a return instruction
:ivar str nop_instruction: The bytes for a nop instruction
:ivar int instruction_alignment: The instruction alignment requirement
:ivar list default_register_values: A weird listing describing how registers should be initialized for purposes of
sanity
:ivar dict entry_register_values: A mapping from register name to a description of the value that should be in it
at program entry on linux
:ivar list default_symbolic_register: Honestly, who knows what this is supposed to do. Fill it with the names of
the general purpose registers.
:ivar dict register_names: A mapping from register file offset to register name
:ivar dict registers: A mapping from register name to a tuple of (register file offset, size in bytes)
:ivar list lib_paths: A listing of common locations where shared libraries for this architecture may be found
:ivar str got_section_name: The name of the GOT section in ELFs
:ivar str ld_linux_name: The name of the linux dynamic loader program
:cvar int byte_width: the number of bits in a byte.
:ivar TLSArchInfo elf_tls: A description of how thread-local storage works
"""
byte_width = 8
instruction_endness = "Iend_BE"
elf_tls = None # type: TLSArchInfo
def __init__(self, endness, instruction_endness=None):
self.bytes = self.bits // self.byte_width
if endness not in (Endness.LE, Endness.BE, Endness.ME):
raise ArchError("Must pass a valid endness: Endness.LE, Endness.BE, or Endness.ME")
if instruction_endness is not None:
self.instruction_endness = instruction_endness
if self.vex_support and _pyvex:
self.vex_archinfo = _pyvex.default_vex_archinfo()
if endness == Endness.BE:
if self.vex_archinfo:
self.vex_archinfo["endness"] = _pyvex.vex_endness_from_string("VexEndnessBE")
self.memory_endness = Endness.BE
self.register_endness = Endness.BE
if _capstone and self.cs_mode is not None:
self.cs_mode -= _capstone.CS_MODE_LITTLE_ENDIAN
self.cs_mode += _capstone.CS_MODE_BIG_ENDIAN
if _keystone and self.ks_mode is not None:
self.ks_mode -= _keystone.KS_MODE_LITTLE_ENDIAN
self.ks_mode += _keystone.KS_MODE_BIG_ENDIAN
self.ret_instruction = reverse_ends(self.ret_instruction)
self.nop_instruction = reverse_ends(self.nop_instruction)
if self.register_list and _pyvex is not None:
(_, _), max_offset = max(_pyvex.vex_ffi.guest_offsets.items(), key=lambda x: x[1])
max_offset += self.bits
# Register collections
if type(self.vex_arch) is str:
va = self.vex_arch[7:].lower() # pylint: disable=unsubscriptable-object
for r in self.register_list:
if r.vex_offset is None:
for name in (r.vex_name, r.name) + r.alias_names:
try:
r.vex_offset = _pyvex.vex_ffi.guest_offsets[(va, name)]
except KeyError:
r.vex_offset = max_offset
max_offset += r.size
else:
break
self.default_register_values = [
(r.name,) + r.default_value for r in self.register_list if r.default_value is not None
]
self.entry_register_values = {
r.name: r.linux_entry_value for r in self.register_list if r.linux_entry_value is not None
}
self.default_symbolic_registers = [r.name for r in self.register_list if r.general_purpose]
self.register_names = {r.vex_offset: r.name for r in self.register_list}
self.registers = self._get_register_dict()
self.argument_registers = {r.vex_offset for r in self.register_list if r.argument}
self.persistent_regs = [r.name for r in self.register_list if r.persistent]
self.concretize_unique_registers = {r.vex_offset for r in self.register_list if r.concretize_unique}
self.artificial_registers = {r.name for r in self.register_list if r.artificial}
self.cpu_flag_register_offsets_and_bitmasks_map = {}
self.reg_blacklist = []
self.reg_blacklist_offsets = []
# Artificial registers offsets
self.artificial_registers_offsets = []
for reg_name in self.artificial_registers:
reg = self.get_register_by_name(reg_name)
self.artificial_registers_offsets.extend(range(reg.vex_offset, reg.vex_offset + reg.size))
# Register offsets
try:
self.ip_offset = self.registers["ip"][0]
self.sp_offset = self.registers["sp"][0]
self.bp_offset = self.registers["bp"][0]
self.lr_offset = self.registers.get("lr", (None, None))[0]
except KeyError:
pass
# generate register mapping (offset, size): name
self.register_size_names = {}
for reg in self.register_list:
if reg.vex_offset is None:
continue
self.register_size_names[(reg.vex_offset, reg.size)] = reg.name
for name, off, sz in reg.subregisters:
# special hacks for X86 and AMD64 - don't translate register names to bp, sp, etc.
if self.name in {"X86", "AMD64"} and name in {"bp", "sp", "ip"}:
continue
self.register_size_names[(reg.vex_offset + off, sz)] = name
# allow mapping a sub-register to its base register
self.subregister_map = {}
for reg in self.register_list:
if reg.vex_offset is None:
continue
base_reg = reg.vex_offset, reg.size
self.subregister_map[(reg.vex_offset, reg.size)] = base_reg
self.subregister_map[reg.vex_offset] = base_reg
for name, off, sz in reg.subregisters:
if self.name in {"X86", "AMD64"} and name in {"bp", "sp", "ip"}:
continue
subreg_offset = reg.vex_offset + off
self.subregister_map[(subreg_offset, sz)] = base_reg
if subreg_offset not in self.subregister_map:
self.subregister_map[subreg_offset] = base_reg
# Unicorn specific stuff
if self.uc_mode is not None:
if endness == Endness.BE:
self.uc_mode -= _unicorn.UC_MODE_LITTLE_ENDIAN
self.uc_mode += _unicorn.UC_MODE_BIG_ENDIAN
self.uc_regs = {}
# map register names to Unicorn const
for r in self.register_names.values():
reg_name = self.uc_prefix + "REG_" + r.upper()
if hasattr(self.uc_const, reg_name):
self.uc_regs[r] = getattr(self.uc_const, reg_name)
# VEX register offset to unicorn register ID map
self.vex_to_unicorn_map = {}
pc_reg_name = self.get_register_by_name("pc")
for reg_name, unicorn_reg_id in self.uc_regs.items():
if reg_name == pc_reg_name:
continue
vex_reg = self.get_register_by_name(reg_name)
self.vex_to_unicorn_map[vex_reg.vex_offset] = (unicorn_reg_id, vex_reg.size)
# VEX registers used in lieu of flags register
self.vex_cc_regs = []
vex_cc_register_names = ["cc_op", "cc_dep1", "cc_dep2", "cc_ndep"]
for reg_name in vex_cc_register_names:
vex_flag_reg = self.get_register_by_name(reg_name)
if vex_flag_reg is not None:
self.vex_cc_regs.append(vex_flag_reg)
def copy(self):
"""
Produce a copy of this instance of this arch.
"""
res = copy.copy(self)
res.vex_archinfo = copy.deepcopy(self.vex_archinfo)
res._cs = None
res._ks = None
return res
def __repr__(self):
return f"<Arch {self.name} ({self.memory_endness[-2:]})>"
def __hash__(self):
return hash((self.name, self.bits, self.memory_endness))
def __eq__(self, other):
if not isinstance(other, Arch):
return False
return self.name == other.name and self.bits == other.bits and self.memory_endness == other.memory_endness
def __ne__(self, other):
return not self == other
def __getstate__(self):
self._cs = None
self._ks = None
if self.vex_archinfo is not None:
# clear hwcacheinfo-caches because it may contain cffi.CData
self.vex_archinfo["hwcache_info"]["caches"] = None
return self.__dict__
def __setstate__(self, data):
self.__dict__.update(data)
def get_register_by_name(self, reg_name):
"""
Return the Register object associated with the given name.
This includes subregisters.
For example, if you are operating in a platform-independent
setting, and wish to address "whatever the stack pointer is"
you could pass 'sp' here, and get Register(...r13...) back
on an ARM platform.
"""
for r in self.register_list:
if reg_name == r.name or reg_name in r.alias_names:
return r
return None
def get_default_reg_value(self, register):
if register == "sp":
# Convert it to the corresponding register name
registers = [r for r, v in self.registers.items() if v[0] == self.sp_offset]
if len(registers) > 0:
register = registers[0]
else:
return None
for reg, val, _, _ in self.default_register_values:
if reg == register:
return val
return None
def struct_fmt(self, size=None, signed=False, endness=None):
"""
Produce a format string for use in python's ``struct`` module to decode a single word.
:param int size: The size in bytes to pack/unpack. Defaults to wordsize
:param bool signed: Whether the data should be extracted signed/unsigned. Default unsigned
:param str endness: The endian to use in packing/unpacking. Defaults to memory endness
:return str: A format string with an endness modifier and a single format character
"""
if size is None:
size = self.bytes
if endness is None:
endness = self.memory_endness
if endness == Endness.BE:
fmt_end = ">"
elif endness == Endness.LE:
fmt_end = "<"
elif endness == Endness.ME:
raise ValueError("Please don't middle-endian at me, I'm begging you")
else:
raise ValueError("Invalid endness value: %r" % endness)
if size == 8:
fmt_size = "Q"
elif size == 4:
fmt_size = "I"
elif size == 2:
fmt_size = "H"
elif size == 1:
fmt_size = "B"
else:
raise ValueError("Invalid size: Must be a integer power of 2 less than 16")
if signed:
fmt_size = fmt_size.lower()
return fmt_end + fmt_size
def _get_register_dict(self) -> Dict[RegisterName, Tuple[RegisterOffset, int]]:
res = {}
for r in self.register_list:
if r.vex_offset is None:
continue
res[r.name] = (r.vex_offset, r.size)
for i in r.alias_names:
res[i] = (r.vex_offset, r.size)
for reg, offset, size in r.subregisters:
res[reg] = (r.vex_offset + offset, size)
return res
# e.g. sizeof['int'] = 32
sizeof = {}
@property
def capstone(self):
"""
A Capstone instance for this arch
"""
if _capstone is None:
raise Exception("Capstone is not installed!")
if self.cs_arch is None:
raise ArchError("Arch %s does not support disassembly with Capstone" % self.name)
if self._cs is None:
self._cs = _capstone.Cs(self.cs_arch, self.cs_mode)
self._configure_capstone()
self._cs.detail = True
return self._cs
@property
def keystone(self):
"""
A Keystone instance for this arch
"""
if self._ks is None:
if _keystone is None:
raise Exception("Keystone is not installed!")
if self.ks_arch is None:
raise ArchError("Arch %s does not support disassembly with Keystone" % self.name)
self._ks = _keystone.Ks(self.ks_arch, self.ks_mode)
self._configure_keystone()
return self._ks
def _configure_capstone(self):
pass
def _configure_keystone(self):
pass
@property
def unicorn(self):
"""
A Unicorn engine instance for this arch
"""
if _unicorn is None or self.uc_arch is None:
raise ArchError("Arch %s does not support with Unicorn" % self.name)
# always create a new Unicorn instance
return _unicorn.Uc(self.uc_arch, self.uc_mode)
def asm(self, string, addr=0, as_bytes=True, thumb=False):
"""
Compile the assembly instruction represented by string using Keystone
:param string: The textual assembly instructions, separated by semicolons
:param addr: The address at which the text should be assembled, to deal with PC-relative access. Default 0
:param as_bytes: Set to False to return a list of integers instead of a python byte string
:param thumb: If working with an ARM processor, set to True to assemble in thumb mode.
:return: The assembled bytecode
"""
if thumb and not hasattr(self, "keystone_thumb"):
l.warning("Specified thumb=True on non-ARM architecture")
thumb = False
ks = self.keystone_thumb if thumb else self.keystone # pylint: disable=no-member
try:
encoding, _ = ks.asm(string, addr, as_bytes) # pylint: disable=too-many-function-args
except TypeError:
bytelist, _ = ks.asm(string, addr)
if as_bytes:
if bytes is str:
encoding = "".join(chr(c) for c in bytelist)
else:
encoding = bytes(bytelist)
else:
encoding = bytelist
return encoding
def disasm(self, bytestring, addr=0, thumb=False):
if thumb and not hasattr(self, "capstone_thumb"):
l.warning("Specified thumb=True on non-ARM architecture")
thumb = False
cs = self.capstone_thumb if thumb else self.capstone # pylint: disable=no-member
return "\n".join(f"{insn.address:#x}:\t{insn.mnemonic} {insn.op_str}" for insn in cs.disasm(bytestring, addr))
def translate_dynamic_tag(self, tag):
try:
return self.dynamic_tag_translation[tag]
except KeyError:
if isinstance(tag, int):
l.error("Please look up and add dynamic tag type %#x for %s", tag, self.name)
return tag
def translate_symbol_type(self, tag):
try:
return self.symbol_type_translation[tag]
except KeyError:
if isinstance(tag, int):
l.error("Please look up and add symbol type %#x for %s", tag, self.name)
return tag
def translate_register_name(self, offset, size=None):
if size is not None:
try:
return self.register_size_names[(offset, size)]
except KeyError:
pass
try:
return self.register_names[offset]
except KeyError:
return str(offset)
def get_base_register(self, offset, size=None):
"""
Convert a register or sub-register to its base register's offset.
:param int offset: The offset of the register to look up for.
:param int size: Size of the register.
:return: Offset and size of the base register, or None if no base register is found.
"""
if size is None:
key = offset
else:
key = (offset, size)
return self.subregister_map.get(key, None)
def get_register_offset(self, name):
try:
return self.registers[name][0]
except:
raise ValueError("Register %s does not exist!" % name)
def is_artificial_register(self, offset, size):
r = self.get_base_register(offset, size)
if r is None:
return False
r_offset, _ = r
try:
r_name = self.register_names[r_offset]
except KeyError:
return False
return r_name in self.artificial_registers
# Determined by watching the output of strace ld-linux.so.2 --list --inhibit-cache
def library_search_path(self, pedantic=False):
"""
A list of paths in which to search for shared libraries.
"""
subfunc = lambda x: x.replace("${TRIPLET}", self.triplet).replace("${ARCH}", self.linux_name)
path = ["/lib/${TRIPLET}/", "/usr/lib/${TRIPLET}/", "/lib/", "/usr/lib", "/usr/${TRIPLET}/lib/"]
if self.bits == 64:
path.append("/usr/${TRIPLET}/lib64/")
path.append("/usr/lib64/")
path.append("/lib64/")
elif self.bits == 32:
path.append("/usr/${TRIPLET}/lib32/")
path.append("/usr/lib32/")
path.append("/lib32/")
if pedantic:
path = sum([[x + "tls/${ARCH}/", x + "tls/", x + "${ARCH}/", x] for x in path], [])
return list(map(subfunc, path))
def m_addr(self, addr, *args, **kwargs):
"""
Given the address of some code block, convert it to the address where this block
is stored in memory. The memory address can also be referred to as the "real" address.
:param addr: The address to convert.
:return: The "real" address in memory.
:rtype: int
"""
return addr
def x_addr(self, addr, *args, **kwargs):
"""
Given the address of some code block, convert it to the value that should be assigned
to the instruction pointer register in order to execute the code in that block.
:param addr: The address to convert.
:return: The "execution" address.
:rtype: int
"""
return addr
def is_thumb(self, addr): # pylint:disable=unused-argument
"""
Return True, if the address is the THUMB address. False otherwise.
For non-ARM architectures this method always returns False.
:param addr: The address to check.
:return: Whether the given address is the THUMB address.
"""
return False
@property
def vex_support(self):
"""
Whether the architecture is supported by VEX or not.
:return: True if this Arch is supported by VEX, False otherwise.
:rtype: bool
"""
return self.vex_arch is not None
@property
def unicorn_support(self):
"""
Whether the architecture is supported by Unicorn engine or not,
:return: True if this Arch is supported by the Unicorn engine, False otherwise.
:rtype: bool
"""
return self.qemu_name is not None
@property
def capstone_support(self):
"""
Whether the architecture is supported by the Capstone engine or not.
:return: True if this Arch is supported by the Capstone engine, False otherwise.
:rtype: bool
"""
return self.cs_arch is not None
@property
def keystone_support(self):
"""
Whether the architecture is supported by the Keystone engine or not.
:return: True if this Arch is supported by the Keystone engine, False otherwise.
:rtype: bool
"""
return self.ks_arch is not None
address_types = (int,)
function_address_types = (int,)
# various names
name = None # type: str
vex_arch = None
qemu_name = None
ida_processor = None
linux_name = None
triplet = None
# instruction stuff
max_inst_bytes = None
ret_instruction = b""
nop_instruction = b""
instruction_alignment = None
# register offsets
ip_offset = None # type: RegisterOffset
sp_offset = None # type: RegisterOffset
bp_offset = None # type: RegisterOffset
ret_offset = None # type: RegisterOffset
fp_ret_offset = None # type: RegisterOffset
lr_offset = None # type: RegisterOffset
# whether or not VEX has ccall handlers for conditionals for this arch
vex_conditional_helpers = False
# memory stuff
bits = None
memory_endness = Endness.LE
register_endness = Endness.LE
stack_change = None
# is it safe to cache IRSBs?
cache_irsb = True
branch_delay_slot = False
function_prologs = set()
function_epilogs = set()
# Capstone stuff
cs_arch = None
cs_mode = None
_cs = None
# Keystone stuff
ks_arch = None
ks_mode = None
_ks = None
# Unicorn stuff
uc_arch = None
uc_mode = None
uc_const = None
uc_prefix = None
uc_regs = None
artificial_registers_offsets = None
artificial_registers = None
cpu_flag_register_offsets_and_bitmasks_map = None
reg_blacklist = None
reg_blacklist_offsets = None
vex_to_unicorn_map = None
vex_cc_regs = None
call_pushes_ret = False
initial_sp = 0x7FFF0000
# Difference of the stack pointer after a call instruction (or its equivalent) is executed
call_sp_fix = 0
stack_size = 0x8000000
# Register information
register_list = [] # type: List[Register]
default_register_values = []
entry_register_values = {}
default_symbolic_registers = []
registers = {} # type: Dict[RegisterName, Tuple[RegisterOffset, int]]
register_names = {} # type: Dict[RegisterOffset, RegisterName]
argument_registers = set()
argument_register_positions = {}
persistent_regs = []
concretize_unique_registers = (
set()
) # this is a list of registers that should be concretized, if unique, at the end of each block
lib_paths = []
reloc_s_a = []
reloc_b_a = []
reloc_s = []
reloc_copy = []
reloc_tls_mod_id = []
reloc_tls_doffset = []
reloc_tls_offset = []
dynamic_tag_translation = {}
symbol_type_translation = {}
got_section_name = ""
vex_archinfo = None
arch_id_map = []
all_arches = []
def register_arch(regexes, bits, endness, my_arch):
"""
Register a new architecture.
Architectures are loaded by their string name using ``arch_from_id()``, and
this defines the mapping it uses to figure it out.
Takes a list of regular expressions, and an Arch class as input.
:param regexes: List of regular expressions (str or SRE_Pattern)
:type regexes: list
:param bits: The canonical "bits" of this architecture, ex. 32 or 64
:type bits: int
:param endness: The "endness" of this architecture. Use Endness.LE, Endness.BE, Endness.ME, "any", or None if the
architecture has no intrinsic endianness.
:type endness: str or None
:param class my_arch:
:return: None
"""
if not isinstance(regexes, list):
raise TypeError("regexes must be a list")
for rx in regexes:
if not isinstance(rx, str) and not isinstance(rx, re._pattern_type):
raise TypeError("Each regex must be a string or compiled regular expression")
try:
re.compile(rx)
except:
raise ValueError("Invalid Regular Expression %s" % rx)
# if not isinstance(my_arch,Arch):
# raise TypeError("Arch must be a subclass of archinfo.Arch")
if not isinstance(bits, int):
raise TypeError("Bits must be an int")
if endness is not None:
if endness not in (Endness.BE, Endness.LE, Endness.ME, "any"):
raise TypeError("Endness must be Endness.BE, Endness.LE, or 'any'")
arch_id_map.append((regexes, bits, endness, my_arch))
if endness == "any":
all_arches.append(my_arch(Endness.BE))
all_arches.append(my_arch(Endness.LE))
else:
all_arches.append(my_arch(endness))
class ArchNotFound(Exception):
pass
def arch_from_id(ident, endness="any", bits="") -> Arch:
"""
Take our best guess at the arch referred to by the given identifier, and return an instance of its class.
You may optionally provide the ``endness`` and ``bits`` parameters (strings) to help this function out.
"""
if bits == 64 or (isinstance(bits, str) and "64" in bits):
bits = 64
elif isinstance(bits, str) and "32" in bits:
bits = 32
elif not bits and "64" in ident:
bits = 64
elif not bits and "32" in ident:
bits = 32
endness = endness.lower()
if "lit" in endness:
endness = Endness.LE
elif "big" in endness:
endness = Endness.BE
elif "lsb" in endness:
endness = Endness.LE
elif "msb" in endness:
endness = Endness.BE
elif "le" in endness:
endness = Endness.LE
elif "be" in endness:
endness = Endness.BE
elif "l" in endness:
endness = "unsure"
elif "b" in endness:
endness = "unsure"
else:
endness = "unsure"
ident = ident.lower()
cls = None
aendness = ""
for arxs, abits, aendness, acls in arch_id_map:
found_it = False
for rx in arxs:
if re.search(rx, ident):
found_it = True
break
if not found_it:
continue
if bits and bits != abits:
continue
if aendness == "any" or endness == aendness or endness == "unsure":
cls = acls
break
if not cls:
raise ArchNotFound(
f"Can't find architecture info for architecture {ident} with {repr(bits)} bits and {endness} endness"
)
if endness == "unsure":
if aendness == "any":
# We really don't care, use default
return cls()
else:
# We're expecting the ident to pick the endness.
# ex. 'armeb' means obviously this is Iend_BE
return cls(aendness)
else:
return cls(endness)
def reverse_ends(string):
count = (len(string) + 3) // 4
ise = "I" * count
string += b"\x00" * (count * 4 - len(string))
return _struct.pack(">" + ise, *_struct.unpack("<" + ise, string))
def get_host_arch():
"""
Return the arch of the machine we are currently running on.
"""
return arch_from_id(_platform.machine())

View File

@@ -0,0 +1,404 @@
import logging
l = logging.getLogger("archinfo.arch_aarch64")
try:
import capstone as _capstone
except ImportError:
_capstone = None
try:
import keystone as _keystone
except ImportError:
_keystone = None
try:
import unicorn as _unicorn
except ImportError:
_unicorn = None
from .arch import Arch, register_arch, Endness, Register
from .tls import TLSArchInfo
class ArchAArch64(Arch):
def __init__(self, endness=Endness.LE):
super().__init__(endness)
if endness == Endness.BE:
self.ida_processor = "armb"
self.function_prologs = set()
self.function_epilogs = set()
bits = 64
vex_arch = "VexArchARM64"
name = "AARCH64"
qemu_name = "aarch64"
ida_processor = "arm"
linux_name = "aarch64"
triplet = "aarch64-linux-gnueabihf"
max_inst_bytes = 4
ret_offset = 16
vex_conditional_helpers = True
syscall_num_offset = 80
call_pushes_ret = False
stack_change = -8
memory_endness = Endness.LE
register_endness = Endness.LE
instruction_endness = Endness.LE
sizeof = {"short": 16, "int": 32, "long": 64, "long long": 64}
if _capstone:
cs_arch = _capstone.CS_ARCH_ARM64
cs_mode = _capstone.CS_MODE_LITTLE_ENDIAN
if _keystone:
ks_arch = _keystone.KS_ARCH_ARM64
ks_mode = _keystone.KS_MODE_LITTLE_ENDIAN
uc_arch = _unicorn.UC_ARCH_ARM64 if _unicorn else None
uc_mode = _unicorn.UC_MODE_LITTLE_ENDIAN if _unicorn else None
uc_const = _unicorn.arm64_const if _unicorn else None
uc_prefix = "UC_ARM64_" if _unicorn else None
initial_sp = 0x7FFFFFFFFFF0000
ret_instruction = b"\xC0\x03\x5F\xD6" # ret
nop_instruction = b"\x1F\x20\x03\xD5" # nop
function_prologs = set()
function_epilogs = set()
instruction_alignment = 4
register_list = [
Register(
name="x0",
size=8,
subregisters=[("w0", 0, 4)],
alias_names=("r0",),
general_purpose=True,
argument=True,
linux_entry_value="ld_destructor",
),
Register(
name="x1", size=8, subregisters=[("w1", 0, 4)], alias_names=("r1",), general_purpose=True, argument=True
),
Register(
name="x2", size=8, subregisters=[("w2", 0, 4)], alias_names=("r2",), general_purpose=True, argument=True
),
Register(
name="x3", size=8, subregisters=[("w3", 0, 4)], alias_names=("r3",), general_purpose=True, argument=True
),
Register(
name="x4", size=8, subregisters=[("w4", 0, 4)], alias_names=("r4",), general_purpose=True, argument=True
),
Register(
name="x5", size=8, subregisters=[("w5", 0, 4)], alias_names=("r5",), general_purpose=True, argument=True
),
Register(
name="x6", size=8, subregisters=[("w6", 0, 4)], alias_names=("r6",), general_purpose=True, argument=True
),
Register(name="x7", size=8, subregisters=[("w7", 0, 4)], alias_names=("r7",), general_purpose=True),
Register(name="x8", size=8, subregisters=[("w8", 0, 4)], alias_names=("r8",), general_purpose=True),
Register(name="x9", size=8, subregisters=[("w9", 0, 4)], alias_names=("r9",), general_purpose=True),
Register(name="x10", size=8, subregisters=[("w10", 0, 4)], alias_names=("r10",), general_purpose=True),
Register(name="x11", size=8, subregisters=[("w11", 0, 4)], alias_names=("r11",), general_purpose=True),
Register(name="x12", size=8, subregisters=[("w12", 0, 4)], alias_names=("r12",), general_purpose=True),
Register(name="x13", size=8, subregisters=[("w13", 0, 4)], alias_names=("r13",), general_purpose=True),
Register(name="x14", size=8, subregisters=[("w14", 0, 4)], alias_names=("r14",), general_purpose=True),
Register(name="x15", size=8, subregisters=[("w15", 0, 4)], alias_names=("r15",), general_purpose=True),
Register(name="x16", size=8, subregisters=[("w16", 0, 4)], alias_names=("r16", "ip0"), general_purpose=True),
Register(name="x17", size=8, subregisters=[("w17", 0, 4)], alias_names=("r17", "ip1"), general_purpose=True),
Register(name="x18", size=8, subregisters=[("w18", 0, 4)], alias_names=("r18",), general_purpose=True),
Register(name="x19", size=8, subregisters=[("w19", 0, 4)], alias_names=("r19",), general_purpose=True),
Register(name="x20", size=8, subregisters=[("w20", 0, 4)], alias_names=("r20",), general_purpose=True),
Register(name="x21", size=8, subregisters=[("w21", 0, 4)], alias_names=("r21",), general_purpose=True),
Register(name="x22", size=8, subregisters=[("w22", 0, 4)], alias_names=("r22",), general_purpose=True),
Register(name="x23", size=8, subregisters=[("w23", 0, 4)], alias_names=("r23",), general_purpose=True),
Register(name="x24", size=8, subregisters=[("w24", 0, 4)], alias_names=("r24",), general_purpose=True),
Register(name="x25", size=8, subregisters=[("w25", 0, 4)], alias_names=("r25",), general_purpose=True),
Register(name="x26", size=8, subregisters=[("w26", 0, 4)], alias_names=("r26",), general_purpose=True),
Register(name="x27", size=8, subregisters=[("w27", 0, 4)], alias_names=("r27",), general_purpose=True),
Register(name="x28", size=8, subregisters=[("w28", 0, 4)], alias_names=("r28",), general_purpose=True),
Register(
name="x29", size=8, subregisters=[("w29", 0, 4)], alias_names=("r29", "fp", "bp"), general_purpose=True
),
Register(name="x30", size=8, subregisters=[("w30", 0, 4)], alias_names=("r30", "lr"), general_purpose=True),
Register(
name="xsp",
size=8,
subregisters=[("wsp", 0, 4)],
alias_names=("sp",),
general_purpose=True,
default_value=(initial_sp, True, "global"),
),
Register(name="pc", size=8, alias_names=("ip",)),
Register(name="cc_op", size=8, artificial=True),
Register(name="cc_dep1", size=8, artificial=True),
Register(name="cc_dep2", size=8, artificial=True),
Register(name="cc_ndep", size=8, artificial=True),
Register(name="tpidr_el0", size=8),
Register(
name="q0",
size=16,
subregisters=[("d0", 0, 8), ("s0", 0, 4), ("h0", 0, 2), ("b0", 0, 1)],
alias_names=("v0",),
floating_point=True,
vector=True,
),
Register(
name="q1",
size=16,
subregisters=[("d1", 0, 8), ("s1", 0, 4), ("h1", 0, 2), ("b1", 0, 1)],
alias_names=("v1",),
floating_point=True,
vector=True,
),
Register(
name="q2",
size=16,
subregisters=[("d2", 0, 8), ("s2", 0, 4), ("h2", 0, 2), ("b2", 0, 1)],
alias_names=("v2",),
floating_point=True,
vector=True,
),
Register(
name="q3",
size=16,
subregisters=[("d3", 0, 8), ("s3", 0, 4), ("h3", 0, 2), ("b3", 0, 1)],
alias_names=("v3",),
floating_point=True,
vector=True,
),
Register(
name="q4",
size=16,
subregisters=[("d4", 0, 8), ("s4", 0, 4), ("h4", 0, 2), ("b4", 0, 1)],
alias_names=("v4",),
floating_point=True,
vector=True,
),
Register(
name="q5",
size=16,
subregisters=[("d5", 0, 8), ("s5", 0, 4), ("h5", 0, 2), ("b5", 0, 1)],
alias_names=("v5",),
floating_point=True,
vector=True,
),
Register(
name="q6",
size=16,
subregisters=[("d6", 0, 8), ("s6", 0, 4), ("h6", 0, 2), ("b6", 0, 1)],
alias_names=("v6",),
floating_point=True,
vector=True,
),
Register(
name="q7",
size=16,
subregisters=[("d7", 0, 8), ("s7", 0, 4), ("h7", 0, 2), ("b7", 0, 1)],
alias_names=("v7",),
floating_point=True,
vector=True,
),
Register(
name="q8",
size=16,
subregisters=[("d8", 0, 8), ("s8", 0, 4), ("h8", 0, 2), ("b8", 0, 1)],
alias_names=("v8",),
floating_point=True,
vector=True,
),
Register(
name="q9",
size=16,
subregisters=[("d9", 0, 8), ("s9", 0, 4), ("h9", 0, 2), ("b9", 0, 1)],
alias_names=("v9",),
floating_point=True,
vector=True,
),
Register(
name="q10",
size=16,
subregisters=[("d10", 0, 8), ("s10", 0, 4), ("h10", 0, 2), ("b10", 0, 1)],
alias_names=("v10",),
floating_point=True,
vector=True,
),
Register(
name="q11",
size=16,
subregisters=[("d11", 0, 8), ("s11", 0, 4), ("h11", 0, 2), ("b11", 0, 1)],
alias_names=("v11",),
floating_point=True,
vector=True,
),
Register(
name="q12",
size=16,
subregisters=[("d12", 0, 8), ("s12", 0, 4), ("h12", 0, 2), ("b12", 0, 1)],
alias_names=("v12",),
floating_point=True,
vector=True,
),
Register(
name="q13",
size=16,
subregisters=[("d13", 0, 8), ("s13", 0, 4), ("h13", 0, 2), ("b13", 0, 1)],
alias_names=("v13",),
floating_point=True,
vector=True,
),
Register(
name="q14",
size=16,
subregisters=[("d14", 0, 8), ("s14", 0, 4), ("h14", 0, 2), ("b14", 0, 1)],
alias_names=("v14",),
floating_point=True,
vector=True,
),
Register(
name="q15",
size=16,
subregisters=[("d15", 0, 8), ("s15", 0, 4), ("h15", 0, 2), ("b15", 0, 1)],
alias_names=("v15",),
floating_point=True,
vector=True,
),
Register(
name="q16",
size=16,
subregisters=[("d16", 0, 8), ("s16", 0, 4), ("h16", 0, 2), ("b16", 0, 1)],
alias_names=("v16",),
floating_point=True,
vector=True,
),
Register(
name="q17",
size=16,
subregisters=[("d17", 0, 8), ("s17", 0, 4), ("h17", 0, 2), ("b17", 0, 1)],
alias_names=("v17",),
floating_point=True,
vector=True,
),
Register(
name="q18",
size=16,
subregisters=[("d18", 0, 8), ("s18", 0, 4), ("h18", 0, 2), ("b18", 0, 1)],
alias_names=("v18",),
floating_point=True,
vector=True,
),
Register(
name="q19",
size=16,
subregisters=[("d19", 0, 8), ("s19", 0, 4), ("h19", 0, 2), ("b19", 0, 1)],
alias_names=("v19",),
floating_point=True,
vector=True,
),
Register(
name="q20",
size=16,
subregisters=[("d20", 0, 8), ("s20", 0, 4), ("h20", 0, 2), ("b20", 0, 1)],
alias_names=("v20",),
floating_point=True,
vector=True,
),
Register(
name="q21",
size=16,
subregisters=[("d21", 0, 8), ("s21", 0, 4), ("h21", 0, 2), ("b21", 0, 1)],
alias_names=("v21",),
floating_point=True,
vector=True,
),
Register(
name="q22",
size=16,
subregisters=[("d22", 0, 8), ("s22", 0, 4), ("h22", 0, 2), ("b22", 0, 1)],
alias_names=("v22",),
floating_point=True,
vector=True,
),
Register(
name="q23",
size=16,
subregisters=[("d23", 0, 8), ("s23", 0, 4), ("h23", 0, 2), ("b23", 0, 1)],
alias_names=("v23",),
floating_point=True,
vector=True,
),
Register(
name="q24",
size=16,
subregisters=[("d24", 0, 8), ("s24", 0, 4), ("h24", 0, 2), ("b24", 0, 1)],
alias_names=("v24",),
floating_point=True,
vector=True,
),
Register(
name="q25",
size=16,
subregisters=[("d25", 0, 8), ("s25", 0, 4), ("h25", 0, 2), ("b25", 0, 1)],
alias_names=("v25",),
floating_point=True,
vector=True,
),
Register(
name="q26",
size=16,
subregisters=[("d26", 0, 8), ("s26", 0, 4), ("h26", 0, 2), ("b26", 0, 1)],
alias_names=("v26",),
floating_point=True,
vector=True,
),
Register(
name="q27",
size=16,
subregisters=[("d27", 0, 8), ("s27", 0, 4), ("h27", 0, 2), ("b27", 0, 1)],
alias_names=("v27",),
floating_point=True,
vector=True,
),
Register(
name="q28",
size=16,
subregisters=[("d28", 0, 8), ("s28", 0, 4), ("h28", 0, 2), ("b28", 0, 1)],
alias_names=("v28",),
floating_point=True,
vector=True,
),
Register(
name="q29",
size=16,
subregisters=[("d29", 0, 8), ("s29", 0, 4), ("h29", 0, 2), ("b29", 0, 1)],
alias_names=("v29",),
floating_point=True,
vector=True,
),
Register(
name="q30",
size=16,
subregisters=[("d30", 0, 8), ("s30", 0, 4), ("h30", 0, 2), ("b30", 0, 1)],
alias_names=("v30",),
floating_point=True,
vector=True,
),
Register(
name="q31",
size=16,
subregisters=[("d31", 0, 8), ("s31", 0, 4), ("h31", 0, 2), ("b31", 0, 1)],
alias_names=("v31",),
floating_point=True,
vector=True,
),
Register(name="qcflag", size=16, floating_point=True),
Register(name="emnote", size=4, artificial=True),
Register(name="cmstart", size=8),
Register(name="cmlen", size=8),
Register(name="nraddr", size=8),
Register(name="ip_at_syscall", size=8, artificial=True),
Register(name="fpcr", size=4, floating_point=True, default_value=(initial_sp, True, "global")),
]
got_section_name = ".got"
ld_linux_name = "ld-linux-aarch64.so.1"
elf_tls = TLSArchInfo(1, 32, [], [0], [], 0, 0)
register_arch([r".*arm64.*|.*aarch64*"], 64, "any", ArchAArch64)

View File

@@ -0,0 +1,458 @@
import logging
l = logging.getLogger("archinfo.arch_amd64")
try:
import capstone as _capstone
except ImportError:
_capstone = None
try:
import keystone as _keystone
except ImportError:
_keystone = None
try:
import unicorn as _unicorn
except ImportError:
_unicorn = None
try:
import pyvex as _pyvex
except ImportError:
_pyvex = None
from .arch import Arch, register_arch, Endness, Register
from .tls import TLSArchInfo
from .archerror import ArchError
_NATIVE_FUNCTION_PROLOGS = [
rb"\x55\x48\x89\xe5", # push rbp; mov rbp, rsp
rb"\x48[\x83,\x81]\xec[\x00-\xff]", # sub rsp, xxx
]
# every function prolog can potentially be prefixed with endbr64
_endbr64 = b"\xf3\x0f\x1e\xfa"
_prefixed = [(_endbr64 + prolog) for prolog in _NATIVE_FUNCTION_PROLOGS]
_FUNCTION_PROLOGS = _prefixed + _NATIVE_FUNCTION_PROLOGS
class ArchAMD64(Arch):
def __init__(self, endness=Endness.LE):
if endness != Endness.LE:
raise ArchError("Arch AMD64 must be little endian")
super().__init__(endness)
self.argument_register_positions = (
{
self.registers["rdi"][0]: 0,
self.registers["rsi"][0]: 1,
self.registers["rdx"][0]: 2,
self.registers["rcx"][0]: 3, # Used for user calls
self.registers["r10"][0]: 3, # Used for Linux kernel calls
self.registers["r8"][0]: 4,
self.registers["r9"][0]: 5,
# fp registers
self.registers["xmm0"][0]: 0,
self.registers["xmm1"][0]: 1,
self.registers["xmm2"][0]: 2,
self.registers["xmm3"][0]: 3,
self.registers["xmm4"][0]: 4,
self.registers["xmm5"][0]: 5,
self.registers["xmm6"][0]: 6,
self.registers["xmm7"][0]: 7,
}
if _pyvex is not None
else None
)
# Register blacklist
reg_blacklist = ("fs", "gs")
if self.reg_blacklist is not None and self.reg_blacklist_offsets is not None:
for register in self.register_list:
if register.name in reg_blacklist:
self.reg_blacklist.append(register.name)
self.reg_blacklist_offsets.append(register.vex_offset)
if _unicorn and _pyvex:
# CPU flag registers
uc_flags_reg = _unicorn.x86_const.UC_X86_REG_EFLAGS
cpu_flag_registers = {"d": 1 << 10, "ac": 1 << 18, "id": 1 << 21}
for reg, reg_bitmask in cpu_flag_registers.items():
reg_offset = self.get_register_offset(reg)
self.cpu_flag_register_offsets_and_bitmasks_map[reg_offset] = (uc_flags_reg, reg_bitmask)
mxcsr_registers = {"sseround": 1 << 14 | 1 << 13}
uc_mxcsr_reg = _unicorn.x86_const.UC_X86_REG_MXCSR
for reg, reg_bitmask in mxcsr_registers.items():
reg_offset = self.get_register_offset(reg)
self.cpu_flag_register_offsets_and_bitmasks_map[reg_offset] = (uc_mxcsr_reg, reg_bitmask)
@property
def capstone_x86_syntax(self):
"""
The current syntax Capstone uses for x64. It can be 'intel' or 'at&t'
"""
return self._cs_x86_syntax
@capstone_x86_syntax.setter
def capstone_x86_syntax(self, new_syntax):
if new_syntax not in ("intel", "at&t"):
raise ArchError('Unsupported Capstone x86 syntax. It must be either "intel" or "at&t".')
if new_syntax != self._cs_x86_syntax:
self._cs = None
self._cs_x86_syntax = new_syntax
def _configure_capstone(self):
if self._cs_x86_syntax == "at&t":
self._cs.syntax = _capstone.CS_OPT_SYNTAX_ATT
else:
self._cs.syntax = _capstone.CS_OPT_SYNTAX_INTEL
@property
def keystone_x86_syntax(self):
"""
The current syntax Keystone uses for x86. It can be 'intel',
'at&t', 'nasm', 'masm', 'gas' or 'radix16'
"""
return self._ks_x86_syntax
@keystone_x86_syntax.setter
def keystone_x86_syntax(self, new_syntax):
if new_syntax not in ("intel", "at&t", "nasm", "masm", "gas", "radix16"):
raise ArchError(
"Unsupported Keystone x86 syntax. It must be one of the following: "
'"intel", "at&t", "nasm", "masm", "gas" or "radix16".'
)
if new_syntax != self._ks_x86_syntax:
self._ks = None
self._ks_x86_syntax = new_syntax
def _configure_keystone(self):
if self._ks_x86_syntax == "at&t":
self._ks.syntax = _keystone.KS_OPT_SYNTAX_ATT
elif self._ks_x86_syntax == "nasm":
self._ks.syntax = _keystone.KS_OPT_SYNTAX_NASM
elif self._ks_x86_syntax == "masm":
self._ks.syntax = _keystone.KS_OPT_SYNTAX_MASM
elif self._ks_x86_syntax == "gas":
self._ks.syntax = _keystone.KS_OPT_SYNTAX_GAS
elif self._ks_x86_syntax == "radix16":
self._ks.syntax = _keystone.KS_OPT_SYNTAX_RADIX16
else:
self._ks.syntax = _keystone.KS_OPT_SYNTAX_INTEL
bits = 64
vex_arch = "VexArchAMD64"
vex_endness = "VexEndnessLE"
name = "AMD64"
qemu_name = "x86_64"
ida_processor = "metapc"
linux_name = "x86_64"
triplet = "x86_64-linux-gnu"
max_inst_bytes = 15
ret_offset = 16
vex_conditional_helpers = True
syscall_num_offset = 16
call_pushes_ret = True
stack_change = -8
initial_sp = 0x7FFFFFFFFFF0000
call_sp_fix = -8
memory_endness = Endness.LE
register_endness = Endness.LE
sizeof = {"short": 16, "int": 32, "long": 64, "long long": 64}
if _capstone:
cs_arch = _capstone.CS_ARCH_X86
cs_mode = _capstone.CS_MODE_64 + _capstone.CS_MODE_LITTLE_ENDIAN
_cs_x86_syntax = None # Set it to 'att' in order to use AT&T syntax for x86
if _keystone:
ks_arch = _keystone.KS_ARCH_X86
ks_mode = _keystone.KS_MODE_64 + _keystone.KS_MODE_LITTLE_ENDIAN
_ks_x86_syntax = None
uc_arch = _unicorn.UC_ARCH_X86 if _unicorn else None
uc_mode = (_unicorn.UC_MODE_64 + _unicorn.UC_MODE_LITTLE_ENDIAN) if _unicorn else None
uc_const = _unicorn.x86_const if _unicorn else None
uc_prefix = "UC_X86_" if _unicorn else None
function_prologs = _FUNCTION_PROLOGS
function_epilogs = {
rb"\xc9\xc3", # leaveq; retq
rb"([^\x41][\x50-\x5f]{1}|\x41[\x50-\x5f])\xc3", # pop <reg>; retq
rb"\x48[\x83,\x81]\xc4([\x00-\xff]{1}|[\x00-\xff]{4})\xc3", # add rsp, <siz>; retq
}
ret_instruction = b"\xc3"
nop_instruction = b"\x90"
instruction_alignment = 1
register_list = [
Register(
name="rax",
size=8,
subregisters=[("eax", 0, 4), ("ax", 0, 2), ("al", 0, 1), ("ah", 1, 1)],
general_purpose=True,
linux_entry_value=0x1C,
),
Register(
name="rcx",
size=8,
subregisters=[("ecx", 0, 4), ("cx", 0, 2), ("cl", 0, 1), ("ch", 1, 1)],
general_purpose=True,
argument=True,
),
Register(
name="rdx",
size=8,
subregisters=[("edx", 0, 4), ("dx", 0, 2), ("dl", 0, 1), ("dh", 1, 1)],
general_purpose=True,
argument=True,
linux_entry_value="ld_destructor",
),
Register(
name="rbx",
size=8,
subregisters=[("ebx", 0, 4), ("bx", 0, 2), ("bl", 0, 1), ("bh", 1, 1)],
general_purpose=True,
linux_entry_value=0,
),
Register(
name="rsp",
size=8,
subregisters=[("esp", 0, 4)],
alias_names=("sp",),
general_purpose=True,
default_value=(initial_sp, True, "global"),
),
Register(
name="rbp",
size=8,
subregisters=[("ebp", 0, 4), ("_bp", 0, 2), ("bpl", 0, 1), ("bph", 1, 1)],
alias_names=("bp",),
general_purpose=True,
linux_entry_value=0,
),
Register(
name="rsi",
size=8,
subregisters=[("esi", 0, 4), ("si", 0, 2), ("sil", 0, 1), ("sih", 1, 1)],
general_purpose=True,
argument=True,
linux_entry_value="argv",
),
Register(
name="rdi",
size=8,
subregisters=[("edi", 0, 4), ("di", 0, 2), ("dil", 0, 1), ("dih", 1, 1)],
general_purpose=True,
argument=True,
linux_entry_value="argc",
),
Register(
name="r8",
size=8,
subregisters=[("r8d", 0, 4), ("r8w", 0, 2), ("r8b", 0, 1)],
general_purpose=True,
argument=True,
),
Register(
name="r9",
size=8,
subregisters=[("r9d", 0, 4), ("r9w", 0, 2), ("r9b", 0, 1)],
general_purpose=True,
argument=True,
),
Register(
name="r10",
size=8,
subregisters=[("r10d", 0, 4), ("r10w", 0, 2), ("r10b", 0, 1)],
general_purpose=True,
argument=True,
),
Register(
name="r11", size=8, subregisters=[("r11d", 0, 4), ("r11w", 0, 2), ("r11b", 0, 1)], general_purpose=True
),
Register(
name="r12",
size=8,
subregisters=[("r12d", 0, 4), ("r12w", 0, 2), ("r12b", 0, 1)],
general_purpose=True,
linux_entry_value=0,
),
Register(
name="r13",
size=8,
subregisters=[("r13d", 0, 4), ("r13w", 0, 2), ("r13b", 0, 1)],
general_purpose=True,
linux_entry_value=0,
),
Register(
name="r14",
size=8,
subregisters=[("r14d", 0, 4), ("r14w", 0, 2), ("r14b", 0, 1)],
general_purpose=True,
linux_entry_value=0,
),
Register(
name="r15",
size=8,
subregisters=[("r15d", 0, 4), ("r15w", 0, 2), ("r15b", 0, 1)],
general_purpose=True,
linux_entry_value=0,
),
Register(name="cc_op", size=8, default_value=(0, False, None), concrete=False, artificial=True),
Register(name="cc_dep1", size=8, concrete=False, artificial=True),
Register(name="cc_dep2", size=8, concrete=False, artificial=True),
Register(name="cc_ndep", size=8, concrete=False, artificial=True, linux_entry_value=0),
Register(name="d", size=8, alias_names=("dflag",), default_value=(1, False, None), concrete=False),
Register(name="rip", size=8, alias_names=("ip", "pc"), general_purpose=True),
Register(name="ac", size=8, alias_names=("acflag",), concrete=False),
Register(name="id", size=8, alias_names=("idflag",)),
Register(
name="fs",
size=8,
vex_name="fs_const",
alias_names=("fs_const",),
default_value=(0x9000000000000000, True, "global"),
concrete=False,
),
Register(name="sseround", size=8, vector=True, default_value=(0, False, None)),
Register(name="cr0", size=8),
Register(name="cr2", size=8),
Register(name="cr3", size=8),
Register(name="cr4", size=8),
Register(name="cr8", size=8),
Register(
name="ymm0",
size=32,
subregisters=[("xmm0", 0, 16), ("xmm0lq", 0, 8), ("xmm0hq", 8, 8), ("ymm0hx", 16, 16)],
vector=True,
),
Register(
name="ymm1",
size=32,
subregisters=[("xmm1", 0, 16), ("xmm1lq", 0, 8), ("xmm1hq", 8, 8), ("ymm1hx", 16, 16)],
vector=True,
),
Register(
name="ymm2",
size=32,
subregisters=[("xmm2", 0, 16), ("xmm2lq", 0, 8), ("xmm2hq", 8, 8), ("ymm2hx", 16, 16)],
vector=True,
),
Register(
name="ymm3",
size=32,
subregisters=[("xmm3", 0, 16), ("xmm3lq", 0, 8), ("xmm3hq", 8, 8), ("ymm3hx", 16, 16)],
vector=True,
),
Register(
name="ymm4",
size=32,
subregisters=[("xmm4", 0, 16), ("xmm4lq", 0, 8), ("xmm4hq", 8, 8), ("ymm4hx", 16, 16)],
vector=True,
),
Register(
name="ymm5",
size=32,
subregisters=[("xmm5", 0, 16), ("xmm5lq", 0, 8), ("xmm5hq", 8, 8), ("ymm5hx", 16, 16)],
vector=True,
),
Register(
name="ymm6",
size=32,
subregisters=[("xmm6", 0, 16), ("xmm6lq", 0, 8), ("xmm6hq", 8, 8), ("ymm6hx", 16, 16)],
vector=True,
),
Register(
name="ymm7",
size=32,
subregisters=[("xmm7", 0, 16), ("xmm7lq", 0, 8), ("xmm7hq", 8, 8), ("ymm7hx", 16, 16)],
vector=True,
),
Register(
name="ymm8",
size=32,
subregisters=[("xmm8", 0, 16), ("xmm8lq", 0, 8), ("xmm8hq", 8, 8), ("ymm8hx", 16, 16)],
vector=True,
),
Register(
name="ymm9",
size=32,
subregisters=[("xmm9", 0, 16), ("xmm9lq", 0, 8), ("xmm9hq", 8, 8), ("ymm9hx", 16, 16)],
vector=True,
),
Register(
name="ymm10",
size=32,
subregisters=[("xmm10", 0, 16), ("xmm10lq", 0, 8), ("xmm10hq", 8, 8), ("ymm10hx", 16, 16)],
vector=True,
),
Register(
name="ymm11",
size=32,
subregisters=[("xmm11", 0, 16), ("xmm11lq", 0, 8), ("xmm11hq", 8, 8), ("ymm11hx", 16, 16)],
vector=True,
),
Register(
name="ymm12",
size=32,
subregisters=[("xmm12", 0, 16), ("xmm12lq", 0, 8), ("xmm12hq", 8, 8), ("ymm12hx", 16, 16)],
vector=True,
),
Register(
name="ymm13",
size=32,
subregisters=[("xmm13", 0, 16), ("xmm13lq", 0, 8), ("xmm13hq", 8, 8), ("ymm13hx", 16, 16)],
vector=True,
),
Register(
name="ymm14",
size=32,
subregisters=[("xmm14", 0, 16), ("xmm14lq", 0, 8), ("xmm14hq", 8, 8), ("ymm14hx", 16, 16)],
vector=True,
),
Register(
name="ymm15",
size=32,
subregisters=[("xmm15", 0, 16), ("xmm15lq", 0, 8), ("xmm15hq", 8, 8), ("ymm15hx", 16, 16)],
vector=True,
),
Register(name="ftop", size=4, floating_point=True, default_value=(7, False, None), artificial=True),
Register(
name="fpreg",
size=64,
subregisters=[
("mm0", 0, 8),
("mm1", 8, 8),
("mm2", 16, 8),
("mm3", 24, 8),
("mm4", 32, 8),
("mm5", 40, 8),
("mm6", 48, 8),
("mm7", 56, 8),
],
alias_names=("fpu_regs",),
floating_point=True,
),
Register(name="fptag", size=8, alias_names=("fpu_tags",), floating_point=True, default_value=(0, False, None)),
Register(name="fpround", size=8, floating_point=True, default_value=(0, False, None)),
Register(name="fc3210", size=8, floating_point=True),
Register(name="emnote", size=4, artificial=True),
Register(name="cmstart", size=8),
Register(name="cmlen", size=8),
Register(name="nraddr", size=8),
Register(name="gs", size=8, vex_name="gs_const", alias_names=("gs_const",), concrete=False),
Register(name="ip_at_syscall", size=8, concrete=False, artificial=True),
Register(name="cs_seg", size=2, vex_name="cs"),
Register(name="ds_seg", size=2, vex_name="ds"),
Register(name="es_seg", size=2, vex_name="es"),
Register(name="fs_seg", size=2, vex_name="fs"),
Register(name="fs_seg", size=2, vex_name="gs"),
Register(name="ss_seg", size=2, vex_name="ss"),
]
symbol_type_translation = {10: "STT_GNU_IFUNC", "STT_LOOS": "STT_GNU_IFUNC"}
got_section_name = ".got.plt"
ld_linux_name = "ld-linux-x86-64.so.2"
elf_tls = TLSArchInfo(2, 704, [16], [8], [0], 0, 0)
register_arch([r".*amd64|.*x64|.*x86_64|.*metapc"], 64, Endness.LE, ArchAMD64)

View File

@@ -0,0 +1,550 @@
from .arch import Arch, register_arch, Endness, Register
from .tls import TLSArchInfo
import logging
l = logging.getLogger("archinfo.arch_arm")
try:
import capstone as _capstone
except ImportError:
_capstone = None
try:
import keystone as _keystone
except ImportError:
_keystone = None
try:
import unicorn as _unicorn
except ImportError:
_unicorn = None
# TODO: determine proper base register (if it exists)
# TODO: handle multiple return registers?
# TODO: which endianness should be default?
def is_arm_arch(a):
return a.name.startswith("ARM")
def get_real_address_if_arm(arch, addr):
"""
Obtain the real address of an instruction. ARM architectures are supported.
:param Arch arch: The Arch object.
:param int addr: The instruction address.
:return: The real address of an instruction.
:rtype: int
"""
return ((addr >> 1) << 1) if is_arm_arch(arch) else addr
class ArchARM(Arch):
"""
ARM architecture specific subclass
"""
def __init__(self, endness=Endness.LE):
instruction_endness = None
if endness == Endness.LE:
instruction_endness = Endness.LE
super().__init__(endness, instruction_endness=instruction_endness)
if endness == Endness.BE:
self.function_prologs = {
# br"\xe9\x2d[\x40-\x7f\xc0-\xff][\x00-\xff]", # stmfd sp!, {xxxxx, lr}
rb"\xe5\x2d\xe0\x04", # push {lr}
rb"\xe1\xa0\xc0\x0c\xe5\x2d\xe0\x04",
}
self.thumb_prologs = {
# push.w {r4, r5, r7, r8, lr}
rb"\xe9\x2d\x41\xb0",
# push.w {r4-r7, r8, lr} | push.w {r4-r9, lr} | push.w {r4-r7, r9, r10, lr} | push.w {r4-r10, lr} |
# push.w {r4-r8, r10, r11, lr} | push.w {r4-r11, lr}
rb"\xe9\x2d[\x41\x43\x46\x47\x4d\x4f]\xf0",
# push.w {r3-r9, lr} | push.w {r3-r7, r9, r10, lr} | push.w {r3-r11, lr}
rb"\xe9\x2d[\x43\x46\x4f]\xf8",
rb"[\xb4\xb5][\x00\x10\x30\x70\xf0]\xb0[\x80-\x8f\xa3\xa8]",
# push {??, ??, ..., ??, lr}; sub sp, sp, #??
rb"\xb4\x80\xb0[\x80-\xff]", # push {r7}; sub sp, sp, #??
rb"\xb4[\x00-\xff]\xb5\x00\xb0[\x80-\xff]", # push {r?, r?}; push {lr}; sub sp, sp, #??
rb"\xb0[\x80-\xff]\x90[\x00-\xff]", # sub sp, sp, #??; str r0, [sp, ?]
# stmt0: push {lr} | push {r3, lr} | push {r4, lr} | push {r4, r5, lr} | push {r3, r4, r5, lr} |
# push {r4, r5, r6, lr} | push {r4, r5, r6, r7, lr} | push {r3, r4, r5, r6, r7, lr}
# stmt1: ldr r4, [pc, #??]
# stmt2: add sp, r4
rb"\xb5[\x00\x08\x10\x30\x38\x70\xf0\xf8]\x4c[\x00-\xff]\x44\xa5",
# stmt0: push {lr} | push {r3, lr} | push {r4, lr} | push {r4, r5, lr} | push {r3, r4, r5, lr} |
# push {r4, r5, r6, lr} | push {r4, r5, r6, r7, lr} | push {r3, r4, r5, r6, r7, lr}
# stmt1: mov r3/r4/r5/r6/r7, r0 | mov r4/r5/r6/r7, r1 | mov r6/r7, r3
rb"\xb5[\x00\x08\x10\x30\x38\x70\xf0\xf8]\x46[\x03-\x07\x0c-\x0f\x1e-\x1f]",
# stmt0: push {r3, lr}
# stmt1: movs r2/r3, #0
rb"\xb5\x08[\x22\x23]\x00",
# ldr r3, [pc, #??]; ldr r2, [pc, #??]; add r3, pc; push {r4,r5,lr}
rb"\x4b[\x00-\xff]\x4a[\x00-\xff]\x44\x7b\xb5\x30",
# push {r3,r4,r5,lr}; mov r3, #0;
rb"\xb5\x38\xf2\x40\x03\x00\xf2\xc0\x03\x00",
}
self.function_epilogs = {
rb"\xe8\xbd[\x00-\xff]{2}\xe1\x2f\xff\x1e" # pop {xxx}; bx lr
rb"\xe4\x9d\xe0\x04\xe1\x2f\xff\x1e" # pop {xxx}; bx lr
}
# ArchARM will match with any ARM, but ArchARMEL/ArchARMHF is a mismatch
def __eq__(self, other):
# pylint: disable=unidiomatic-typecheck
if not isinstance(other, ArchARM):
return False
if self.memory_endness != other.memory_endness or self.bits != other.bits:
return False
if type(self) is type(other):
return True
if type(self) is ArchARM or type(other) is ArchARM:
return True
return False
def __getstate__(self):
self._cs = None
self._cs_thumb = None
self._ks = None
self._ks_thumb = None
return super().__getstate__()
@property
def capstone_thumb(self):
if _capstone is None:
l.warning("Capstone is not installed!")
return None
if self._cs_thumb is None:
self._cs_thumb = _capstone.Cs(self.cs_arch, self.cs_mode + _capstone.CS_MODE_THUMB)
self._cs_thumb.detail = True
return self._cs_thumb
@property
def keystone_thumb(self):
if _keystone is None:
l.warning("Keystone is not installed!")
return None
if self._ks_thumb is None:
self._ks_thumb = _keystone.Ks(self.ks_arch, _keystone.KS_MODE_THUMB)
return self._ks_thumb
@property
def unicorn_thumb(self):
if _unicorn is None:
l.warning("Unicorn is not installed!")
return None
return _unicorn.Uc(self.uc_arch, self.uc_mode + _unicorn.UC_MODE_THUMB)
def m_addr(self, addr, *args, **kwargs):
"""
Given the address of some code block, convert it to the address where this block
is stored in memory. The memory address can also be referred to as the "real" address.
For ARM-architecture, the "real" address is always even (has its lowest bit clear).
:param addr: The address to convert.
:return: The "real" address in memory.
:rtype: int
"""
return addr & ~1
# pylint: disable=keyword-arg-before-vararg, arguments-differ
def x_addr(self, addr, thumb=None, *args, **kwargs):
"""
Given the address of some code block, convert it to the value that should be assigned
to the instruction pointer register in order to execute the code in that block.
:param addr: The address to convert.
:param thumb: Set this parameter to True if you want to convert the address into the THUMB form.
Set this parameter to False if you want to convert the address into the ARM form.
Set this parameter to None (default) if you want to keep the address as is.
:return: The "execution" address.
:rtype: int
"""
if thumb is None:
return addr
elif not thumb:
return addr & ~1
else: # thumb
return addr | 1
def is_thumb(self, addr): # pylint:disable=unused-argument
"""
Return True, if the address is the THUMB address. False otherwise.
:param addr: The address to check.
:return: Whether the given address is the THUMB address.
"""
return bool(addr & 1)
bits = 32
vex_arch = "VexArchARM"
name = "ARMEL"
qemu_name = "arm"
ida_processor = "armb"
linux_name = "arm"
triplet = "arm-linux-gnueabihf"
max_inst_bytes = 4
ret_offset = 8
fp_ret_offset = 8
vex_conditional_helpers = True
syscall_num_offset = 36
call_pushes_ret = False
stack_change = -4
memory_endness = Endness.LE
register_endness = Endness.LE
sizeof = {"short": 16, "int": 32, "long": 32, "long long": 64}
if _capstone:
cs_arch = _capstone.CS_ARCH_ARM
cs_mode = _capstone.CS_MODE_LITTLE_ENDIAN
_cs_thumb = None
if _keystone:
ks_arch = _keystone.KS_ARCH_ARM
ks_mode = _keystone.KS_MODE_ARM + _keystone.KS_MODE_LITTLE_ENDIAN
_ks_thumb = None
uc_arch = _unicorn.UC_ARCH_ARM if _unicorn else None
uc_mode = _unicorn.UC_MODE_LITTLE_ENDIAN if _unicorn else None
uc_mode_thumb = _unicorn.UC_MODE_LITTLE_ENDIAN + _unicorn.UC_MODE_THUMB if _unicorn else None
uc_const = _unicorn.arm_const if _unicorn else None
uc_prefix = "UC_ARM_" if _unicorn else None
# self.ret_instruction = b"\x0E\xF0\xA0\xE1" # this is mov pc, lr
ret_instruction = b"\x1E\xFF\x2F\xE1" # this is bx lr
nop_instruction = b"\x00\x00\x00\x00"
function_prologs = {
# br"[\x00-\xff][\x40-\x7f\xc0-\xff]\x2d\xe9", # stmfd sp!, {xxxxx,lr}
rb"\x04\xe0\x2d\xe5", # push {lr}
rb"\r\xc0\xa0\xe1[\x00-\xff][\x40-\x7f\xc0-\xff]\x2d\xe9", # mov r12, sp; stmfd sp!, {xxxxx,lr}
rb"\r\xc0\xa0\xe1\x04\xe0\x2d\xe5", # mov r12, sp; push {lr}
}
thumb_prologs = {
# push.w {r4, r5, r7, r8, lr}
rb"\x2d\xe9\xb0\x41",
# push.w {r4-r7, r8, lr} | push.w {r4-r9, lr} | push.w {r4-r7, r9, r10, lr} | push.w {r4-r10, lr} |
# push.w {r4-r8, r10, r11, lr} | push.w {r4-r11, lr}
rb"\x2d\xe9\xf0[\x41\x43\x46\x47\x4d\x4f]",
# push.w {r3-r9, lr} | push.w {r3-r7, r9, r10, lr} | push.w {r3-r11, lr}
rb"\x2d\xe9\xf8[\x43\x46\x4f]",
rb"[\x00\x10\x30\x70\xf0][\xb4\xb5][\x80-\x8f\xa3\xa8]\xb0", # push {??, ??, ..., ??, lr}; sub sp, sp, #??
rb"\x80\xb4[\x80-\xff]\xb0", # push {r7}; sub sp, sp, #??
rb"[\x00-\xff]\xb4\x00\xb5[\x80-\xff]\xb0", # push {r?, r?}; push {lr}; sub sp, sp, #??
rb"[\x80-\xff]\xb0[\x00-\xff]\x90", # sub sp, sp, #??; str r0, [sp, ?]
# stmt0: push {lr} | push {r3, lr} | push {r4, lr} | push {r4, r5, lr} | push {r3, r4, r5, lr} |
# push {r4, r5, r6, lr} | push {r4, r5, r6, r7, lr} | push {r3, r4, r5, r6, r7, lr}
# stmt1: ldr r4, [pc, #??]
# stmt2: add sp, r4
rb"[\x00\x08\x10\x30\x38\x70\xf0\xf8]\xb5[\x00-\xff]\x4c\xa5\x44",
# stmt0: push {lr} | push {r3, lr} | push {r4, lr} | push {r4, r5, lr} | push {r3, r4, r5, lr} |
# push {r4, r5, r6, lr} | push {r4, r5, r6, r7, lr} | push {r3, r4, r5, r6, r7, lr}
# stmt1: mov r3/r4/r5/r6/r7, r0 | mov r4/r5/r6/r7, r1 | mov r6/r7, r3
rb"[\x00\x08\x10\x30\x38\x70\xf0\xf8]\xb5[\x03-\x07\x0c-\x0f\x1e-\x1f]\x46",
# stmt0: push {r3, lr}
# stmt1: movs r2/r3, #0
rb"\x08\xb5\x00[\x22\x23]",
# ldr r3, [pc, #??]; ldr r2, [pc, #??]; add r3, pc; push {r4,r5,lr}
rb"[\x00-\xff]\x4b[\x00-\xff]\x4a\x7b\x44\x30\xb5",
# push {r3,r4,r5,lr}; mov r3, #0;
rb"\x38\xb5\x40\xf2\x00\x03\xc0\xf2\x00\x03",
}
function_epilogs = {
rb"[\x00-\xff]{2}\xbd\xe8\x1e\xff\x2f\xe1" # pop {xxx}; bx lr
rb"\x04\xe0\x9d\xe4\x1e\xff\x2f\xe1" # pop {xxx}; bx lr
}
instruction_alignment = 2 # cuz there is also thumb mode
register_list = [
Register(
name="r0",
size=4,
alias_names=("a1",),
general_purpose=True,
argument=True,
linux_entry_value="ld_destructor",
),
Register(name="r1", size=4, alias_names=("a2",), general_purpose=True, argument=True),
Register(name="r2", size=4, alias_names=("a3",), general_purpose=True, argument=True),
Register(name="r3", size=4, alias_names=("a4",), general_purpose=True, argument=True),
Register(name="r4", size=4, alias_names=("v1",), general_purpose=True),
Register(name="r5", size=4, alias_names=("v2",), general_purpose=True),
Register(name="r6", size=4, alias_names=("v3",), general_purpose=True),
Register(name="r7", size=4, alias_names=("v4",), general_purpose=True),
Register(name="r8", size=4, alias_names=("v5",), general_purpose=True),
Register(name="r9", size=4, alias_names=("v6", "sb"), general_purpose=True),
Register(name="r10", size=4, alias_names=("v7", "sl"), general_purpose=True),
Register(name="r11", size=4, alias_names=("v8", "fp", "bp"), general_purpose=True),
Register(name="r12", size=4, general_purpose=True),
# r12 is sometimes known as "ip" (intraprocedural call scratch) but we can't have that...
Register(
name="sp",
size=4,
alias_names=("r13",),
general_purpose=True,
default_value=(Arch.initial_sp, True, "global"),
),
Register(name="lr", size=4, alias_names=("r14",), general_purpose=True, concretize_unique=True),
Register(name="pc", size=4, vex_name="r15t", alias_names=("r15", "ip")),
Register(name="cc_op", size=4, default_value=(0, False, None), artificial=True, concrete=False),
Register(name="cc_dep1", size=4, default_value=(0, False, None), artificial=True, concrete=False),
Register(name="cc_dep2", size=4, default_value=(0, False, None), artificial=True, concrete=False),
Register(name="cc_ndep", size=4, default_value=(0, False, None), artificial=True, concrete=False),
Register(name="qflag32", size=4, default_value=(0, False, None), artificial=True, concrete=False),
Register(name="geflag0", size=4, vector=True, default_value=(0, False, None), artificial=True, concrete=False),
Register(name="geflag1", size=4, vector=True, default_value=(0, False, None), artificial=True, concrete=False),
Register(name="geflag2", size=4, vector=True, default_value=(0, False, None), artificial=True, concrete=False),
Register(name="geflag3", size=4, vector=True, default_value=(0, False, None), artificial=True, concrete=False),
Register(name="emnote", size=4, vector=True, default_value=(0, False, None), artificial=True, concrete=False),
Register(name="cmstart", size=4, artificial=True, vector=True, default_value=(0, False, None), concrete=False),
Register(name="cmlen", size=4, artificial=True, default_value=(0, False, None), concrete=False),
Register(name="nraddr", size=4, artificial=True, default_value=(0, False, None), concrete=False),
Register(name="ip_at_syscall", size=4, artificial=True, concrete=False),
Register(name="d0", size=8, floating_point=True, vector=True, subregisters=[("s0", 0, 4), ("s1", 4, 4)]),
Register(name="d1", size=8, floating_point=True, vector=True, subregisters=[("s2", 0, 4), ("s3", 4, 4)]),
Register(name="d2", size=8, floating_point=True, vector=True, subregisters=[("s4", 0, 4), ("s5", 4, 4)]),
Register(name="d3", size=8, floating_point=True, vector=True, subregisters=[("s6", 0, 4), ("s7", 4, 4)]),
Register(name="d4", size=8, floating_point=True, vector=True, subregisters=[("s8", 0, 4), ("s9", 4, 4)]),
Register(name="d5", size=8, floating_point=True, vector=True, subregisters=[("s10", 0, 4), ("s11", 4, 4)]),
Register(name="d6", size=8, floating_point=True, vector=True, subregisters=[("s12", 0, 4), ("s13", 4, 4)]),
Register(name="d7", size=8, floating_point=True, vector=True, subregisters=[("s14", 0, 4), ("s15", 4, 4)]),
Register(name="d8", size=8, floating_point=True, vector=True, subregisters=[("s16", 0, 4), ("s17", 4, 4)]),
Register(name="d9", size=8, floating_point=True, vector=True, subregisters=[("s18", 0, 4), ("s19", 4, 4)]),
Register(name="d10", size=8, floating_point=True, vector=True, subregisters=[("s20", 0, 4), ("s21", 4, 4)]),
Register(name="d11", size=8, floating_point=True, vector=True, subregisters=[("s22", 0, 4), ("s23", 4, 4)]),
Register(name="d12", size=8, floating_point=True, vector=True, subregisters=[("s24", 0, 4), ("s25", 4, 4)]),
Register(name="d13", size=8, floating_point=True, vector=True, subregisters=[("s26", 0, 4), ("s27", 4, 4)]),
Register(name="d14", size=8, floating_point=True, vector=True, subregisters=[("s28", 0, 4), ("s29", 4, 4)]),
Register(name="d15", size=8, floating_point=True, vector=True, subregisters=[("s30", 0, 4), ("s31", 4, 4)]),
Register(name="d16", size=8, floating_point=True, vector=True),
Register(name="d17", size=8, floating_point=True, vector=True),
Register(name="d18", size=8, floating_point=True, vector=True),
Register(name="d19", size=8, floating_point=True, vector=True),
Register(name="d20", size=8, floating_point=True, vector=True),
Register(name="d21", size=8, floating_point=True, vector=True),
Register(name="d22", size=8, floating_point=True, vector=True),
Register(name="d23", size=8, floating_point=True, vector=True),
Register(name="d24", size=8, floating_point=True, vector=True),
Register(name="d25", size=8, floating_point=True, vector=True),
Register(name="d26", size=8, floating_point=True, vector=True),
Register(name="d27", size=8, floating_point=True, vector=True),
Register(name="d28", size=8, floating_point=True, vector=True),
Register(name="d29", size=8, floating_point=True, vector=True),
Register(name="d30", size=8, floating_point=True, vector=True),
Register(name="d31", size=8, floating_point=True, vector=True),
Register(name="fpscr", size=4, floating_point=True, artificial=True, concrete=False),
Register(name="tpidruro", size=4, artificial=True, concrete=False),
Register(name="itstate", size=4, artificial=True, default_value=(0, False, None), concrete=False),
]
got_section_name = ".got"
ld_linux_name = "ld-linux.so.3"
elf_tls = TLSArchInfo(1, 8, [], [0], [], 0, 0)
# elf_tls = TLSArchInfo(1, 32, [], [0], [], 0, 0)
# that line was lying in the original CLE code and I have no clue why it's different
class ArchARMHF(ArchARM):
"""
This is an architecture description for the ARM hard-float (armhf).
It supports at least an ARM 32-bit processor with ARMv7 architecture, Thumb-2 and VFP3D16.
"""
name = "ARMHF"
triplet = "arm-linux-gnueabihf"
ld_linux_name = "ld-linux-armhf.so.3"
fp_ret_offset = 128 # s0
class ArchARMEL(ArchARM):
"""
This is an architecture description for ARM EABI (armel).
It targets a range of older 32-bit ARM devices without hardware FPUs.
"""
name = "ARMEL"
triplet = "arm-linux-gnueabi"
ld_linux_name = "ld-linux.so.3"
elf_tls = TLSArchInfo(1, 8, [], [0], [], 0, 0)
class ArchARMCortexM(ArchARMEL):
"""
This is an architecture description for ARM Cortex-M microcontroller-class CPUs.
These CPUs have the following unusual / annoying distinctions from their relatives:
- Explicitly only support the Thumb-2 instruction set. Executing with the T-bit off causes the processor to fault
instantly
- Always little-endian
- Coprocessors? Nope, none of that rubbish
- Well-known standard memory map across all devices
- Rarely use an MPU, even though this does exist on some devices
- A built-in "NVIC" (Nested Vectored Interrupt Controller) as part of the standard.
- Standardized "blob format" including the IVT, with initial SP and entry prepended
- Usually don't run an OS (SimLinux? No thanks)
- As part of the above, handle syscalls (SVC) instructions through an interrupt (now called PendSV)
Uses its own fancy stack layout for this, which (UGH) varies by sub-sub-architecture
- Some fancy instructions normally never seen in other uses of Thumb (CPSID, CPSIE, WFI, MRS.W, MSR.W)
- New registers, namely:
* FAULTMASK
* PRIMASK
* BASEPRI
* CONTROL
* SP, banked as PSP or MSP
* PSR, now just one PSR, with a few meta-registers APSR, IPSR, and EPSR which take a chunk of that each
"""
name = "ARMCortexM"
triplet = "arm-none-eabi" # ARM's own CM compilers use this triplet
# These are the standard THUMB prologs. We leave these off for other ARMs due to their length
# For CM, we assume the FPs are OK, as they are almost guaranteed to appear all over the place
function_prologs = {}
thumb_prologs = {rb"[\x00-\xff]\xb5", rb"\x2d\xe9[\x00-\xff][\x00-\xff]"} # push {xxx,lr} # push.w {xxx, lr}
function_epilogs = {
rb"[\x00-\xff]\xbd" # pop {xxx, pc}
# TODO: POP.W
}
register_list = [
Register(
name="r0",
size=4,
alias_names=("a1",),
general_purpose=True,
argument=True,
linux_entry_value="ld_destructor",
),
Register(name="r1", size=4, alias_names=("a2",), general_purpose=True, argument=True),
Register(name="r2", size=4, alias_names=("a3",), general_purpose=True, argument=True),
Register(name="r3", size=4, alias_names=("a4",), general_purpose=True, argument=True),
Register(name="r4", size=4, alias_names=("v1",), general_purpose=True),
Register(name="r5", size=4, alias_names=("v2",), general_purpose=True),
Register(name="r6", size=4, alias_names=("v3",), general_purpose=True),
Register(name="r7", size=4, alias_names=("v4",), general_purpose=True),
Register(name="r8", size=4, alias_names=("v5",), general_purpose=True),
Register(name="r9", size=4, alias_names=("v6", "sb"), general_purpose=True),
Register(name="r10", size=4, alias_names=("v7", "sl"), general_purpose=True),
Register(name="r11", size=4, alias_names=("v8", "fp", "bp"), general_purpose=True),
# r11 is used as frame pointer
Register(name="r12", size=4, general_purpose=True),
# r12 is sometimes known as "ip" (intraprocedural call scratch) but we can't have that...
Register(
name="sp",
size=4,
alias_names=("r13",),
general_purpose=True,
default_value=(Arch.initial_sp, True, "global"),
),
Register(name="lr", size=4, alias_names=("r14",), general_purpose=True, concretize_unique=True),
Register(name="pc", size=4, vex_name="r15t", alias_names=("r15", "ip")),
# Control registers for Cortex-M33 with ArmV8 securtiy extension enabled (Trustzone)
Register(name="msp", size=4, general_purpose=True),
Register(name="msp_s", size=4, general_purpose=True),
Register(name="msp_ns", size=4, general_purpose=True),
Register(name="psp", size=4, general_purpose=True),
Register(name="psp_s", size=4, general_purpose=True),
Register(name="psp_ns", size=4, general_purpose=True),
Register(name="msplim", size=4, general_purpose=True),
Register(name="msplim_s", size=4, general_purpose=True),
Register(name="msplim_ns", size=4, general_purpose=True),
Register(name="msplim_ns", size=4, general_purpose=True),
# additional stack pointers for secure/non_secure world
Register(name="sp_process", size=4, general_purpose=True),
Register(name="sp_process_s", size=4, general_purpose=True),
Register(name="sp_process_ns", size=4, general_purpose=True),
Register(name="sp_main", size=4, general_purpose=True),
Register(name="sp_main_s", size=4, general_purpose=True),
Register(name="sp_main_ns", size=4, general_purpose=True),
Register(name="cc_op", size=4, default_value=(0, False, None), artificial=True, concrete=False),
Register(name="cc_dep1", size=4, default_value=(0, False, None), artificial=True, concrete=False),
Register(name="cc_dep2", size=4, default_value=(0, False, None), artificial=True, concrete=False),
Register(name="cc_ndep", size=4, default_value=(0, False, None), artificial=True, concrete=False),
Register(name="qflag32", size=4, default_value=(0, False, None), artificial=True, concrete=False),
Register(name="ip_at_syscall", size=4, artificial=True, concrete=False),
# Cortex-M Has a different FPU from all other ARMs.
Register(name="d0", size=8, subregisters=[("s0", 0, 4), ("s1", 4, 4)], floating_point=True),
Register(name="d1", size=8, subregisters=[("s2", 0, 4), ("s3", 4, 4)], floating_point=True),
Register(name="d2", size=8, subregisters=[("s4", 0, 4), ("s5", 4, 4)], floating_point=True),
Register(name="d3", size=8, subregisters=[("s6", 0, 4), ("s7", 4, 4)], floating_point=True),
Register(name="d4", size=8, subregisters=[("s8", 0, 4), ("s9", 4, 4)], floating_point=True),
Register(name="d5", size=8, subregisters=[("s10", 0, 4), ("s11", 4, 4)], floating_point=True),
Register(name="d6", size=8, subregisters=[("s12", 0, 4), ("s13", 4, 4)], floating_point=True),
Register(name="d7", size=8, subregisters=[("s14", 0, 4), ("s15", 4, 4)], floating_point=True),
Register(name="d8", size=8, subregisters=[("s16", 0, 4), ("s17", 4, 4)], floating_point=True),
Register(name="d9", size=8, subregisters=[("s18", 0, 4), ("s19", 4, 4)], floating_point=True),
Register(name="d10", size=8, subregisters=[("s20", 0, 4), ("s21", 4, 4)], floating_point=True),
Register(name="d11", size=8, subregisters=[("s22", 0, 4), ("s23", 4, 4)], floating_point=True),
Register(name="d12", size=8, subregisters=[("s24", 0, 4), ("s25", 4, 4)], floating_point=True),
Register(name="d13", size=8, subregisters=[("s26", 0, 4), ("s27", 4, 4)], floating_point=True),
Register(name="d14", size=8, subregisters=[("s28", 0, 4), ("s29", 4, 4)], floating_point=True),
Register(name="d15", size=8, subregisters=[("s30", 0, 4), ("s31", 4, 4)], floating_point=True),
# xPSR register. Includes APSR, IPSR and EPSR.
Register(name="cpsr", size=4, default_value=(0, False, None)),
# TODO: NOTE: This is technically part of the EPSR, not its own register
Register(name="fpscr", size=4, floating_point=True),
# TODO: NOTE: This is also part of EPSR
Register(name="itstate", size=4, artificial=True, default_value=(0, False, None), concrete=False),
# Whether exceptions are masked or not. (e.g., everything but NMI)
Register(name="faultmask", size=4, default_value=(0, False, None)),
Register(name="faultmask_s", size=4, default_value=(0, False, None)),
Register(name="faultmask_ns", size=4, default_value=(0, False, None)),
# The one-byte priority, above which interrupts will not be handled if PRIMASK is 1.
# Yes, you can implement an RTOS scheduler in hardware with this and the NVIC, you monster!
Register(name="basepri", size=4, default_value=(0, False, None)),
Register(name="basepri_s", size=4, default_value=(0, False, None)),
Register(name="basepri_ns", size=4, default_value=(0, False, None)),
# Only the bottom bit of PRIMASK is relevant, even though the docs say its 32bit.
# Configures whether interrupt priorities are respected or not.
Register(name="primask", size=4, default_value=(0, False, None)),
Register(name="primask_s", size=4, default_value=(0, False, None)),
Register(name="primask_ns", size=4, default_value=(0, False, None)),
# NOTE: We specifically declare IEPSR here. Not PSR, .... variants.for
# VEX already handles the content of APSR, and half of EPSR (as ITSTATE) above.
# We only keep here the data not computed via CCalls
# The default is to have the T bit on.
Register(name="iepsr", size=4, default_value=(0x01000000, False, None)),
# CONTROL:
# Bit 2: Whether the FPU is active or not
# Bit 1: Whether we use MSP (0) or PSP (1)
# Bit 0: Thread mode privilege level. 0 for privileged, 1 for unprivileged.
Register(name="control", size=4, default_value=(0, False, None)),
]
# Special handling of CM mode in *stone
if _capstone:
cs_arch = _capstone.CS_ARCH_ARM
cs_mode = _capstone.CS_MODE_LITTLE_ENDIAN + _capstone.CS_MODE_THUMB + _capstone.CS_MODE_MCLASS
_cs_thumb = None
if _keystone:
ks_arch = _keystone.KS_ARCH_ARM
ks_mode = _keystone.KS_MODE_THUMB + _keystone.KS_MODE_LITTLE_ENDIAN
_ks_thumb = None
uc_arch = _unicorn.UC_ARCH_ARM if _unicorn else None
uc_mode = _unicorn.UC_MODE_THUMB + _unicorn.UC_MODE_LITTLE_ENDIAN if _unicorn else None
uc_mode_thumb = _unicorn.UC_MODE_THUMB + _unicorn.UC_MODE_LITTLE_ENDIAN if _unicorn else None
@property
def capstone_thumb(self):
return self.capstone
@property
def keystone_thumb(self):
return self.keystone
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# TODO: Make arm_spotter use these
# TODO: Make SimOS use these.
# TODO: Add.... the NVIC? to SimOS
register_arch([r".*cortexm|.*cortex\-m.*|.*v7\-m.*"], 32, "any", ArchARMCortexM)
register_arch([r".*armhf.*"], 32, "any", ArchARMHF)
register_arch([r".*armeb|.*armbe"], 32, Endness.BE, ArchARM)
register_arch([r".*armel|arm.*"], 32, Endness.LE, ArchARMEL)
register_arch([r".*arm.*|.*thumb.*"], 32, "any", ArchARM)

View File

@@ -0,0 +1,150 @@
import logging
from .arch import Arch, register_arch, Endness
from .archerror import ArchError
from .tls import TLSArchInfo
l = logging.getLogger(__name__)
class ArchAVR8(Arch):
bits = 32
vex_arch = None
name = "AVR8"
qemu_name = "avr"
linux_name = "avr" # ???
triplet = "avr-linux-gnu" # ???
max_inst_bytes = 4
instruction_alignment = 2
elf_tls = TLSArchInfo(1, 8, [], [0], [], 0, 0) # ???
def __init__(self, endness=Endness.LE):
if endness != Endness.LE:
raise ArchError("Arch AVR8 must be little endian")
super().__init__(endness)
# IO Registers are mapped into the register file starting at 0x20
# Any instruction that references an IO register by numer should just add this.
self.ioreg_offset = 0x20
# Instructions and data are in different memory in AVR
# Translate data address into the address space by adding this
self.data_offset = 0x10000000
self.registers = {}
self.registers.update({"r%d" % i: (i, 1) for i in range(0, 32)})
self.registers.update({"R%d_R%d" % (i + 1, i): (i, 2) for i in range(0, 32, 2)})
self.registers["W"] = (24, 2)
self.registers["X"] = (26, 2)
self.registers["Y"] = (28, 2)
self.registers["Z"] = (30, 2)
self.registers["WL"] = (24, 1)
self.registers["WH"] = (25, 1)
self.registers["XL"] = (26, 1)
self.registers["XH"] = (27, 1)
self.registers["YL"] = (28, 1)
self.registers["YH"] = (29, 1)
self.registers["ZL"] = (30, 1)
self.registers["ZH"] = (31, 1)
self.registers["EEDR"] = (0x40, 1)
self.registers["EEARL"] = (0x41, 1)
self.registers["EEARH"] = (0x42, 1)
self.registers["GTCCR"] = (0x43, 1)
self.registers["TCCR0A"] = (0x44, 1)
self.registers["TCCR0B"] = (0x45, 1)
self.registers["TCNT0"] = (0x46, 1)
self.registers["OCR0A"] = (0x47, 1)
self.registers["OCR0B"] = (0x48, 1)
self.registers["IO_0x29"] = (0x49, 1)
self.registers["GPIOR1"] = (0x4A, 1)
self.registers["GPIOR2"] = (0x4B, 1)
self.registers["SPCR"] = (0x4C, 1)
self.registers["SPSR"] = (0x4D, 1)
self.registers["SPDR"] = (0x4E, 1)
self.registers["IO_0x2f"] = (0x4F, 1)
self.registers["ACSR"] = (0x50, 1)
self.registers["IO_0x31"] = (0x51, 1)
self.registers["IO_0x32"] = (0x52, 1)
self.registers["SMCR"] = (0x53, 1)
self.registers["MCUSR"] = (0x54, 1)
self.registers["MCUCR"] = (0x55, 1)
self.registers["IO_0x36"] = (0x56, 1)
self.registers["SPMCSR"] = (0x57, 1)
self.registers["RAMPD"] = (0x58, 1)
self.registers["RAMPX"] = (0x59, 1)
self.registers["RAMPY"] = (0x5A, 1)
self.registers["RAMPZ"] = (0x5B, 1)
self.registers["EIND"] = (0x5C, 1)
self.registers["SP"] = (0x5D, 2)
self.registers["SPL"] = (0x5D, 1)
self.registers["SPH"] = (0x5E, 1)
self.registers["SREG"] = (0x5F, 1)
self.registers["WDTCSR"] = (0x60, 1)
self.registers["CLKPR"] = (0x61, 1)
self.registers["PRR"] = (0x64, 1)
self.registers["OSCCAL"] = (0x66, 1)
self.registers["PCICR"] = (0x68, 1)
self.registers["EICRA"] = (0x69, 1)
self.registers["PCMSK0"] = (0x6B, 1)
self.registers["PCMSK2"] = (0x6D, 1)
self.registers["PCMSK1"] = (0x6C, 1)
self.registers["TIMSK0"] = (0x6E, 1)
self.registers["TIMSK1"] = (0x6F, 1)
self.registers["TIMSK2"] = (0x70, 1)
self.registers["ADCL"] = (0x78, 1)
self.registers["ADCH"] = (0x79, 1)
self.registers["ADCSRA"] = (0x7A, 1)
self.registers["ADCSRB"] = (0x7B, 1)
self.registers["ADMUX"] = (0x7C, 1)
self.registers["DIDR0"] = (0x7E, 1)
self.registers["DIDR1"] = (0x7F, 1)
self.registers["TCCR1A"] = (0x80, 1)
self.registers["TCCR1B"] = (0x81, 1)
self.registers["TCCR1C"] = (0x82, 1)
self.registers["TCNT1H"] = (0x85, 1)
self.registers["TCNT1L"] = (0x84, 1)
self.registers["ICR1H"] = (0x87, 1)
self.registers["ICR1L"] = (0x86, 1)
self.registers["OCR1AH"] = (0x89, 1)
self.registers["OCR1AL"] = (0x88, 1)
self.registers["OCR1BH"] = (0x8B, 1)
self.registers["OCR1BL"] = (0x8A, 1)
self.registers["TCCR2A"] = (0xB0, 1)
self.registers["TCCR2B"] = (0xB1, 1)
self.registers["TCNT2"] = (0xB2, 1)
self.registers["OCR2A"] = (0xB3, 1)
self.registers["OCR2B"] = (0xB4, 1)
self.registers["ASSR"] = (0xB6, 1)
self.registers["TWBR"] = (0xB8, 1)
self.registers["TWSR"] = (0xB9, 1)
self.registers["TWAR"] = (0xBA, 1)
self.registers["TWDR"] = (0xBB, 1)
self.registers["TWCR"] = (0xBC, 1)
self.registers["TWAMR"] = (0xBD, 1)
self.registers["UCSR0A"] = (0xC0, 1)
self.registers["UCSR0B"] = (0xC1, 1)
self.registers["UCSR0C"] = (0xC2, 1)
self.registers["UBRR0H"] = (0xC5, 1)
self.registers["UBRR0L"] = (0xC4, 1)
self.registers["UDR0"] = (0xC6, 1)
self.registers["pc"] = (0x80000000, 2)
self.registers["ip"] = (0x80000000, 2)
self.registers["sp"] = self.registers["SP"]
self.register_names = {}
self.register_names.update({i: "r%d" % i for i in range(0, 32)})
self.register_names[self.registers["pc"][0]] = "pc"
self.register_names[self.registers["sp"][0]] = "sp"
self.ip_offset = self.registers["pc"][0]
self.sp_offset = self.registers["sp"][0]
register_arch([r".*avr"], 32, Endness.LE, ArchAVR8)

View File

@@ -0,0 +1,219 @@
import logging
l = logging.getLogger("archinfo.arch_mips32")
try:
import capstone as _capstone
except ImportError:
_capstone = None
try:
import keystone as _keystone
except ImportError:
_keystone = None
try:
import unicorn as _unicorn
except ImportError:
_unicorn = None
from .arch import Arch, register_arch, Endness, Register
from .tls import TLSArchInfo
# FIXME: Tell fish to fix whatever he was storing in info['current_function']
# TODO: Only persist t9 in PIC programs
class ArchMIPS32(Arch):
def __init__(self, endness=Endness.BE):
super().__init__(endness)
if endness == Endness.BE:
self.function_prologs = {
rb"\x27\xbd\xff[\x00-\xff]" # addiu $sp, xxx
rb"\x3c\x1c[\x00-\xff][\x00-\xff]\x9c\x27[\x00-\xff][\x00-\xff]" # lui $gp, xxx; addiu $gp, $gp, xxxx
}
self.function_epilogs = {
rb"\x8f\xbf[\x00-\xff]{2}([\x00-\xff]{4}){0,4}\x03\xe0\x00\x08" # lw ra, off(sp); ... ; jr ra
}
self.qemu_name = "mips"
self.triplet = "mips-linux-gnu"
self.linux_name = "mips"
bits = 32
vex_arch = "VexArchMIPS32"
name = "MIPS32"
ida_processor = "mipsb"
qemu_name = "mipsel"
linux_name = "mipsel" # ???
triplet = "mipsel-linux-gnu"
max_inst_bytes = 4
ret_offset = 16
syscall_num_offset = 16
call_pushes_ret = False
stack_change = -4
branch_delay_slot = True
sizeof = {"short": 16, "int": 32, "long": 32, "long long": 64}
if _capstone:
cs_arch = _capstone.CS_ARCH_MIPS
cs_mode = _capstone.CS_MODE_32 + _capstone.CS_MODE_LITTLE_ENDIAN
if _keystone:
ks_arch = _keystone.KS_ARCH_MIPS
ks_mode = _keystone.KS_MODE_32 + _keystone.KS_MODE_LITTLE_ENDIAN
uc_arch = _unicorn.UC_ARCH_MIPS if _unicorn else None
uc_mode = (_unicorn.UC_MODE_32 + _unicorn.UC_MODE_LITTLE_ENDIAN) if _unicorn else None
uc_const = _unicorn.mips_const if _unicorn else None
uc_prefix = "UC_MIPS_" if _unicorn else None
function_prologs = {
rb"[\x00-\xff]\xff\xbd\x27", # addiu $sp, xxx
rb"[\x00-\xff][\x00-\xff]\x1c\x3c[\x00-\xff][\x00-\xff]\x9c\x27", # lui $gp, xxx; addiu $gp, $gp, xxxx
}
function_epilogs = {rb"[\x00-\xff]{2}\xbf\x8f([\x00-\xff]{4}){0,4}\x08\x00\xe0\x03"} # lw ra, off(sp); ... ; jr ra
ret_instruction = b"\x08\x00\xE0\x03" + b"\x25\x08\x20\x00"
nop_instruction = b"\x00\x00\x00\x00"
instruction_alignment = 4
register_list = [
Register(name="zero", size=4, alias_names=("r0",)),
Register(name="at", size=4, alias_names=("r1",), general_purpose=True),
Register(name="v0", size=4, alias_names=("r2",), general_purpose=True, linux_entry_value="ld_destructor"),
Register(name="v1", size=4, alias_names=("r3",), general_purpose=True),
Register(name="a0", size=4, alias_names=("r4",), general_purpose=True, argument=True),
Register(name="a1", size=4, alias_names=("r5",), general_purpose=True, argument=True),
Register(name="a2", size=4, alias_names=("r6",), general_purpose=True, argument=True),
Register(name="a3", size=4, alias_names=("r7",), general_purpose=True, argument=True),
Register(name="t0", size=4, alias_names=("r8",), general_purpose=True),
Register(name="t1", size=4, alias_names=("r9",), general_purpose=True),
Register(name="t2", size=4, alias_names=("r10",), general_purpose=True),
Register(name="t3", size=4, alias_names=("r11",), general_purpose=True),
Register(name="t4", size=4, alias_names=("r12",), general_purpose=True),
Register(name="t5", size=4, alias_names=("r13",), general_purpose=True),
Register(name="t6", size=4, alias_names=("r14",), general_purpose=True),
Register(name="t7", size=4, alias_names=("r15",), general_purpose=True),
Register(name="s0", size=4, alias_names=("r16",), general_purpose=True),
Register(name="s1", size=4, alias_names=("r17",), general_purpose=True),
Register(name="s2", size=4, alias_names=("r18",), general_purpose=True),
Register(name="s3", size=4, alias_names=("r19",), general_purpose=True),
Register(name="s4", size=4, alias_names=("r20",), general_purpose=True),
Register(name="s5", size=4, alias_names=("r21",), general_purpose=True),
Register(name="s6", size=4, alias_names=("r22",), general_purpose=True),
Register(name="s7", size=4, alias_names=("r23",), general_purpose=True),
Register(name="t8", size=4, alias_names=("r24",), general_purpose=True),
Register(name="t9", size=4, alias_names=("r25",), general_purpose=True, persistent=True),
Register(name="k0", size=4, alias_names=("r26",), general_purpose=True),
Register(name="k1", size=4, alias_names=("r27",), general_purpose=True),
Register(name="gp", size=4, alias_names=("r28",), persistent=True),
Register(name="sp", size=4, alias_names=("r29",), default_value=(Arch.initial_sp, True, "global")),
Register(name="s8", size=4, alias_names=("r30", "fp", "bp"), general_purpose=True),
Register(
name="ra", size=4, alias_names=("r31", "lr"), general_purpose=True, persistent=True, linux_entry_value=0
),
Register(name="pc", size=4, alias_names=("ip",)),
Register(name="hi", size=4, general_purpose=True),
Register(name="lo", size=4, general_purpose=True),
Register(name="f0", size=8, floating_point=True, subregisters=[("f0_lo", 0, 4)]),
Register(name="f1", size=8, floating_point=True, subregisters=[("f1_lo", 0, 4)]),
Register(name="f2", size=8, floating_point=True, subregisters=[("f2_lo", 0, 4)]),
Register(name="f3", size=8, floating_point=True, subregisters=[("f3_lo", 0, 4)]),
Register(name="f4", size=8, floating_point=True, subregisters=[("f4_lo", 0, 4)]),
Register(name="f5", size=8, floating_point=True, subregisters=[("f5_lo", 0, 4)]),
Register(name="f6", size=8, floating_point=True, subregisters=[("f6_lo", 0, 4)]),
Register(name="f7", size=8, floating_point=True, subregisters=[("f7_lo", 0, 4)]),
Register(name="f8", size=8, floating_point=True, subregisters=[("f8_lo", 0, 4)]),
Register(name="f9", size=8, floating_point=True, subregisters=[("f9_lo", 0, 4)]),
Register(name="f10", size=8, floating_point=True, subregisters=[("f10_lo", 0, 4)]),
Register(name="f11", size=8, floating_point=True, subregisters=[("f11_lo", 0, 4)]),
Register(name="f12", size=8, floating_point=True, subregisters=[("f12_lo", 0, 4)]),
Register(name="f13", size=8, floating_point=True, subregisters=[("f13_lo", 0, 4)]),
Register(name="f14", size=8, floating_point=True, subregisters=[("f14_lo", 0, 4)]),
Register(name="f15", size=8, floating_point=True, subregisters=[("f15_lo", 0, 4)]),
Register(name="f16", size=8, floating_point=True, subregisters=[("f16_lo", 0, 4)]),
Register(name="f17", size=8, floating_point=True, subregisters=[("f17_lo", 0, 4)]),
Register(name="f18", size=8, floating_point=True, subregisters=[("f18_lo", 0, 4)]),
Register(name="f19", size=8, floating_point=True, subregisters=[("f19_lo", 0, 4)]),
Register(name="f20", size=8, floating_point=True, subregisters=[("f20_lo", 0, 4)]),
Register(name="f21", size=8, floating_point=True, subregisters=[("f21_lo", 0, 4)]),
Register(name="f22", size=8, floating_point=True, subregisters=[("f22_lo", 0, 4)]),
Register(name="f23", size=8, floating_point=True, subregisters=[("f23_lo", 0, 4)]),
Register(name="f24", size=8, floating_point=True, subregisters=[("f24_lo", 0, 4)]),
Register(name="f25", size=8, floating_point=True, subregisters=[("f25_lo", 0, 4)]),
Register(name="f26", size=8, floating_point=True, subregisters=[("f26_lo", 0, 4)]),
Register(name="f27", size=8, floating_point=True, subregisters=[("f27_lo", 0, 4)]),
Register(name="f28", size=8, floating_point=True, subregisters=[("f28_lo", 0, 4)]),
Register(name="f29", size=8, floating_point=True, subregisters=[("f29_lo", 0, 4)]),
Register(name="f30", size=8, floating_point=True, subregisters=[("f30_lo", 0, 4)]),
Register(name="f31", size=8, floating_point=True, subregisters=[("f31_lo", 0, 4)]),
Register(name="fir", size=4, floating_point=True),
Register(name="fccr", size=4, floating_point=True),
Register(name="fexr", size=4, floating_point=True),
Register(name="fenr", size=4, floating_point=True),
Register(name="fcsr", size=4, floating_point=True),
Register(name="ulr", size=4),
Register(name="emnote", size=4, artificial=True),
Register(name="cmstart", size=4),
Register(name="cmlen", size=4),
Register(name="nraddr", size=4),
Register(name="cond", size=4),
Register(name="dspcontrol", size=4),
Register(name="ac0", size=8),
Register(name="ac1", size=8),
Register(name="ac2", size=8),
Register(name="ac3", size=8),
Register(name="cp0_status", size=4),
Register(name="ip_at_syscall", size=4, artificial=True),
]
# see https://github.com/radare/radare/blob/master/src/include/elf/mips.h
dynamic_tag_translation = {
0x70000001: "DT_MIPS_RLD_VERSION",
0x70000002: "DT_MIPS_TIME_STAMP",
0x70000003: "DT_MIPS_ICHECKSUM",
0x70000004: "DT_MIPS_IVERSION",
0x70000005: "DT_MIPS_FLAGS",
0x70000006: "DT_MIPS_BASE_ADDRESS",
0x70000007: "DT_MIPS_MSYM",
0x70000008: "DT_MIPS_CONFLICT",
0x70000009: "DT_MIPS_LIBLIST",
0x7000000A: "DT_MIPS_LOCAL_GOTNO",
0x7000000B: "DT_MIPS_CONFLICTNO",
0x70000010: "DT_MIPS_LIBLISTNO",
0x70000011: "DT_MIPS_SYMTABNO",
0x70000012: "DT_MIPS_UNREFEXTNO",
0x70000013: "DT_MIPS_GOTSYM",
0x70000014: "DT_MIPS_HIPAGENO",
0x70000016: "DT_MIPS_RLD_MAP",
0x70000017: "DT_MIPS_DELTA_CLASS",
0x70000018: "DT_MIPS_DELTA_CLASS_NO",
0x70000019: "DT_MIPS_DELTA_INSTANCE",
0x7000001A: "DT_MIPS_DELTA_INSTANCE_NO",
0x7000001B: "DT_MIPS_DELTA_RELOC",
0x7000001C: "DT_MIPS_DELTA_RELOC_NO",
0x7000001D: "DT_MIPS_DELTA_SYM",
0x7000001E: "DT_MIPS_DELTA_SYM_NO",
0x70000020: "DT_MIPS_DELTA_CLASSSYM",
0x70000021: "DT_MIPS_DELTA_CLASSSYM_NO",
0x70000022: "DT_MIPS_CXX_FLAGS",
0x70000023: "DT_MIPS_PIXIE_INIT",
0x70000024: "DT_MIPS_SYMBOL_LIB",
0x70000025: "DT_MIPS_LOCALPAGE_GOTIDX",
0x70000026: "DT_MIPS_LOCAL_GOTIDX",
0x70000027: "DT_MIPS_HIDDEN_GOTIDX",
0x70000028: "DT_MIPS_PROTECTED_GOTIDX",
0x70000029: "DT_MIPS_OPTIONS",
0x7000002A: "DT_MIPS_INTERFACE",
0x7000002B: "DT_MIPS_DYNSTR_ALIGN",
0x7000002C: "DT_MIPS_INTERFACE_SIZE",
0x7000002D: "DT_MIPS_RLD_TEXT_RESOLVE_ADDR",
0x7000002E: "DT_MIPS_PERF_SUFFIX",
0x7000002F: "DT_MIPS_COMPACT_SIZE",
0x70000030: "DT_MIPS_GP_VALUE",
0x70000031: "DT_MIPS_AUX_DYNAMIC",
0x70000032: "DT_MIPS_PLTGOT",
}
got_section_name = ".got"
ld_linux_name = "ld.so.1"
elf_tls = TLSArchInfo(1, 8, [], [0], [], 0x7000, 0x8000)
register_arch([r"mipsel|mipsle"], 32, Endness.LE, ArchMIPS32)
register_arch([r".*mips.*"], 32, "any", ArchMIPS32)

View File

@@ -0,0 +1,199 @@
import logging
l = logging.getLogger("archinfo.arch_mips64")
try:
import capstone as _capstone
except ImportError:
_capstone = None
try:
import keystone as _keystone
except ImportError:
_keystone = None
try:
import unicorn as _unicorn
except ImportError:
_unicorn = None
from .arch import Arch, register_arch, Endness, Register
from .tls import TLSArchInfo
class ArchMIPS64(Arch):
def __init__(self, endness=Endness.BE):
super().__init__(endness)
if endness == Endness.BE:
self.function_prologs = set()
self.function_epilogs = set()
self.triplet = "mips64-linux-gnu"
self.linux_name = "mips64"
self.ida_name = "mips64b"
bits = 64
vex_arch = "VexArchMIPS64"
name = "MIPS64"
qemu_name = "mips64el"
ida_processor = "mips64"
linux_name = "mips64el" # ???
triplet = "mips64el-linux-gnu"
max_inst_bytes = 4
ret_offset = 32
syscall_register_offset = 16
call_pushes_ret = False
stack_change = -8
branch_delay_slot = True
sizeof = {"short": 16, "int": 32, "long": 64, "long long": 64}
if _capstone:
cs_arch = _capstone.CS_ARCH_MIPS
cs_mode = _capstone.CS_MODE_64 + _capstone.CS_MODE_LITTLE_ENDIAN
if _keystone:
ks_arch = _keystone.KS_ARCH_MIPS
ks_mode = _keystone.KS_MODE_64 + _keystone.KS_MODE_LITTLE_ENDIAN
uc_arch = _unicorn.UC_ARCH_MIPS if _unicorn else None
uc_mode = (_unicorn.UC_MODE_64 + _unicorn.UC_MODE_LITTLE_ENDIAN) if _unicorn else None
uc_const = _unicorn.mips_const if _unicorn else None
uc_prefix = "UC_MIPS_" if _unicorn else None
function_prologs = set()
function_epilogs = set()
ret_instruction = b"\x08\x00\xE0\x03" + b"\x25\x08\x20\x00"
nop_instruction = b"\x00\x00\x00\x00"
instruction_alignment = 4
register_list = [
Register(name="zero", size=8, alias_names=("r0",)),
Register(name="at", size=8, alias_names=("r1",), general_purpose=True),
Register(name="v0", size=8, alias_names=("r2",), general_purpose=True, linux_entry_value="ld_destructor"),
Register(name="v1", size=8, alias_names=("r3",), general_purpose=True),
Register(name="a0", size=8, alias_names=("r4",), general_purpose=True, argument=True),
Register(name="a1", size=8, alias_names=("r5",), general_purpose=True, argument=True),
Register(name="a2", size=8, alias_names=("r6",), general_purpose=True, argument=True),
Register(name="a3", size=8, alias_names=("r7",), general_purpose=True, argument=True),
Register(
name="t0",
size=8,
alias_names=(
"r8",
"a4",
),
general_purpose=True,
),
Register(
name="t1",
size=8,
alias_names=(
"r9",
"a5",
),
general_purpose=True,
),
Register(
name="t2",
size=8,
alias_names=(
"r10",
"a6",
),
general_purpose=True,
),
Register(
name="t3",
size=8,
alias_names=(
"r11",
"a7",
),
general_purpose=True,
),
Register(name="t4", size=8, alias_names=("r12",), general_purpose=True),
Register(name="t5", size=8, alias_names=("r13",), general_purpose=True),
Register(name="t6", size=8, alias_names=("r14",), general_purpose=True),
Register(name="t7", size=8, alias_names=("r15",), general_purpose=True),
Register(name="s0", size=8, alias_names=("r16",), general_purpose=True),
Register(name="s1", size=8, alias_names=("r17",), general_purpose=True),
Register(name="s2", size=8, alias_names=("r18",), general_purpose=True),
Register(name="s3", size=8, alias_names=("r19",), general_purpose=True),
Register(name="s4", size=8, alias_names=("r20",), general_purpose=True),
Register(name="s5", size=8, alias_names=("r21",), general_purpose=True),
Register(name="s6", size=8, alias_names=("r22",), general_purpose=True),
Register(name="s7", size=8, alias_names=("r23",), general_purpose=True),
Register(name="t8", size=8, alias_names=("r24",), general_purpose=True),
Register(name="t9", size=8, alias_names=("r25",), general_purpose=True, persistent=True),
Register(name="k0", size=8, alias_names=("r26",), general_purpose=True),
Register(name="k1", size=8, alias_names=("r27",), general_purpose=True),
Register(name="gp", size=8, alias_names=("r28",), persistent=True),
Register(name="sp", size=8, alias_names=("r29",), default_value=(Arch.initial_sp, True, "global")),
Register(name="s8", size=8, alias_names=("r30", "fp", "bp"), general_purpose=True),
Register(
name="ra", size=8, alias_names=("r31", "lr"), general_purpose=True, persistent=True, linux_entry_value=0
),
Register(name="pc", size=8, alias_names=("ip",)),
Register(name="hi", size=8, general_purpose=True),
Register(name="lo", size=8, general_purpose=True),
Register(name="f0", size=8, floating_point=True, subregisters=[("f0_lo", 0, 4)]),
Register(name="f1", size=8, floating_point=True, subregisters=[("f1_lo", 0, 4)]),
Register(name="f2", size=8, floating_point=True, subregisters=[("f2_lo", 0, 4)]),
Register(name="f3", size=8, floating_point=True, subregisters=[("f3_lo", 0, 4)]),
Register(name="f4", size=8, floating_point=True, subregisters=[("f4_lo", 0, 4)]),
Register(name="f5", size=8, floating_point=True, subregisters=[("f5_lo", 0, 4)]),
Register(name="f6", size=8, floating_point=True, subregisters=[("f6_lo", 0, 4)]),
Register(name="f7", size=8, floating_point=True, subregisters=[("f7_lo", 0, 4)]),
Register(name="f8", size=8, floating_point=True, subregisters=[("f8_lo", 0, 4)]),
Register(name="f9", size=8, floating_point=True, subregisters=[("f9_lo", 0, 4)]),
Register(name="f10", size=8, floating_point=True, subregisters=[("f10_lo", 0, 4)]),
Register(name="f11", size=8, floating_point=True, subregisters=[("f11_lo", 0, 4)]),
Register(name="f12", size=8, floating_point=True, subregisters=[("f12_lo", 0, 4)]),
Register(name="f13", size=8, floating_point=True, subregisters=[("f13_lo", 0, 4)]),
Register(name="f14", size=8, floating_point=True, subregisters=[("f14_lo", 0, 4)]),
Register(name="f15", size=8, floating_point=True, subregisters=[("f15_lo", 0, 4)]),
Register(name="f16", size=8, floating_point=True, subregisters=[("f16_lo", 0, 4)]),
Register(name="f17", size=8, floating_point=True, subregisters=[("f17_lo", 0, 4)]),
Register(name="f18", size=8, floating_point=True, subregisters=[("f18_lo", 0, 4)]),
Register(name="f19", size=8, floating_point=True, subregisters=[("f19_lo", 0, 4)]),
Register(name="f20", size=8, floating_point=True, subregisters=[("f20_lo", 0, 4)]),
Register(name="f21", size=8, floating_point=True, subregisters=[("f21_lo", 0, 4)]),
Register(name="f22", size=8, floating_point=True, subregisters=[("f22_lo", 0, 4)]),
Register(name="f23", size=8, floating_point=True, subregisters=[("f23_lo", 0, 4)]),
Register(name="f24", size=8, floating_point=True, subregisters=[("f24_lo", 0, 4)]),
Register(name="f25", size=8, floating_point=True, subregisters=[("f25_lo", 0, 4)]),
Register(name="f26", size=8, floating_point=True, subregisters=[("f26_lo", 0, 4)]),
Register(name="f27", size=8, floating_point=True, subregisters=[("f27_lo", 0, 4)]),
Register(name="f28", size=8, floating_point=True, subregisters=[("f28_lo", 0, 4)]),
Register(name="f29", size=8, floating_point=True, subregisters=[("f29_lo", 0, 4)]),
Register(name="f30", size=8, floating_point=True, subregisters=[("f30_lo", 0, 4)]),
Register(name="f31", size=8, floating_point=True, subregisters=[("f31_lo", 0, 4)]),
Register(name="fir", size=4, floating_point=True),
Register(name="fccr", size=4, floating_point=True),
Register(name="fexr", size=4, floating_point=True),
Register(name="fenr", size=4, floating_point=True),
Register(name="fcsr", size=4, floating_point=True),
Register(name="cp0_status", size=4),
Register(name="ulr", size=8),
Register(name="emnote", size=4, artificial=True),
Register(name="cond", size=4),
Register(name="cmstart", size=8),
Register(name="cmlen", size=8),
Register(name="nraddr", size=8),
Register(name="ip_at_syscall", size=8, artificial=True),
]
# http://techpubs.sgi.com/library/manuals/4000/007-4658-001/pdf/007-4658-001.pdf
dynamic_tag_translation = {
0x70000001: "DT_MIPS_RLD_VERSION",
0x70000005: "DT_MIPS_FLAGS",
0x70000006: "DT_MIPS_BASE_ADDRESS",
0x7000000A: "DT_MIPS_LOCAL_GOTNO",
0x70000011: "DT_MIPS_SYMTABNO",
0x70000012: "DT_MIPS_UNREFEXTNO",
0x70000013: "DT_MIPS_GOTSYM",
0x70000016: "DT_MIPS_RLD_MAP",
}
got_section_name = ".got"
ld_linux_name = "ld.so.1"
elf_tls = TLSArchInfo(1, 16, [], [0], [], 0x7000, 0x8000)
register_arch([r".*mipsel.*|.*mips64el|.*mipsel64"], 64, Endness.LE, ArchMIPS64)
register_arch([r".*mips64.*|.*mips.*"], 64, "any", ArchMIPS64)

View File

@@ -0,0 +1,262 @@
import logging
l = logging.getLogger("archinfo.arch_ppc32")
try:
import capstone as _capstone
except ImportError:
_capstone = None
try:
import keystone as _keystone
except ImportError:
_keystone = None
# try:
# import unicorn as _unicorn
# except ImportError:
# _unicorn = None
try:
import pyvex as _pyvex
except ImportError:
_pyvex = None
from .arch import Arch, register_arch, Endness, Register
from .tls import TLSArchInfo
# Note: PowerPC doesn't have pc, so guest_CIA is commented as IP (no arch visible register)
# PowerPC doesn't have stack base pointer, so bp_offset is set to -1 below
# Normally r1 is used as stack pointer
class ArchPPC32(Arch):
def __init__(self, endness=Endness.LE):
super().__init__(endness)
if endness == Endness.BE:
self.function_prologs = {
# stwu r1, -off(r1); mflr r0
rb"\x94\x21[\x00-\xff]{2}\x7c\x08\x02\xa6"
}
self.function_epilogs = {
# mtlr reg; ... ; blr
rb"[\x00-\xff]{2}\x03\xa6([\x00-\xff]{4}){0,6}\x4e\x80\x00\x20"
}
self.argument_register_positions = (
{
self.registers["r3"][0]: 0,
self.registers["r4"][0]: 1,
self.registers["r5"][0]: 2,
self.registers["r6"][0]: 3,
self.registers["r7"][0]: 4,
self.registers["r8"][0]: 5,
self.registers["r9"][0]: 6,
self.registers["r10"][0]: 7,
}
if _pyvex is not None
else None
)
bits = 32
vex_arch = "VexArchPPC32"
name = "PPC32"
qemu_name = "ppc"
ida_processor = "ppc"
linux_name = "ppc750" # ?
triplet = "powerpc-linux-gnu"
max_inst_bytes = 4
# https://www.ibm.com/developerworks/community/forums/html/topic?id=77777777-0000-0000-0000-000013836863
# claims that r15 is the base pointer but that is NOT what I see in practice
ret_offset = 28
syscall_num_offset = 16
call_pushes_ret = False
stack_change = -4
sizeof = {"short": 16, "int": 32, "long": 32, "long long": 64}
if _capstone:
cs_arch = _capstone.CS_ARCH_PPC
cs_mode = _capstone.CS_MODE_32 + _capstone.CS_MODE_LITTLE_ENDIAN
if _keystone:
ks_arch = _keystone.KS_ARCH_PPC
ks_mode = _keystone.KS_MODE_32 + _keystone.KS_MODE_LITTLE_ENDIAN
# Unicorn not supported
# uc_arch = _unicorn.UC_ARCH_PPC if _unicorn else None
# uc_mode = (_unicorn.UC_MODE_32 + _unicorn.UC_MODE_LITTLE_ENDIAN) if _unicorn else None
ret_instruction = b"\x20\x00\x80\x4e"
nop_instruction = b"\x00\x00\x00\x60"
instruction_alignment = 4
register_list = [
Register(name="gpr0", size=4, alias_names=("r0",), general_purpose=True),
Register(
name="gpr1",
size=4,
alias_names=("r1", "sp"),
general_purpose=True,
default_value=(Arch.initial_sp, True, "global"),
),
Register(name="gpr2", size=4, alias_names=("r2",), general_purpose=True),
Register(
name="gpr3", size=4, alias_names=("r3",), general_purpose=True, argument=True, linux_entry_value="argc"
),
Register(
name="gpr4", size=4, alias_names=("r4",), general_purpose=True, argument=True, linux_entry_value="argv"
),
Register(
name="gpr5", size=4, alias_names=("r5",), general_purpose=True, argument=True, linux_entry_value="envp"
),
Register(
name="gpr6", size=4, alias_names=("r6",), general_purpose=True, argument=True, linux_entry_value="auxv"
),
Register(
name="gpr7",
size=4,
alias_names=("r7",),
general_purpose=True,
argument=True,
linux_entry_value="ld_destructor",
),
Register(name="gpr8", size=4, alias_names=("r8",), general_purpose=True, argument=True),
Register(name="gpr9", size=4, alias_names=("r9",), general_purpose=True, argument=True),
Register(name="gpr10", size=4, alias_names=("r10",), general_purpose=True, argument=True),
Register(name="gpr11", size=4, alias_names=("r11",), general_purpose=True),
Register(name="gpr12", size=4, alias_names=("r12",), general_purpose=True),
Register(name="gpr13", size=4, alias_names=("r13",), general_purpose=True),
Register(name="gpr14", size=4, alias_names=("r14",), general_purpose=True),
Register(name="gpr15", size=4, alias_names=("r15",), general_purpose=True),
Register(name="gpr16", size=4, alias_names=("r16",), general_purpose=True),
Register(name="gpr17", size=4, alias_names=("r17",), general_purpose=True),
Register(name="gpr18", size=4, alias_names=("r18",), general_purpose=True),
Register(name="gpr19", size=4, alias_names=("r19",), general_purpose=True),
Register(name="gpr20", size=4, alias_names=("r20",), general_purpose=True),
Register(name="gpr21", size=4, alias_names=("r21",), general_purpose=True),
Register(name="gpr22", size=4, alias_names=("r22",), general_purpose=True),
Register(name="gpr23", size=4, alias_names=("r23",), general_purpose=True),
Register(name="gpr24", size=4, alias_names=("r24",), general_purpose=True),
Register(name="gpr25", size=4, alias_names=("r25",), general_purpose=True, persistent=True),
Register(name="gpr26", size=4, alias_names=("r26",), general_purpose=True),
Register(name="gpr27", size=4, alias_names=("r27",), general_purpose=True),
Register(name="gpr28", size=4, alias_names=("r28",), general_purpose=True),
Register(name="gpr29", size=4, alias_names=("r29",), general_purpose=True),
Register(name="gpr30", size=4, alias_names=("r30",), general_purpose=True),
Register(name="gpr31", size=4, alias_names=("r31", "bp"), general_purpose=True),
Register(name="vsr0", size=16, subregisters=[("fpr0", 0, 8)], alias_names=("v0",), floating_point=True),
Register(name="vsr1", size=16, subregisters=[("fpr1", 0, 8)], alias_names=("v1",), floating_point=True),
Register(name="vsr2", size=16, subregisters=[("fpr2", 0, 8)], alias_names=("v2",), floating_point=True),
Register(name="vsr3", size=16, subregisters=[("fpr3", 0, 8)], alias_names=("v3",), floating_point=True),
Register(name="vsr4", size=16, subregisters=[("fpr4", 0, 8)], alias_names=("v4",), floating_point=True),
Register(name="vsr5", size=16, subregisters=[("fpr5", 0, 8)], alias_names=("v5",), floating_point=True),
Register(name="vsr6", size=16, subregisters=[("fpr6", 0, 8)], alias_names=("v6",), floating_point=True),
Register(name="vsr7", size=16, subregisters=[("fpr7", 0, 8)], alias_names=("v7",), floating_point=True),
Register(name="vsr8", size=16, subregisters=[("fpr8", 0, 8)], alias_names=("v8",), floating_point=True),
Register(name="vsr9", size=16, subregisters=[("fpr9", 0, 8)], alias_names=("v9",), floating_point=True),
Register(name="vsr10", size=16, subregisters=[("fpr10", 0, 8)], alias_names=("v10",), floating_point=True),
Register(name="vsr11", size=16, subregisters=[("fpr11", 0, 8)], alias_names=("v11",), floating_point=True),
Register(name="vsr12", size=16, subregisters=[("fpr12", 0, 8)], alias_names=("v12",), floating_point=True),
Register(name="vsr13", size=16, subregisters=[("fpr13", 0, 8)], alias_names=("v13",), floating_point=True),
Register(name="vsr14", size=16, subregisters=[("fpr14", 0, 8)], alias_names=("v14",), floating_point=True),
Register(name="vsr15", size=16, subregisters=[("fpr15", 0, 8)], alias_names=("v15",), floating_point=True),
Register(name="vsr16", size=16, subregisters=[("fpr16", 0, 8)], alias_names=("v16",), floating_point=True),
Register(name="vsr17", size=16, subregisters=[("fpr17", 0, 8)], alias_names=("v17",), floating_point=True),
Register(name="vsr18", size=16, subregisters=[("fpr18", 0, 8)], alias_names=("v18",), floating_point=True),
Register(name="vsr19", size=16, subregisters=[("fpr19", 0, 8)], alias_names=("v19",), floating_point=True),
Register(name="vsr20", size=16, subregisters=[("fpr20", 0, 8)], alias_names=("v20",), floating_point=True),
Register(name="vsr21", size=16, subregisters=[("fpr21", 0, 8)], alias_names=("v21",), floating_point=True),
Register(name="vsr22", size=16, subregisters=[("fpr22", 0, 8)], alias_names=("v22",), floating_point=True),
Register(name="vsr23", size=16, subregisters=[("fpr23", 0, 8)], alias_names=("v23",), floating_point=True),
Register(name="vsr24", size=16, subregisters=[("fpr24", 0, 8)], alias_names=("v24",), floating_point=True),
Register(name="vsr25", size=16, subregisters=[("fpr25", 0, 8)], alias_names=("v25",), floating_point=True),
Register(name="vsr26", size=16, subregisters=[("fpr26", 0, 8)], alias_names=("v26",), floating_point=True),
Register(name="vsr27", size=16, subregisters=[("fpr27", 0, 8)], alias_names=("v27",), floating_point=True),
Register(name="vsr28", size=16, subregisters=[("fpr28", 0, 8)], alias_names=("v28",), floating_point=True),
Register(name="vsr29", size=16, subregisters=[("fpr29", 0, 8)], alias_names=("v29",), floating_point=True),
Register(name="vsr30", size=16, subregisters=[("fpr30", 0, 8)], alias_names=("v30",), floating_point=True),
Register(name="vsr31", size=16, subregisters=[("fpr31", 0, 8)], alias_names=("v31",), floating_point=True),
Register(name="vsr32", size=16, alias_names=("v32",), vector=True),
Register(name="vsr33", size=16, alias_names=("v33",), vector=True),
Register(name="vsr34", size=16, alias_names=("v34",), vector=True),
Register(name="vsr35", size=16, alias_names=("v35",), vector=True),
Register(name="vsr36", size=16, alias_names=("v36",), vector=True),
Register(name="vsr37", size=16, alias_names=("v37",), vector=True),
Register(name="vsr38", size=16, alias_names=("v38",), vector=True),
Register(name="vsr39", size=16, alias_names=("v39",), vector=True),
Register(name="vsr40", size=16, alias_names=("v40",), vector=True),
Register(name="vsr41", size=16, alias_names=("v41",), vector=True),
Register(name="vsr42", size=16, alias_names=("v42",), vector=True),
Register(name="vsr43", size=16, alias_names=("v43",), vector=True),
Register(name="vsr44", size=16, alias_names=("v44",), vector=True),
Register(name="vsr45", size=16, alias_names=("v45",), vector=True),
Register(name="vsr46", size=16, alias_names=("v46",), vector=True),
Register(name="vsr47", size=16, alias_names=("v47",), vector=True),
Register(name="vsr48", size=16, alias_names=("v48",), vector=True),
Register(name="vsr49", size=16, alias_names=("v49",), vector=True),
Register(name="vsr50", size=16, alias_names=("v50",), vector=True),
Register(name="vsr51", size=16, alias_names=("v51",), vector=True),
Register(name="vsr52", size=16, alias_names=("v52",), vector=True),
Register(name="vsr53", size=16, alias_names=("v53",), vector=True),
Register(name="vsr54", size=16, alias_names=("v54",), vector=True),
Register(name="vsr55", size=16, alias_names=("v55",), vector=True),
Register(name="vsr56", size=16, alias_names=("v56",), vector=True),
Register(name="vsr57", size=16, alias_names=("v57",), vector=True),
Register(name="vsr58", size=16, alias_names=("v58",), vector=True),
Register(name="vsr59", size=16, alias_names=("v59",), vector=True),
Register(name="vsr60", size=16, alias_names=("v60",), vector=True),
Register(name="vsr61", size=16, alias_names=("v61",), vector=True),
Register(name="vsr62", size=16, alias_names=("v62",), vector=True),
Register(name="vsr63", size=16, alias_names=("v63",), vector=True),
Register(name="cia", size=4, alias_names=("ip", "pc")),
Register(name="lr", size=4),
Register(name="ctr", size=4),
Register(name="xer_so", size=1),
Register(name="xer_ov", size=1),
Register(name="xer_ca", size=1),
Register(name="xer_bc", size=1),
Register(name="cr0_321", size=1),
Register(name="cr0_0", size=1, alias_names=("cr0",)),
Register(name="cr1_321", size=1),
Register(name="cr1_0", size=1, alias_names=("cr1",)),
Register(name="cr2_321", size=1),
Register(name="cr2_0", size=1, alias_names=("cr2",)),
Register(name="cr3_321", size=1),
Register(name="cr3_0", size=1, alias_names=("cr3",)),
Register(name="cr4_321", size=1),
Register(name="cr4_0", size=1, alias_names=("cr4",)),
Register(name="cr5_321", size=1),
Register(name="cr5_0", size=1, alias_names=("cr5",)),
Register(name="cr6_321", size=1),
Register(name="cr6_0", size=1, alias_names=("cr6",)),
Register(name="cr7_321", size=1),
Register(name="cr7_0", size=1, alias_names=("cr7",)),
Register(name="fpround", size=1, floating_point=True),
Register(name="dfpround", size=1, floating_point=True),
Register(name="c_fpcc", size=1, floating_point=True),
Register(name="vrsave", size=4, vector=True),
Register(name="vscr", size=4, vector=True),
Register(name="emnote", size=4, artificial=True),
Register(name="cmstart", size=4),
Register(name="cmlen", size=4),
Register(name="nraddr", size=4),
Register(name="nraddr_gpr2", size=4),
Register(name="redir_sp", size=4),
Register(name="redir_stack", size=128),
Register(name="ip_at_syscall", size=4, artificial=True),
Register(name="sprg3_ro", size=4),
Register(name="tfhar", size=8),
Register(name="texasr", size=8),
Register(name="tfiar", size=8),
Register(name="ppr", size=8),
Register(name="texasru", size=4),
Register(name="pspb", size=4),
]
function_prologs = {
rb"[\x00-\xff]{2}\x21\x94\xa6\x02\x08\x7c", # stwu r1, -off(r1); mflr r0
}
function_epilogs = {rb"\xa6\x03[\x00-\xff]{2}([\x00-\xff]{4}){0,6}\x20\x00\x80\x4e"} # mtlr reg; ... ; blr
got_section_name = ".plt"
ld_linux_name = "ld.so.1"
elf_tls = TLSArchInfo(1, 52, [], [48], [], 0x7000, 0x8000)
register_arch([r".*p\w*pc.*be"], 32, "Iend_BE", ArchPPC32)
register_arch([r".*p\w*pc.*"], 32, "any", ArchPPC32)

View File

@@ -0,0 +1,302 @@
import logging
l = logging.getLogger("archinfo.arch_ppc64")
try:
import capstone as _capstone
except ImportError:
_capstone = None
try:
import keystone as _keystone
except ImportError:
_keystone = None
# try:
# import unicorn as _unicorn
# except ImportError:
# _unicorn = None
try:
import pyvex as _pyvex
except ImportError:
_pyvex = None
from .arch import Arch, register_arch, Endness, Register
from .tls import TLSArchInfo
# Note: PowerPC doesn't have pc, so guest_CIA is commented as IP (no arch visible register)
# Normally r1 is used as stack pointer
class ArchPPC64(Arch):
def __init__(self, endness=Endness.LE):
super().__init__(endness)
if endness == Endness.BE:
self.function_prologs = {
rb"\x94\x21[\x00-\xff]{2}\x7c\x08\x02\xa6", # stwu r1, -off(r1); mflr r0
rb"(?!\x94\x21[\x00-\xff]{2})\x7c\x08\x02\xa6", # mflr r0
rb"\xf8\x61[\x00-\xff]{2}", # std r3, -off(r1)
}
self.function_epilogs = {
rb"[\x00-\xff]{2}\x03\xa6([\x00-\xff]{4}){0,6}\x4e\x80\x00\x20" # mtlr reg; ... ; blr
}
self.triplet = "powerpc-linux-gnu"
self.argument_register_positions = (
{
self.registers["r3"][0]: 0,
self.registers["r4"][0]: 1,
self.registers["r5"][0]: 2,
self.registers["r6"][0]: 3,
self.registers["r7"][0]: 4,
self.registers["r8"][0]: 5,
self.registers["r9"][0]: 6,
self.registers["r10"][0]: 7,
# fp registers
self.registers["vsr1"][0]: 0,
self.registers["vsr2"][0]: 1,
self.registers["vsr3"][0]: 2,
self.registers["vsr4"][0]: 3,
self.registers["vsr5"][0]: 4,
self.registers["vsr6"][0]: 5,
self.registers["vsr7"][0]: 6,
self.registers["vsr8"][0]: 7,
self.registers["vsr9"][0]: 8,
self.registers["vsr10"][0]: 9,
self.registers["vsr11"][0]: 10,
self.registers["vsr12"][0]: 11,
self.registers["vsr13"][0]: 12,
# vector registers
self.registers["vsr2"][0]: 0,
self.registers["vsr3"][0]: 1,
self.registers["vsr4"][0]: 2,
self.registers["vsr5"][0]: 3,
self.registers["vsr6"][0]: 4,
self.registers["vsr7"][0]: 5,
self.registers["vsr8"][0]: 6,
self.registers["vsr9"][0]: 7,
self.registers["vsr10"][0]: 8,
self.registers["vsr11"][0]: 9,
self.registers["vsr12"][0]: 10,
self.registers["vsr13"][0]: 11,
}
if _pyvex is not None
else None
)
bits = 64
vex_arch = "VexArchPPC64"
name = "PPC64"
qemu_name = "ppc64"
ida_processor = "ppc64"
triplet = "powerpc64le-linux-gnu"
linux_name = "ppc750"
max_inst_bytes = 4
ret_offset = 40
syscall_num_offset = 16
call_pushes_ret = False
stack_change = -8
initial_sp = 0xFFFFFFFFFF000000
sizeof = {"short": 16, "int": 32, "long": 64, "long long": 64}
if _capstone:
cs_arch = _capstone.CS_ARCH_PPC
cs_mode = _capstone.CS_MODE_64 + _capstone.CS_MODE_LITTLE_ENDIAN
if _keystone:
ks_arch = _keystone.KS_ARCH_PPC
ks_mode = _keystone.KS_MODE_64 + _keystone.KS_MODE_LITTLE_ENDIAN
# Unicorn not supported
# uc_arch = _unicorn.UC_ARCH_PPC if _unicorn else None
# uc_mode = (_unicorn.UC_MODE_64 + _unicorn.UC_MODE_LITTLE_ENDIAN) if _unicorn else None
ret_instruction = b"\x20\x00\x80\x4e"
nop_instruction = b"\x00\x00\x00\x60"
instruction_alignment = 4
register_list = [
Register(name="gpr0", size=8, alias_names=("r0",), general_purpose=True),
Register(
name="gpr1",
size=8,
alias_names=("r1", "sp"),
general_purpose=True,
default_value=(initial_sp, True, "global"),
),
Register(
name="gpr2",
size=8,
alias_names=("r2", "rtoc"),
general_purpose=True,
persistent=True,
linux_entry_value="toc",
),
Register(
name="gpr3", size=8, alias_names=("r3",), general_purpose=True, argument=True, linux_entry_value="argc"
),
Register(
name="gpr4", size=8, alias_names=("r4",), general_purpose=True, argument=True, linux_entry_value="argv"
),
Register(
name="gpr5", size=8, alias_names=("r5",), general_purpose=True, argument=True, linux_entry_value="envp"
),
Register(
name="gpr6", size=8, alias_names=("r6",), general_purpose=True, argument=True, linux_entry_value="auxv"
),
Register(
name="gpr7",
size=8,
alias_names=("r7",),
general_purpose=True,
argument=True,
linux_entry_value="ld_destructor",
),
Register(name="gpr8", size=8, alias_names=("r8",), general_purpose=True, argument=True),
Register(name="gpr9", size=8, alias_names=("r9",), general_purpose=True, argument=True),
Register(name="gpr10", size=8, alias_names=("r10",), general_purpose=True, argument=True),
Register(name="gpr11", size=8, alias_names=("r11",), general_purpose=True),
Register(name="gpr12", size=8, alias_names=("r12",), general_purpose=True, linux_entry_value="entry"),
Register(name="gpr13", size=8, alias_names=("r13",), general_purpose=True),
Register(name="gpr14", size=8, alias_names=("r14",), general_purpose=True),
Register(name="gpr15", size=8, alias_names=("r15",), general_purpose=True),
Register(name="gpr16", size=8, alias_names=("r16",), general_purpose=True),
Register(name="gpr17", size=8, alias_names=("r17",), general_purpose=True),
Register(name="gpr18", size=8, alias_names=("r18",), general_purpose=True),
Register(name="gpr19", size=8, alias_names=("r19",), general_purpose=True),
Register(name="gpr20", size=8, alias_names=("r20",), general_purpose=True),
Register(name="gpr21", size=8, alias_names=("r21",), general_purpose=True),
Register(name="gpr22", size=8, alias_names=("r22",), general_purpose=True),
Register(name="gpr23", size=8, alias_names=("r23",), general_purpose=True),
Register(name="gpr24", size=8, alias_names=("r24",), general_purpose=True),
Register(name="gpr25", size=8, alias_names=("r25",), general_purpose=True, persistent=True),
Register(name="gpr26", size=8, alias_names=("r26",), general_purpose=True),
Register(name="gpr27", size=8, alias_names=("r27",), general_purpose=True),
Register(name="gpr28", size=8, alias_names=("r28",), general_purpose=True),
Register(name="gpr29", size=8, alias_names=("r29",), general_purpose=True),
Register(name="gpr30", size=8, alias_names=("r30",), general_purpose=True),
Register(name="gpr31", size=8, alias_names=("r31", "bp"), general_purpose=True),
Register(name="vsr0", size=16, subregisters=[("fpr0", 0, 8)], alias_names=("v0",), floating_point=True),
Register(name="vsr1", size=16, subregisters=[("fpr1", 0, 8)], alias_names=("v1",), floating_point=True),
Register(name="vsr2", size=16, subregisters=[("fpr2", 0, 8)], alias_names=("v2",), floating_point=True),
Register(name="vsr3", size=16, subregisters=[("fpr3", 0, 8)], alias_names=("v3",), floating_point=True),
Register(name="vsr4", size=16, subregisters=[("fpr4", 0, 8)], alias_names=("v4",), floating_point=True),
Register(name="vsr5", size=16, subregisters=[("fpr5", 0, 8)], alias_names=("v5",), floating_point=True),
Register(name="vsr6", size=16, subregisters=[("fpr6", 0, 8)], alias_names=("v6",), floating_point=True),
Register(name="vsr7", size=16, subregisters=[("fpr7", 0, 8)], alias_names=("v7",), floating_point=True),
Register(name="vsr8", size=16, subregisters=[("fpr8", 0, 8)], alias_names=("v8",), floating_point=True),
Register(name="vsr9", size=16, subregisters=[("fpr9", 0, 8)], alias_names=("v9",), floating_point=True),
Register(name="vsr10", size=16, subregisters=[("fpr10", 0, 8)], alias_names=("v10",), floating_point=True),
Register(name="vsr11", size=16, subregisters=[("fpr11", 0, 8)], alias_names=("v11",), floating_point=True),
Register(name="vsr12", size=16, subregisters=[("fpr12", 0, 8)], alias_names=("v12",), floating_point=True),
Register(name="vsr13", size=16, subregisters=[("fpr13", 0, 8)], alias_names=("v13",), floating_point=True),
Register(name="vsr14", size=16, subregisters=[("fpr14", 0, 8)], alias_names=("v14",), floating_point=True),
Register(name="vsr15", size=16, subregisters=[("fpr15", 0, 8)], alias_names=("v15",), floating_point=True),
Register(name="vsr16", size=16, subregisters=[("fpr16", 0, 8)], alias_names=("v16",), floating_point=True),
Register(name="vsr17", size=16, subregisters=[("fpr17", 0, 8)], alias_names=("v17",), floating_point=True),
Register(name="vsr18", size=16, subregisters=[("fpr18", 0, 8)], alias_names=("v18",), floating_point=True),
Register(name="vsr19", size=16, subregisters=[("fpr19", 0, 8)], alias_names=("v19",), floating_point=True),
Register(name="vsr20", size=16, subregisters=[("fpr20", 0, 8)], alias_names=("v20",), floating_point=True),
Register(name="vsr21", size=16, subregisters=[("fpr21", 0, 8)], alias_names=("v21",), floating_point=True),
Register(name="vsr22", size=16, subregisters=[("fpr22", 0, 8)], alias_names=("v22",), floating_point=True),
Register(name="vsr23", size=16, subregisters=[("fpr23", 0, 8)], alias_names=("v23",), floating_point=True),
Register(name="vsr24", size=16, subregisters=[("fpr24", 0, 8)], alias_names=("v24",), floating_point=True),
Register(name="vsr25", size=16, subregisters=[("fpr25", 0, 8)], alias_names=("v25",), floating_point=True),
Register(name="vsr26", size=16, subregisters=[("fpr26", 0, 8)], alias_names=("v26",), floating_point=True),
Register(name="vsr27", size=16, subregisters=[("fpr27", 0, 8)], alias_names=("v27",), floating_point=True),
Register(name="vsr28", size=16, subregisters=[("fpr28", 0, 8)], alias_names=("v28",), floating_point=True),
Register(name="vsr29", size=16, subregisters=[("fpr29", 0, 8)], alias_names=("v29",), floating_point=True),
Register(name="vsr30", size=16, subregisters=[("fpr30", 0, 8)], alias_names=("v30",), floating_point=True),
Register(name="vsr31", size=16, subregisters=[("fpr31", 0, 8)], alias_names=("v31",), floating_point=True),
Register(name="vsr32", size=16, alias_names=("v32",), vector=True),
Register(name="vsr33", size=16, alias_names=("v33",), vector=True),
Register(name="vsr34", size=16, alias_names=("v34",), vector=True),
Register(name="vsr35", size=16, alias_names=("v35",), vector=True),
Register(name="vsr36", size=16, alias_names=("v36",), vector=True),
Register(name="vsr37", size=16, alias_names=("v37",), vector=True),
Register(name="vsr38", size=16, alias_names=("v38",), vector=True),
Register(name="vsr39", size=16, alias_names=("v39",), vector=True),
Register(name="vsr40", size=16, alias_names=("v40",), vector=True),
Register(name="vsr41", size=16, alias_names=("v41",), vector=True),
Register(name="vsr42", size=16, alias_names=("v42",), vector=True),
Register(name="vsr43", size=16, alias_names=("v43",), vector=True),
Register(name="vsr44", size=16, alias_names=("v44",), vector=True),
Register(name="vsr45", size=16, alias_names=("v45",), vector=True),
Register(name="vsr46", size=16, alias_names=("v46",), vector=True),
Register(name="vsr47", size=16, alias_names=("v47",), vector=True),
Register(name="vsr48", size=16, alias_names=("v48",), vector=True),
Register(name="vsr49", size=16, alias_names=("v49",), vector=True),
Register(name="vsr50", size=16, alias_names=("v50",), vector=True),
Register(name="vsr51", size=16, alias_names=("v51",), vector=True),
Register(name="vsr52", size=16, alias_names=("v52",), vector=True),
Register(name="vsr53", size=16, alias_names=("v53",), vector=True),
Register(name="vsr54", size=16, alias_names=("v54",), vector=True),
Register(name="vsr55", size=16, alias_names=("v55",), vector=True),
Register(name="vsr56", size=16, alias_names=("v56",), vector=True),
Register(name="vsr57", size=16, alias_names=("v57",), vector=True),
Register(name="vsr58", size=16, alias_names=("v58",), vector=True),
Register(name="vsr59", size=16, alias_names=("v59",), vector=True),
Register(name="vsr60", size=16, alias_names=("v60",), vector=True),
Register(name="vsr61", size=16, alias_names=("v61",), vector=True),
Register(name="vsr62", size=16, alias_names=("v62",), vector=True),
Register(name="vsr63", size=16, alias_names=("v63",), vector=True),
Register(name="cia", size=8, alias_names=("ip", "pc")),
Register(name="lr", size=8),
Register(name="ctr", size=8),
Register(name="xer_so", size=1),
Register(name="xer_ov", size=1),
Register(name="xer_ca", size=1),
Register(name="xer_bc", size=1),
Register(name="cr0_321", size=1),
Register(name="cr0_0", size=1, alias_names=("cr0",)),
Register(name="cr1_321", size=1),
Register(name="cr1_0", size=1, alias_names=("cr1",)),
Register(name="cr2_321", size=1),
Register(name="cr2_0", size=1, alias_names=("cr2",)),
Register(name="cr3_321", size=1),
Register(name="cr3_0", size=1, alias_names=("cr3",)),
Register(name="cr4_321", size=1),
Register(name="cr4_0", size=1, alias_names=("cr4",)),
Register(name="cr5_321", size=1),
Register(name="cr5_0", size=1, alias_names=("cr5",)),
Register(name="cr6_321", size=1),
Register(name="cr6_0", size=1, alias_names=("cr6",)),
Register(name="cr7_321", size=1),
Register(name="cr7_0", size=1, alias_names=("cr7",)),
Register(name="fpround", size=1, floating_point=True),
Register(name="dfpround", size=1, floating_point=True),
Register(name="c_fpcc", size=1, floating_point=True),
Register(name="vrsave", size=4, vector=True),
Register(name="vscr", size=4, vector=True),
Register(name="emnote", size=4, artificial=True),
Register(name="cmstart", size=8),
Register(name="cmlen", size=8),
Register(name="nraddr", size=8),
Register(name="nraddr_gpr2", size=8),
Register(name="redir_sp", size=8),
Register(name="redir_stack", size=256),
Register(name="ip_at_syscall", size=8, artificial=True),
Register(name="sprg3_ro", size=8),
Register(name="tfhar", size=8),
Register(name="texasr", size=8),
Register(name="tfiar", size=8),
Register(name="ppr", size=8),
Register(name="texasru", size=4),
Register(name="pspb", size=4),
]
# see https://github.com/riscv/riscv-binutils-gdb/blob/82dcb8613e1b1fb2989deffde1d3c9729695ff9c/include/elf/ppc64.h
dynamic_tag_translation = {
0x70000000: "DT_PPC64_GLINK",
0x70000001: "DT_PPC64_OPD",
0x70000002: "DT_PPC64_OPDSZ",
0x70000003: "DT_PPC64_OPT",
}
function_prologs = {
rb"[\x00-\xff]{2}\x21\x94\xa6\x02\x08\x7c", # stwu r1, -off(r1); mflr r0
}
function_epilogs = {rb"\xa6\x03[\x00-\xff]{2}([\x00-\xff]{4}){0,6}\x20\x00\x80\x4e"} # mtlr reg; ... ; blr
got_section_name = ".plt"
ld_linux_name = "ld64.so.1"
elf_tls = TLSArchInfo(1, 92, [], [84], [], 0x7000, 0x8000)
register_arch([r".*p\w*pc.*be"], 64, "Iend_BE", ArchPPC64)
register_arch([r".*p\w*pc.*"], 64, "any", ArchPPC64)

View File

@@ -0,0 +1,199 @@
try:
import capstone as _capstone
except ImportError:
_capstone = None
try:
import keystone as _keystone
except ImportError:
_keystone = None
try:
import pyvex as _pyvex
except ImportError:
_pyvex = None
from .arch import Arch, register_arch, Endness, Register
from .archerror import ArchError
from .tls import TLSArchInfo
class ArchS390X(Arch):
def __init__(self, endness=Endness.BE):
super().__init__(endness)
if endness != Endness.BE:
raise ArchError("Arch s390x must be big endian")
self.argument_register_positions = (
{
self.registers["r2"][0]: 0,
self.registers["r3"][0]: 1,
self.registers["r4"][0]: 2,
self.registers["r5"][0]: 3,
self.registers["r6"][0]: 4,
# fp registers
self.registers["f0"][0]: 0,
self.registers["f2"][0]: 1,
self.registers["f4"][0]: 2,
self.registers["f6"][0]: 3,
}
if _pyvex is not None
else None
)
bits = 64
vex_arch = "VexArchS390X" # enum VexArch
name = "S390X"
qemu_name = "s390x" # target/s390x
triplet = "s390x-linux-gnu"
linux_name = "s390" # arch/s390
max_inst_bytes = 6
ret_offset = 584 # offsetof(VexGuestS390XState, guest_r2)
syscall_num_offset = 576 # offsetof(VexGuestS390XState, guest_r1)
call_pushes_ret = False
stack_change = -8
initial_sp = 0x40000000000
sizeof = {"short": 16, "int": 32, "long": 64, "long long": 64}
if _capstone:
cs_arch = _capstone.CS_ARCH_SYSZ
cs_mode = _capstone.CS_MODE_BIG_ENDIAN
if _keystone:
ks_arch = _keystone.KS_ARCH_SYSTEMZ
ks_mode = _keystone.KS_MODE_BIG_ENDIAN
ret_instruction = b"\x07\xf4" # br %r14
nop_instruction = b"\x07\x07" # nopr %r7
instruction_alignment = 2
register_list = [
Register(name="ia", size=8, alias_names=("ip", "pc")),
Register(name="r0", size=8, general_purpose=True),
Register(name="r1", size=8, general_purpose=True, subregisters=[("r1_32", 4, 4)]),
Register(name="r2", size=8, general_purpose=True, argument=True, subregisters=[("r2_32", 4, 4)]),
Register(
name="r3",
size=8,
general_purpose=True,
argument=True,
linux_entry_value="argc",
subregisters=[("r3_32", 4, 4)],
),
Register(
name="r4",
size=8,
general_purpose=True,
argument=True,
linux_entry_value="argv",
subregisters=[("r4_32", 4, 4)],
),
Register(
name="r5",
size=8,
general_purpose=True,
argument=True,
linux_entry_value="envp",
subregisters=[("r5_32", 4, 4)],
),
Register(
name="r6", size=8, general_purpose=True, argument=True, persistent=True, subregisters=[("r6_32", 4, 4)]
),
Register(name="r7", size=8, general_purpose=True, persistent=True, subregisters=[("r7_32", 4, 4)]),
Register(name="r8", size=8, general_purpose=True, persistent=True, subregisters=[("r8_32", 4, 4)]),
Register(name="r9", size=8, general_purpose=True, persistent=True, subregisters=[("r9_32", 4, 4)]),
Register(name="r10", size=8, general_purpose=True, persistent=True, subregisters=[("r10_32", 4, 4)]),
Register(
name="r11",
size=8,
alias_names=("bp",),
general_purpose=True,
persistent=True,
subregisters=[("r11_32", 4, 4)],
),
Register(name="r12", size=8, general_purpose=True, persistent=True, subregisters=[("r12_32", 4, 4)]),
Register(name="r13", size=8, general_purpose=True, persistent=True, subregisters=[("r13_32", 4, 4)]),
# Strictly speaking, there is no fixed link register on s390x.
# However, %r14 is almost always used for that, so mark it as such.
# Situations when that's not the case (e.g. brasl %r0,X)
# can still be handled explicitly.
Register(name="r14", size=8, general_purpose=True, alias_names=("lr",)),
Register(
name="r15",
size=8,
alias_names=("sp",),
general_purpose=True,
persistent=True,
default_value=(initial_sp, True, "global"),
),
Register(name="v0", size=16, subregisters=[("f0", 0, 8)], floating_point=True),
Register(name="v1", size=16, subregisters=[("f1", 0, 8)], floating_point=True),
Register(name="v2", size=16, subregisters=[("f2", 0, 8)], floating_point=True),
Register(name="v3", size=16, subregisters=[("f3", 0, 8)], floating_point=True),
Register(name="v4", size=16, subregisters=[("f4", 0, 8)], floating_point=True),
Register(name="v5", size=16, subregisters=[("f5", 0, 8)], floating_point=True),
Register(name="v6", size=16, subregisters=[("f6", 0, 8)], floating_point=True),
Register(name="v7", size=16, subregisters=[("f7", 0, 8)], floating_point=True),
Register(name="v8", size=16, subregisters=[("f8", 0, 8)], floating_point=True),
Register(name="v9", size=16, subregisters=[("f9", 0, 8)], floating_point=True),
Register(name="v10", size=16, subregisters=[("f10", 0, 8)], floating_point=True),
Register(name="v11", size=16, subregisters=[("f11", 0, 8)], floating_point=True),
Register(name="v12", size=16, subregisters=[("f12", 0, 8)], floating_point=True),
Register(name="v13", size=16, subregisters=[("f13", 0, 8)], floating_point=True),
Register(name="v14", size=16, subregisters=[("f14", 0, 8)], floating_point=True),
Register(name="v15", size=16, subregisters=[("f15", 0, 8)], floating_point=True),
Register(name="v16", size=16, vector=True),
Register(name="v17", size=16, vector=True),
Register(name="v18", size=16, vector=True),
Register(name="v19", size=16, vector=True),
Register(name="v20", size=16, vector=True),
Register(name="v21", size=16, vector=True),
Register(name="v22", size=16, vector=True),
Register(name="v23", size=16, vector=True),
Register(name="v24", size=16, vector=True),
Register(name="v25", size=16, vector=True),
Register(name="v26", size=16, vector=True),
Register(name="v27", size=16, vector=True),
Register(name="v28", size=16, vector=True),
Register(name="v29", size=16, vector=True),
Register(name="v30", size=16, vector=True),
Register(name="v31", size=16, vector=True),
Register(name="a0", size=4),
Register(name="a1", size=4),
Register(name="a2", size=4),
Register(name="a3", size=4),
Register(name="a4", size=4),
Register(name="a5", size=4),
Register(name="a6", size=4),
Register(name="a7", size=4),
Register(name="a8", size=4),
Register(name="a9", size=4),
Register(name="a10", size=4),
Register(name="a11", size=4),
Register(name="a12", size=4),
Register(name="a13", size=4),
Register(name="a14", size=4),
Register(name="a15", size=4),
Register(name="nraddr", size=8),
Register(name="cmstart", size=8),
Register(name="cmlen", size=8),
Register(name="ip_at_syscall", size=8, artificial=True),
Register(name="emnote", size=4, artificial=True),
]
function_prologs = {
rb"\xeb.[\xf0-\xff]..\x24", # stmg %r1,%r3,d2(%r15)
}
function_epilogs = {
rb"\x07\xf4", # br %r14
}
got_section_name = ".got"
ld_linux_name = "ld64.so.1"
elf_tls = TLSArchInfo(
variant=2, # 3.4.7 @ https://www.uclibc.org/docs/tls.pdf
tcbhead_size=64, # sizeof(tcbhead_t)
head_offsets=[0], # offsetof(tcbhead_t, tcb)
dtv_offsets=[8], # offsetof(tcbhead_t, dtv)
pthread_offsets=[16], # offsetof(tcbhead_t, self)
tp_offset=0,
dtv_entry_offset=0,
)
register_arch(["s390"], 64, Endness.BE, ArchS390X)

View File

@@ -0,0 +1,400 @@
import logging
import re
from .arch import Arch, Endness, register_arch
l = logging.getLogger("archinfo.arch_soot")
class SootMethodDescriptor:
__slots__ = ["class_name", "name", "params", "_soot_method", "ret"]
def __init__(self, class_name, name, params, soot_method=None, ret_type=None):
self.class_name = class_name
self.name = name
self.params = params
self._soot_method = soot_method
self.ret = ret_type
def __repr__(self):
return "{}.{}({})".format(self.class_name, self.name, ", ".join(self.params))
def __hash__(self):
return hash((self.class_name, self.name, self.params))
def __eq__(self, other):
return (
isinstance(other, SootMethodDescriptor)
and self.class_name == other.class_name
and self.name == other.name
and self.params == other.params
)
def __ne__(self, other):
return not self == other
def __lt__(self, other):
return self.__repr__() < other.__repr__()
def __gt__(self, other):
return self.__repr__() > other.__repr__()
def __le__(self, other):
return self.__repr__() <= other.__repr__()
def __ge__(self, other):
return self.__repr__() >= other.__repr__()
def address(self, block_idx=0, stmt_idx=0):
"""
:return Address of the method.
:rtype: SootAddressDescriptor
"""
return SootAddressDescriptor(self, block_idx, stmt_idx)
@property
def fullname(self):
"""
:return the full name of the method (class name + method name)
"""
return f"{self.class_name}.{self.name}"
@property
def symbolic(self):
return False
@property
def is_loaded(self):
"""
:return: True, if the method is loaded in CLE and thus infos about attrs,
ret and exceptions are available.
"""
return self._soot_method is not None
@property
def attrs(self):
return self._soot_method.attrs if self.is_loaded else []
@property
def exceptions(self):
return self._soot_method.exceptions if self.is_loaded else []
@property
def block_by_label(self):
return self._soot_method.block_by_label if self.is_loaded else None
# @property
# def ret(self):
# return self._soot_method.ret if self.is_loaded else []
@property
def addr(self):
"""
:return: the soot address description of the entry point of the method
"""
return SootAddressDescriptor(self, 0, 0)
def matches_with_native_name(self, native_method):
"""
The name of native methods are getting encoded, s.t. they translate into
valid C function names. This method indicates if the name of the given
native method matches the name of the soot method.
:return: True, if name of soot method matches the mangled native name.
"""
if "__" in native_method:
# if native methods are overloaded, two underscores are used
native_method, params_sig = native_method.split("__")
params = ArchSoot.decode_parameter_list_signature(params_sig)
# check function signature
if params != self.params:
return False
# demangle native name
native_method = native_method.replace("_1", "_")
# TODO unicode escaping
method_native_name = "Java_{class_name}_{method_name}".format(
class_name=self.class_name.replace(".", "_"), method_name=self.name
)
return native_method == method_native_name
@classmethod
def from_string(cls, tstr):
# this should be the opposite of repr
tstr = tstr.strip()
class_and_method, tparams = tstr.split("(")
params_str = tparams.split(")")[0]
if params_str == "":
params = ()
else:
params = tuple(t.strip() for t in params_str.split(","))
class_name, _, method = class_and_method.rpartition(".")
return cls(class_name, method, params)
@classmethod
def from_soot_method(cls, soot_method):
return cls(
class_name=soot_method.class_name,
name=soot_method.name,
params=soot_method.params,
soot_method=soot_method,
ret_type=soot_method.ret,
)
class SootAddressDescriptor:
__slots__ = ["method", "block_idx", "stmt_idx"]
def __init__(self, method, block_idx, stmt_idx):
if not isinstance(method, SootMethodDescriptor):
raise ValueError('The parameter "method" must be an ' "instance of SootMethodDescriptor.")
self.method = method
self.block_idx = block_idx
self.stmt_idx = stmt_idx
def __repr__(self):
return "<{!r}+({}:{})>".format(
self.method, self.block_idx, "%d" % self.stmt_idx if self.stmt_idx is not None else "[0]"
)
def __hash__(self):
return hash((self.method, self.stmt_idx))
def __eq__(self, other):
return (
isinstance(other, SootAddressDescriptor)
and self.method == other.method
and self.block_idx == other.block_idx
and self.stmt_idx == other.stmt_idx
)
def __ne__(self, other):
return not self == other
def __lt__(self, other):
return self.__repr__() < other.__repr__()
def __gt__(self, other):
return self.__repr__() > other.__repr__()
def __le__(self, other):
return self.__repr__() <= other.__repr__()
def __ge__(self, other):
return self.__repr__() >= other.__repr__()
def __add__(self, stmts_offset):
if not isinstance(stmts_offset, int):
raise TypeError("The stmts_offset must be an int or a long.")
s = self.copy()
s.stmt_idx += stmts_offset
return s
def copy(self):
return SootAddressDescriptor(method=self.method, block_idx=self.block_idx, stmt_idx=self.stmt_idx)
@property
def symbolic(self):
return False
class SootAddressTerminator(SootAddressDescriptor):
__slots__ = []
def __init__(self):
dummy_method = SootMethodDescriptor("dummy", "dummy", tuple())
super().__init__(dummy_method, 0, 0)
def __repr__(self):
return "<Terminator>"
class SootFieldDescriptor:
__slots__ = ["class_name", "name", "type"]
def __init__(self, class_name, name, type_):
self.class_name = class_name
self.name = name
self.type = type_
def __repr__(self):
return f"{self.class_name}.{self.name}"
def __hash__(self):
return hash((self.class_name, self.name, self.type))
def __eq__(self, other):
return (
isinstance(other, SootFieldDescriptor)
and self.class_name == other.class_name
and self.name == other.name
and self.type == other.type
)
def __ne__(self, other):
return not self == other
class SootClassDescriptor:
__slots__ = ["name", "_soot_class"]
def __init__(self, name, soot_class=None):
self.name = name
self._soot_class = soot_class
def __repr__(self):
return self.name
def __hash__(self):
return hash(self.name)
def __eq__(self, other):
return isinstance(other, SootClassDescriptor) and self.name == other.name
def __ne__(self, other):
return not self == other
@property
def is_loaded(self):
"""
:return: True, if the class is loaded in CLE and thus info about field,
methods, ... are available.
"""
return self._soot_class is not None
@property
def fields(self):
return self._soot_class.fields if self.is_loaded else None
@property
def methods(self):
return self._soot_class.methods if self.is_loaded else None
@property
def superclass_name(self):
return self._soot_class.super_class if self.is_loaded else None
@property
def type(self):
return "java.lang.Class"
class SootNullConstant:
def __init__(self):
pass
def __repr__(self):
return "null"
def __hash__(self):
return hash("null")
def __eq__(self, other):
return isinstance(other, SootNullConstant)
def __ne__(self, other):
return not self == other
class SootArgument:
"""
Typed Java argument.
"""
__slots__ = ["value", "type", "is_this_ref"]
def __init__(self, value, type_, is_this_ref=False):
"""
:param value: Value of the argument
:param type_: Type of the argument
:param is_this_ref: Indicates whether the argument represents the
'this' reference, i.e. the object on which an
instance method is invoked.
"""
self.value = value
self.type = type_
self.is_this_ref = is_this_ref
def __repr__(self):
return f"{self.value} ({self.type})"
class ArchSoot(Arch):
def __init__(self, endness=Endness.LE):
super().__init__(endness)
name = "Soot"
vex_arch = None # No VEX support
qemu_name = None # No Qemu/Unicorn-engine support
bits = 64
address_types = (SootAddressDescriptor,)
function_address_types = (SootMethodDescriptor,)
# Size of native counterparts of primitive Java types
sizeof = {"boolean": 8, "byte": 8, "char": 16, "short": 16, "int": 32, "long": 64, "float": 32, "double": 64}
primitive_types = ["boolean", "byte", "char", "short", "int", "long", "float", "double"]
sig_dict = {
"Z": "boolean",
"B": "byte",
"C": "char",
"S": "short",
"I": "int",
"J": "long",
"F": "float",
"D": "double",
"V": "void",
}
@staticmethod
def decode_type_signature(type_sig):
if not type_sig:
return None
# try to translate signature as a primitive type
if type_sig in ArchSoot.sig_dict:
return ArchSoot.sig_dict[type_sig]
# java classes are encoded as 'Lclass_name;'
if type_sig.startswith("L") and type_sig.endswith(";"):
return type_sig[1:-1]
raise ValueError(type_sig)
@staticmethod
def decode_parameter_list_signature(param_sig):
return tuple(
ArchSoot.decode_type_signature(param) for param in re.findall(r"([\[]*[ZBCSIJFDV]|[\[]*L.+;)", param_sig)
)
@staticmethod
def decode_method_signature(method_sig):
# signature format follows the pattern: (param_sig)ret_sig
match = re.search(r"\((.*)\)(.*)", method_sig)
param_sig, ret_sig = match.group(1), match.group(2)
# decode types
params_types = ArchSoot.decode_parameter_list_signature(param_sig)
ret_type = ArchSoot.decode_type_signature(ret_sig)
l.debug("Decoded method signature '%s' as params=%s and ret=%s", method_sig, params_types, ret_type)
return params_types, ret_type
def library_search_path(self, pedantic=False):
"""
Since Java is mostly system independent, we cannot return system
specific paths.
:return: empty list
"""
return []
register_arch(["soot"], 8, Endness.LE, ArchSoot)

View File

@@ -0,0 +1,302 @@
import logging
l = logging.getLogger("archinfo.arch_x86")
try:
import capstone as _capstone
except ImportError:
_capstone = None
try:
import keystone as _keystone
except ImportError:
_keystone = None
try:
import unicorn as _unicorn
except ImportError:
_unicorn = None
try:
import pyvex as _pyvex
except ImportError:
_pyvex = None
from .arch import Arch, register_arch, Endness, Register
from .tls import TLSArchInfo
from .archerror import ArchError
_NATIVE_FUNCTION_PROLOGS = [
rb"\x8b\xff\x55\x8b\xec", # mov edi, edi; push ebp; mov ebp, esp
rb"\x55\x8b\xec", # push ebp; mov ebp, esp
rb"\x55\x89\xe5", # push ebp; mov ebp, esp
rb"\x55\x57\x56", # push ebp; push edi; push esi
# mov eax, 0x000000??; (push ebp; push eax; push edi; push ebx; push esi; push edx; push ecx) sub esp
rb"\xb8[\x00-\xff]\x00\x00\x00[\x50\x51\x52\x53\x55\x56\x57]{0,7}\x8b[\x00-\xff]{2}",
# (push ebp; push eax; push edi; push ebx; push esi; push edx; push ecx) sub esp
rb"[\x50\x51\x52\x53\x55\x56\x57]{1,7}\x83\xec[\x00-\xff]{2,4}",
# (push ebp; push eax; push edi; push ebx; push esi; push edx; push ecx) mov xxx, xxx
rb"[\x50\x51\x52\x53\x55\x56\x57]{1,7}\x8b[\x00-\xff]{2}",
rb"(\x81|\x83)\xec", # sub xxx %esp
]
# every function prolog can potentially be prefixed with endbr32
_endbr32 = b"\xf3\x0f\x1e\xfb"
_prefixed = [(_endbr32 + prolog) for prolog in _NATIVE_FUNCTION_PROLOGS]
_FUNCTION_PROLOGS = _prefixed + _NATIVE_FUNCTION_PROLOGS
class ArchX86(Arch):
def __init__(self, endness=Endness.LE):
if endness != Endness.LE:
raise ArchError("Arch i386 must be little endian")
super().__init__(endness)
if self.vex_archinfo:
self.vex_archinfo["x86_cr0"] = 0xFFFFFFFF
# Register blacklist
reg_blacklist = ("cs", "ds", "es", "fs", "gs", "ss", "gdt", "ldt")
if self.reg_blacklist is not None and self.reg_blacklist_offsets is not None:
for register in self.register_list:
if register.name in reg_blacklist:
self.reg_blacklist.append(register.name)
self.reg_blacklist_offsets.append(register.vex_offset)
if _unicorn and _pyvex:
# CPU flag registers
uc_flags_reg = _unicorn.x86_const.UC_X86_REG_EFLAGS
cpu_flag_registers = {"d": 1 << 10, "ac": 1 << 18, "id": 1 << 21}
for reg, reg_bitmask in cpu_flag_registers.items():
reg_offset = self.get_register_offset(reg)
self.cpu_flag_register_offsets_and_bitmasks_map[reg_offset] = (uc_flags_reg, reg_bitmask)
mxcsr_registers = {"sseround": 1 << 14 | 1 << 13}
uc_mxcsr_reg = _unicorn.x86_const.UC_X86_REG_MXCSR
for reg, reg_bitmask in mxcsr_registers.items():
reg_offset = self.get_register_offset(reg)
self.cpu_flag_register_offsets_and_bitmasks_map[reg_offset] = (uc_mxcsr_reg, reg_bitmask)
@property
def capstone_x86_syntax(self):
"""
Get the current syntax Capstone uses for x86. It can be 'intel' or 'at&t'
:return: Capstone's current x86 syntax
:rtype: str
"""
return self._cs_x86_syntax
@capstone_x86_syntax.setter
def capstone_x86_syntax(self, new_syntax):
"""
Set the syntax that Capstone outputs for x86.
"""
if new_syntax not in ("intel", "at&t"):
raise ArchError('Unsupported Capstone x86 syntax. It must be either "intel" or "at&t".')
if new_syntax != self._cs_x86_syntax:
self._cs = None
self._cs_x86_syntax = new_syntax
def _configure_capstone(self):
self._cs.syntax = (
_capstone.CS_OPT_SYNTAX_ATT if self._cs_x86_syntax == "at&t" else _capstone.CS_OPT_SYNTAX_INTEL
)
@property
def keystone_x86_syntax(self):
"""
Get the current syntax Keystone uses for x86. It can be 'intel',
'at&t', 'nasm', 'masm', 'gas' or 'radix16'
:return: Keystone's current x86 syntax
:rtype: str
"""
return self._ks_x86_syntax
@keystone_x86_syntax.setter
def keystone_x86_syntax(self, new_syntax):
"""
Set the syntax that Keystone uses for x86.
"""
if new_syntax not in ("intel", "at&t", "nasm", "masm", "gas", "radix16"):
raise ArchError(
"Unsupported Keystone x86 syntax. It must be one of the following: "
'"intel", "at&t", "nasm", "masm", "gas" or "radix16".'
)
if new_syntax != self._ks_x86_syntax:
self._ks = None
self._ks_x86_syntax = new_syntax
def _configure_keystone(self):
if self._ks_x86_syntax == "at&t":
self._ks.syntax = _keystone.KS_OPT_SYNTAX_ATT
elif self._ks_x86_syntax == "nasm":
self._ks.syntax = _keystone.KS_OPT_SYNTAX_NASM
elif self._ks_x86_syntax == "masm":
self._ks.syntax = _keystone.KS_OPT_SYNTAX_MASM
elif self._ks_x86_syntax == "gas":
self._ks.syntax = _keystone.KS_OPT_SYNTAX_GAS
elif self._ks_x86_syntax == "radix16":
self._ks.syntax = _keystone.KS_OPT_SYNTAX_RADIX16
else:
self._ks.syntax = _keystone.KS_OPT_SYNTAX_INTEL
bits = 32
vex_arch = "VexArchX86"
name = "X86"
qemu_name = "i386"
ida_processor = "metapc"
linux_name = "i386"
triplet = "i386-linux-gnu"
max_inst_bytes = 15
call_sp_fix = -4
ret_offset = 8
vex_conditional_helpers = True
syscall_num_offset = 8
call_pushes_ret = True
stack_change = -4
memory_endness = Endness.LE
register_endness = Endness.LE
sizeof = {"short": 16, "int": 32, "long": 32, "long long": 64}
if _capstone:
cs_arch = _capstone.CS_ARCH_X86
cs_mode = _capstone.CS_MODE_32 + _capstone.CS_MODE_LITTLE_ENDIAN
_cs_x86_syntax = None # Set it to 'att' in order to use AT&T syntax for x86
if _keystone:
ks_arch = _keystone.KS_ARCH_X86
ks_mode = _keystone.KS_MODE_32 + _keystone.KS_MODE_LITTLE_ENDIAN
_ks_x86_syntax = None
uc_arch = _unicorn.UC_ARCH_X86 if _unicorn else None
uc_mode = (_unicorn.UC_MODE_32 + _unicorn.UC_MODE_LITTLE_ENDIAN) if _unicorn else None
uc_const = _unicorn.x86_const if _unicorn else None
uc_prefix = "UC_X86_" if _unicorn else None
function_prologs = _FUNCTION_PROLOGS
function_epilogs = {
rb"\xc9\xc3", # leave; ret
rb"([^\x41][\x50-\x5f]{1}|\x41[\x50-\x5f])\xc3", # pop <reg>; ret
rb"[^\x48][\x83,\x81]\xc4([\x00-\xff]{1}|[\x00-\xff]{4})\xc3", # add esp, <siz>; retq
}
ret_instruction = b"\xc3"
nop_instruction = b"\x90"
instruction_alignment = 1
register_list = [
Register(
name="eax",
size=4,
subregisters=[("ax", 0, 2), ("al", 0, 1), ("ah", 1, 1)],
general_purpose=True,
argument=True,
linux_entry_value=0x1C,
),
Register(
name="ecx",
size=4,
subregisters=[("cx", 0, 2), ("cl", 0, 1), ("ch", 1, 1)],
general_purpose=True,
argument=True,
),
Register(
name="edx",
size=4,
subregisters=[("dx", 0, 2), ("dl", 0, 1), ("dh", 1, 1)],
general_purpose=True,
argument=True,
linux_entry_value="ld_destructor",
),
Register(
name="ebx",
size=4,
subregisters=[("bx", 0, 2), ("bl", 0, 1), ("bh", 1, 1)],
general_purpose=True,
argument=True,
),
Register(
name="esp",
size=4,
alias_names=("sp",),
general_purpose=True,
default_value=(Arch.initial_sp, True, "global"),
),
Register(name="ebp", size=4, alias_names=("bp",), general_purpose=True, argument=True, linux_entry_value=0),
Register(
name="esi",
size=4,
subregisters=[("si", 0, 2), ("sil", 0, 1), ("sih", 1, 1)],
general_purpose=True,
argument=True,
),
Register(
name="edi",
size=4,
subregisters=[("di", 0, 2), ("dil", 0, 1), ("dih", 1, 1)],
general_purpose=True,
argument=True,
),
Register(name="cc_op", size=4, default_value=(0, False, None), concrete=False, artificial=True),
Register(name="cc_dep1", size=4, concrete=False, artificial=True),
Register(name="cc_dep2", size=4, concrete=False, artificial=True),
Register(name="cc_ndep", size=4, concrete=False, artificial=True),
Register(name="d", size=4, alias_names=("dflag",), default_value=(1, False, None), concrete=False),
Register(name="id", size=4, alias_names=("idflag",), default_value=(1, False, None), concrete=False),
Register(name="ac", size=4, alias_names=("acflag",), default_value=(0, False, None), concrete=False),
Register(name="eip", size=4, alias_names=("ip", "pc")),
Register(
name="fpreg",
size=64,
subregisters=[
("mm0", 0, 8),
("mm1", 8, 8),
("mm2", 16, 8),
("mm3", 24, 8),
("mm4", 32, 8),
("mm5", 40, 8),
("mm6", 48, 8),
("mm7", 56, 8),
],
alias_names=("fpu_regs",),
floating_point=True,
concrete=False,
),
Register(name="fptag", size=8, alias_names=("fpu_tags",), floating_point=True, default_value=(0, False, None)),
Register(name="fpround", size=4, floating_point=True, default_value=(0, False, None)),
Register(name="fc3210", size=4, floating_point=True),
Register(name="ftop", size=4, floating_point=True, default_value=(7, False, None), artificial=True),
Register(name="sseround", size=4, vector=True, default_value=(0, False, None)),
Register(name="xmm0", size=16, vector=True),
Register(name="xmm1", size=16, vector=True),
Register(name="xmm2", size=16, vector=True),
Register(name="xmm3", size=16, vector=True),
Register(name="xmm4", size=16, vector=True),
Register(name="xmm5", size=16, vector=True),
Register(name="xmm6", size=16, vector=True),
Register(name="xmm7", size=16, vector=True),
Register(name="cs", size=2),
Register(name="ds", size=2),
Register(name="es", size=2),
Register(name="fs", size=2, default_value=(0, False, None), concrete=False),
Register(name="gs", size=2, default_value=(0, False, None), concrete=False),
Register(name="ss", size=2),
Register(name="ldt", size=8, default_value=(0, False, None), concrete=False),
Register(name="gdt", size=8, default_value=(0, False, None), concrete=False),
Register(name="emnote", size=4, artificial=True),
Register(name="cmstart", size=4),
Register(name="cmlen", size=4),
Register(name="nraddr", size=4),
Register(name="sc_class", size=4),
Register(name="ip_at_syscall", size=4, concrete=False, artificial=True),
]
symbol_type_translation = {10: "STT_GNU_IFUNC", "STT_LOOS": "STT_GNU_IFUNC"}
lib_paths = ["/lib32", "/usr/lib32"]
got_section_name = ".got.plt"
ld_linux_name = "ld-linux.so.2"
elf_tls = TLSArchInfo(2, 56, [8], [4], [0], 0, 0)
register_arch([r".*i?\d86|.*x32|.*x86|.*metapc"], 32, Endness.LE, ArchX86)

View File

@@ -0,0 +1,2 @@
class ArchError(Exception):
pass

View File

@@ -0,0 +1,19 @@
from collections import namedtuple
# REFERENCES:
# [1] https://www.uclibc.org/docs/tls.pdf
# [2] https://www.uclibc.org/docs/tls-ppc.txt
# [3] https://www.uclibc.org/docs/tls-ppc64.txt
# [4] https://www.linux-mips.org/wiki/NPTL
TLSArchInfo = namedtuple(
"TLSArchInfo",
("variant", "tcbhead_size", "head_offsets", "dtv_offsets", "pthread_offsets", "tp_offset", "dtv_entry_offset"),
)
# variant: 1 or 2 based on the memory layout scheme
# tcbhead_size: the size of the thread control block head struct
# head_offsets: the offsets in the the tcb struct where a pointer to the head is kept
# dtv_offsets: the offsets in the tcb struct where a pointer to the dtv is kept
# pthread_offsets: the offsets in the tcb struct where a pointer to libc's pthread data is kept, I guess?
# tp_offset: the offset between the thread pointer from [1] and the thread pointer given to the program, see [2],[3]
# dtv_entry_offset: the offset between the value stored in the dtv and the actual start of the given dtv entry