コード例 #1
0
ファイル: registers.py プロジェクト: GaZ3ll3/PeachPy
    def __init__(self, mask, virtual_id=None, physical_id=None):
        super(Register, self).__init__()
        from peachpy.util import is_int

        assert is_int(mask), "Mask must be an integer"
        assert mask in Register._mask_size_map, "Unknown mask value: %X" % mask
        self.mask = int(mask)
        assert virtual_id is not None or physical_id is not None, "Virtual or physical ID must be specified"
        assert virtual_id is None or is_int(virtual_id) and virtual_id > 0, "Virtual ID must be a positive integer"
        assert (
            physical_id is None or is_int(physical_id) and physical_id >= 0
        ), "Physical ID must be a non-negative integer"
        self.virtual_id = None if virtual_id is None else int(virtual_id)
        self.physical_id = None if physical_id is None else int(physical_id)
コード例 #2
0
ファイル: instructions.py プロジェクト: Rinoahu/PeachPy
    def format(self, assembly_format, indent):
        from peachpy.x86_64.operand import format_operand

        text = "\t" * self._indent_level if indent else ""
        if assembly_format == "peachpy":
            return text + str(self)
        elif assembly_format == "nasm":
            return text + str(self)
        elif assembly_format == "gas":
            return text + str(self)
        elif assembly_format == "go":
            if self.go_name:
                from peachpy.util import is_int

                if self.name == "CMP" and is_int(self.operands[1]):
                    # CMP instruction with an immediate operand has operands in normal (non-reversed) order
                    return (
                        text
                        + str(self.go_name)
                        + " "
                        + ", ".join(format_operand(op, assembly_format) for op in self.operands)
                    )
                elif self.operands:
                    return (
                        text
                        + str(self.go_name)
                        + " "
                        + ", ".join(format_operand(op, assembly_format) for op in reversed(self.operands))
                    )
                else:
                    return text + str(self.go_name)
            else:
                return text + "; ".join(map(lambda b: "BYTE $0x%02X" % b, self.encode())) + " // " + str(self)
コード例 #3
0
ファイル: operand.py プロジェクト: hotelzululima/PeachPy
    def __init__(self, base=None, index=None, scale=None, displacement=0):
        from peachpy.x86_64.registers import GeneralPurposeRegister64, GeneralPurposeRegister32
        from peachpy.util import is_int, is_sint32

        # Check individual arguments
        if base is not None and not isinstance(base, (GeneralPurposeRegister32, GeneralPurposeRegister64)):
            raise TypeError("Base register must be a 32- or 64-bit general-purpose register")
        if index is not None and not isinstance(index, (GeneralPurposeRegister32, GeneralPurposeRegister64)):
            raise TypeError("Index register must be a 32- or 64-bit general-purpose register")
        if scale is not None and not is_int(scale):
            raise TypeError("Scale must be an integer")
        if scale is not None and int(scale) not in {1, 2, 4, 8}:
            raise TypeError("Scale must be 1, 2, 4, or 8")
        if not is_sint32(displacement):
            raise ValueError("Displacement value (%s) is not representable as a signed 32-bit integer" % str(displacement))

        # Check relations of arguments
        if scale is not None and index is None or scale is None and index is not None:
            raise ValueError("Either both of neither of scale and index must be defined")
        if base is not None and index is not None and base.size != index.size:
            raise TypeError("Base (%s) and index (%s) registers have different size" % (str(base), str(index)))
        if index is None and base is None:
            raise ValueError("Either base or index * scale must be specified")

        self.base = base
        self.index = index
        self.scale = None if scale is None else int(scale)
        self.displacement = int(displacement)
コード例 #4
0
ファイル: operand.py プロジェクト: hotelzululima/PeachPy
 def __add__(self, addend):
     from peachpy.x86_64.registers import GeneralPurposeRegister64, GeneralPurposeRegister32
     from peachpy.util import is_int, is_sint32
     if is_int(addend):
         if not is_sint32(addend):
             raise ValueError("The addend value (%d) is not representable as a signed 32-bit integer" % addend)
         return MemoryAddress(self.base, self.index, self.scale, self.displacement + addend)
     elif isinstance(addend, (GeneralPurposeRegister64, GeneralPurposeRegister32)):
         if self.base is not None:
             raise TypeError("Can not add a general-purpose register to a memory operand with existing base")
         if self.index.size != addend.size:
             raise TypeError("Index (%s) and addend (%s) registers have different size" %
                             (str(self.index), str(addend)))
         return MemoryAddress(addend, self.index, self.scale, self.displacement)
     elif isinstance(addend, MemoryAddress):
         if self.base is not None and addend.base is not None:
             raise ValueError("Can not add memory address: both address expressions use base registers")
         if self.index is not None and addend.index is not None:
             raise ValueError("Can not add memory address: both address expressions use index registers")
         sum_base = self.base if self.base is not None else addend.base
         (sum_index, sum_scale) = (self.index, self.scale) \
             if self.index is not None else (addend.index, addend.scale)
         return MemoryAddress(sum_base, sum_index, sum_scale, self.displacement + addend.displacement)
     else:
         raise TypeError("Can not add %s: unsupported addend type" % str(addend))
コード例 #5
0
ファイル: operand.py プロジェクト: pombredanne/PeachPy
    def __init__(self, base=None, index=None, scale=None, displacement=0):
        from peachpy.x86_64.registers import GeneralPurposeRegister64, \
            XMMRegister, YMMRegister, ZMMRegister, MaskedRegister
        from peachpy.util import is_int, is_sint32

        # Check individual arguments
        if base is not None and not isinstance(base, GeneralPurposeRegister64):
            raise TypeError("Base register must be a 64-bit general-purpose register")
        if index is not None and \
            not isinstance(index, (GeneralPurposeRegister64, XMMRegister, YMMRegister, ZMMRegister)) and not \
            (isinstance(index, MaskedRegister) and
                isinstance(index.register, (XMMRegister, YMMRegister, ZMMRegister)) and
                not index.mask.is_zeroing):
            raise TypeError("Index register must be a 64-bit general-purpose register or an XMM/YMM/ZMM register")
        if scale is not None and not is_int(scale):
            raise TypeError("Scale must be an integer")
        if scale is not None and int(scale) not in {1, 2, 4, 8}:
            raise TypeError("Scale must be 1, 2, 4, or 8")
        if not is_sint32(displacement):
            raise ValueError("Displacement value (%s) is not representable as a signed 32-bit integer" %
                             str(displacement))

        # Check relations of arguments
        if scale is not None and index is None or scale is None and index is not None:
            raise ValueError("Either both of neither of scale and index must be defined")
        if index is None and base is None:
            raise ValueError("Either base or index * scale must be specified")

        self.base = base
        self.index = index
        self.scale = None if scale is None else int(scale)
        self.displacement = int(displacement)
コード例 #6
0
ファイル: operand.py プロジェクト: hotelzululima/PeachPy
def check_operand(operand):
    """Validates operand object as an instruction operand and converts it to a standard form"""

    from peachpy.x86_64.registers import Register, MaskedRegister
    from peachpy.x86_64.pseudo import Label
    from peachpy.x86_64.function import LocalVariable
    from peachpy.literal import Constant
    from peachpy import Argument
    from peachpy.util import is_int, is_int64
    if isinstance(operand, (Register, MaskedRegister, Constant, MemoryOperand, LocalVariable, Argument,
                            RIPRelativeOffset, Label)):
        return operand
    elif is_int(operand):
        if not is_int64(operand):
            raise ValueError("The immediate operand %d is not representable as a 64-bit value")
        return operand
    elif isinstance(operand, list):
        if len(operand) != 1:
            raise ValueError("Memory operands must be represented by a list with only one element")
        return MemoryOperand(operand[0])
    elif isinstance(operand, set):
        if len(operand) != 1:
            raise ValueError("Rounding control & suppress-all-errors operands must be represented by a set "
                             "with only one element")
        return next(iter(operand))
    else:
        raise TypeError("Unsupported operand: %s" % str(operand))
コード例 #7
0
ファイル: operand.py プロジェクト: pombredanne/PeachPy
 def __init__(self, address, size=None, mask=None, broadcast=None):
     from peachpy.x86_64.registers import GeneralPurposeRegister64, \
         XMMRegister, YMMRegister, ZMMRegister, MaskedRegister
     assert isinstance(address, (GeneralPurposeRegister64, XMMRegister, YMMRegister, ZMMRegister, MemoryAddress)) or\
         isinstance(address, MaskedRegister) and \
         isinstance(address.register, (XMMRegister, YMMRegister, ZMMRegister)) and \
         not address.mask.is_zeroing, \
         "Only MemoryAddress, 64-bit general-purpose registers, XMM/YMM/ZMM registers, " \
         "and merge-masked XMM/YMM/ZMM registers may be specified as an address"
     from peachpy.util import is_int
     assert size is None or is_int(size) and int(size) in SizeSpecification._size_name_map, \
         "Unsupported size: %d" % size
     if isinstance(address, MemoryAddress):
         if isinstance(address.index, MaskedRegister):
             self.address = MemoryAddress(address.base, address.index.register, address.scale, address.displacement)
             assert mask is None, "Mask argument can't be used when address index is a masked XMM/YMM/ZMM register"
             mask = address.index.mask
         else:
             self.address = address
     elif isinstance(address, MaskedRegister):
         self.address = MemoryAddress(index=address.register, scale=1)
         assert mask is None, "Mask argument can't be used when address is a masked XMM/YMM/ZMM register"
         mask = address.mask
     else:
         # Convert register to memory address expression
         self.address = MemoryAddress(address)
     self.size = size
     self.mask = mask
     self.broadcast = broadcast
コード例 #8
0
ファイル: registers.py プロジェクト: Rinoahu/PeachPy
 def __mul__(self, scale):
     from peachpy.x86_64.operand import MemoryAddress
     from peachpy.util import is_int
     if not is_int(scale):
         raise TypeError("Register can be scaled only by an integer number")
     if int(scale) not in {1, 2, 4, 8}:
         raise ValueError("Invalid scale value (%d): only scaling by 1, 2, 4, or 8 is supported" % scale)
     return MemoryAddress(index=self, scale=scale)
コード例 #9
0
ファイル: operand.py プロジェクト: hotelzululima/PeachPy
 def __sub__(self, minuend):
     from peachpy.util import is_int, is_sint32
     if is_int(minuend):
         if not is_sint32(-minuend):
             raise ValueError("The addend value (%d) is not representable as a signed 32-bit integer" % minuend)
         return MemoryAddress(self.base, self.index, self.scale, self.displacement - minuend)
     else:
         raise TypeError("Can not add %s: unsupported addend type" % str(minuend))
コード例 #10
0
 def __mul__(self, scale):
     from peachpy.x86_64.operand import MemoryAddress
     from peachpy.util import is_int
     if not is_int(scale):
         raise TypeError("Register can be scaled only by an integer number")
     if int(scale) not in {1, 2, 4, 8}:
         raise ValueError("Invalid scale value (%d): only scaling by 1, 2, 4, or 8 is supported" % scale)
     return MemoryAddress(index=self, scale=scale)
コード例 #11
0
 def __sub__(self, minuend):
     from peachpy.util import is_int, is_sint32
     if is_int(minuend):
         if not is_sint32(-minuend):
             raise ValueError("The addend value (%d) is not representable as a signed 32-bit integer" % minuend)
         return MemoryAddress(self.base, self.index, self.scale, self.displacement - minuend)
     else:
         raise TypeError("Can not add %s: unsupported addend type" % str(minuend))
コード例 #12
0
ファイル: literal.py プロジェクト: Rinoahu/PeachPy
 def _uint32xN(name, n, *args):
     from peachpy.util import is_int, is_int32
     assert is_int(n)
     args = [arg for arg in args if arg is not None]
     if len(args) == 0:
         raise ValueError("At least one constant value must be specified")
     if len(args) != 1 and len(args) != n:
         raise ValueError("Either 1 or %d values must be specified" % n)
     for i, number in enumerate(args):
         if not is_int(number):
             raise TypeError("The value %s is not an integer" % str(number))
         if not is_int32(number):
             raise ValueError("The number %d is not a 32-bit integer" % number)
         if number < 0:
             args[i] += 0x100000000
     if len(args) == 1:
         args = [args[0]] * n
     return Constant(4 * n, n, tuple(args), uint32_t, name)
コード例 #13
0
 def _uint32xN(name, n, *args):
     from peachpy.util import is_int, is_int32
     assert is_int(n)
     args = [arg for arg in args if arg is not None]
     if len(args) == 0:
         raise ValueError("At least one constant value must be specified")
     if len(args) != 1 and len(args) != n:
         raise ValueError("Either 1 or %d values must be specified" % n)
     for i, number in enumerate(args):
         if not is_int(number):
             raise TypeError("The value %s is not an integer" % str(number))
         if not is_int32(number):
             raise ValueError("The number %d is not a 32-bit integer" % number)
         if number < 0:
             args[i] += 0x100000000
     if len(args) == 1:
         args = [args[0]] * n
     return Constant(4 * n, n, tuple(args), uint32_t, name)
コード例 #14
0
ファイル: meta.py プロジェクト: moneytech/PeachPy
    def __init__(self, offset, type, name=None, size=None):
        from peachpy.util import is_int
        if not is_int(offset):
            raise TypeError("Offset %s is not an integer" % str(offset))
        if offset < 0:
            raise ValueError("Offset %d is negative" % offset)
        if not isinstance(type, SymbolType):
            raise TypeError("Symbol type %s is not in SymbolType enumeration" % str(type))
        if name is not None and not isinstance(name, str):
            raise TypeError("Name %s is not a string" % str(name))
        if size is not None:
            if not is_int(size):
                raise TypeError("Size %s is not an integer" % str(size))
            if size < 0:
                raise ValueError("Size %d is negative" % size)

        self.offset = offset
        self.type = type
        self.name = name
        self.size = size
コード例 #15
0
ファイル: meta.py プロジェクト: moneytech/PeachPy
    def __init__(self, offset, type, symbol=None, program_counter=None):
        from peachpy.util import is_int
        if not is_int(offset):
            raise TypeError("Offset %s is not an integer" % str(offset))
        if offset < 0:
            raise ValueError("Offset %d is negative" % offset)
        if not isinstance(type, RelocationType):
            raise TypeError("Relocation type %s is not in RelocationType enumeration" % str(type))
        if symbol is not None and not isinstance(symbol, Symbol):
            raise TypeError("Symbol %s is not an instance of Symbol type" % str(symbol))
        if program_counter is not None:
            if not is_int(program_counter):
                raise TypeError("Program counter %s is not an integer" % str(program_counter))
            if program_counter < 0:
                raise TypeError("Program counter %d is negative" % program_counter)

        self.offset = offset
        self.type = type
        self.symbol = symbol
        self.program_counter = program_counter
コード例 #16
0
ファイル: section.py プロジェクト: Rinoahu/PeachPy
 def alignment(self, alignment):
     from peachpy.util import is_int
     if not is_int(alignment):
         raise TypeError("Alignment %s is not an integer" % str(alignment))
     if alignment < 0:
         raise ValueError("Alignment %d is not a positive integer" % alignment)
     if alignment & (alignment - 1) != 0:
         raise ValueError("Alignment %d is not a power of 2" % alignment)
     if alignment not in Section._alignment_flag_map:
         raise ValueError("Alignment %d exceeds maximum alignment (8192)" % alignment)
     self.flags = (self.flags & ~Section._alignment_mask) | Section._alignment_flag_map[alignment]
コード例 #17
0
    def __init__(self, offset, type, name=None, size=None):
        from peachpy.util import is_int
        if not is_int(offset):
            raise TypeError("Offset %s is not an integer" % str(offset))
        if offset < 0:
            raise ValueError("Offset %d is negative" % offset)
        if not isinstance(type, SymbolType):
            raise TypeError("Symbol type %s is not in SymbolType enumeration" % str(type))
        from peachpy.name import Name
        if name is not None and not (isinstance(name, tuple) and all(isinstance(part, Name) for part in name)):
            raise TypeError("Name %s must be a tuple of Name objects" % str(name))
        if size is not None:
            if not is_int(size):
                raise TypeError("Size %s is not an integer" % str(size))
            if size < 0:
                raise ValueError("Size %d is negative" % size)

        self.offset = offset
        self.type = type
        self.name = ".".join(map(str, name))
        self.size = size
コード例 #18
0
ファイル: symbol.py プロジェクト: GaZ3ll3/PeachPy
 def as_bytearray(self):
     from peachpy.encoder import Encoder
     from peachpy.util import is_int
     if is_int(self.name):
         entry = Encoder.uint32le(0) + Encoder.uint32le(self.name)
     else:
         entry = Encoder.fixed_string(self.name, 8)
     return entry + \
         Encoder.uint32le(self.value) + \
         Encoder.uint16le(self.section_index) + \
         Encoder.uint16le(self.symbol_type) + \
         Encoder.uint8(self.storage_class) + \
         Encoder.uint8(self.auxiliary_entries)
コード例 #19
0
ファイル: meta.py プロジェクト: moneytech/PeachPy
 def alignment(self, alignment):
     from peachpy.util import is_int
     if not is_int(alignment):
         raise TypeError("Alignment %s is not an integer" % str(alignment))
     if alignment < 0:
         raise ValueError("Alignment %d is not a positive integer" % alignment)
     if alignment & (alignment - 1) != 0:
         raise ValueError("Alignment %d is not a power of 2" % alignment)
     if alignment > Section.max_alignment:
         raise ValueError("Alignment %d exceeds maximum alignment (%d)" % (alignment, Section.max_alignment))
     if alignment == 0:
         alignment = 1
     self._alignment = alignment
コード例 #20
0
ファイル: symbol.py プロジェクト: Rinoahu/PeachPy
    def __init__(self, type, offset, symbol):
        from peachpy.util import is_int, is_uint32
        if not isinstance(type, RelocationType):
            raise TypeError("Relocation type %s is not in RelocationType enumeration" % str(type))
        if not is_int(offset):
            raise TypeError("Offset %s is not an integer" % str(offset))
        if not is_uint32(offset):
            raise ValueError("Offset %d can not be represented as a 32-bit unsigned integer" % offset)
        if not isinstance(symbol, Symbol):
            raise TypeError("Symbol %s is not an instance of Symbol type" % str(symbol))

        self.type = type
        self.offset = offset
        self.symbol = symbol
コード例 #21
0
ファイル: section.py プロジェクト: pwaller/PeachPy
 def alignment(self, alignment):
     from peachpy.util import is_int
     if not is_int(alignment):
         raise TypeError("Alignment %s is not an integer" % str(alignment))
     if alignment < 0:
         raise ValueError("Alignment %d is not a positive integer" %
                          alignment)
     if alignment & (alignment - 1) != 0:
         raise ValueError("Alignment %d is not a power of 2" % alignment)
     if alignment not in Section._alignment_flag_map:
         raise ValueError("Alignment %d exceeds maximum alignment (8192)" %
                          alignment)
     self.flags = (self.flags & ~Section._alignment_mask
                   ) | Section._alignment_flag_map[alignment]
コード例 #22
0
ファイル: operand.py プロジェクト: GaZ3ll3/PeachPy
 def __init__(self, address, size=None):
     from peachpy.x86_64.registers import GeneralPurposeRegister64, GeneralPurposeRegister32
     assert isinstance(address, (GeneralPurposeRegister64, GeneralPurposeRegister32, MemoryAddress)),\
         "Only MemoryAddress, and 32- or 64-bit general-purpose registers may be specified as an address"
     from peachpy.util import is_int
     assert size is None or is_int(size) and \
         int(size) in SizeSpecification._size_name_map, \
         "Unsupported size: %d" % size
     if isinstance(address, MemoryAddress):
         self.address = address
     else:
         # Convert general-purpose register to memory address expression
         self.address = MemoryAddress(address)
     self.size = size
コード例 #23
0
 def __init__(self, address, size=None):
     from peachpy.x86_64.registers import GeneralPurposeRegister64, GeneralPurposeRegister32
     assert isinstance(address, (GeneralPurposeRegister64, GeneralPurposeRegister32, MemoryAddress)),\
         "Only MemoryAddress, and 32- or 64-bit general-purpose registers may be specified as an address"
     from peachpy.util import is_int
     assert size is None or is_int(size) and \
         int(size) in SizeSpecification._size_name_map, \
         "Unsupported size: %d" % size
     if isinstance(address, MemoryAddress):
         self.address = address
     else:
         # Convert general-purpose register to memory address expression
         self.address = MemoryAddress(address)
     self.size = size
コード例 #24
0
    def __init__(self, address, size=None, mask=None, broadcast=None):
        from peachpy.x86_64.registers import GeneralPurposeRegister64, \
            XMMRegister, YMMRegister, ZMMRegister, MaskedRegister
        from peachpy.x86_64.function import LocalVariable
        from peachpy.literal import Constant
        assert isinstance(address, (GeneralPurposeRegister64, XMMRegister, YMMRegister, ZMMRegister,
                                    MemoryAddress, Constant, LocalVariable, RIPRelativeOffset)) or \
            isinstance(address, MaskedRegister) and \
            isinstance(address.register, (XMMRegister, YMMRegister, ZMMRegister)) and \
            not address.mask.is_zeroing, \
            "Only MemoryAddress, 64-bit general-purpose registers, RIP-Relative addresses, XMM/YMM/ZMM registers, " \
            "and merge-masked XMM/YMM/ZMM registers may be specified as an address"
        from peachpy.util import is_int
        assert size is None or is_int(size) and int(size) in SizeSpecification._size_name_map, \
            "Unsupported size: %d" % size

        self.symbol = None
        self.size = size
        self.mask = mask
        self.broadcast = broadcast

        if isinstance(address, MemoryAddress):
            if isinstance(address.index, MaskedRegister):
                self.address = MemoryAddress(address.base,
                                             address.index.register,
                                             address.scale,
                                             address.displacement)
                assert mask is None, "Mask argument can't be used when address index is a masked XMM/YMM/ZMM register"
                self.mask = address.index.mask
            else:
                self.address = address
        elif isinstance(address, MaskedRegister):
            self.address = MemoryAddress(index=address.register, scale=1)
            assert mask is None, "Mask argument can't be used when address is a masked XMM/YMM/ZMM register"
            self.mask = address.mask
        elif isinstance(address, Constant):
            self.address = RIPRelativeOffset(0)
            self.symbol = address
            self.size = address.size
        elif isinstance(address, LocalVariable):
            from peachpy.x86_64.registers import rsp
            self.address = MemoryAddress(rsp, displacement=address.offset)
            self.symbol = address
            self.size = address.size
        elif isinstance(address, RIPRelativeOffset):
            self.address = address
        else:
            # Convert register to memory address expression
            self.address = MemoryAddress(address)
コード例 #25
0
def check_operand(operand):
    """Validates operand object as an instruction operand and converts it to a standard form"""

    from peachpy.x86_64.registers import Register, MaskedRegister
    from peachpy.x86_64.pseudo import Label
    from peachpy.x86_64.function import LocalVariable
    from peachpy.literal import Constant
    from peachpy import Argument
    from peachpy.util import is_int, is_int64
    from copy import copy, deepcopy
    if isinstance(operand, Register):
        return copy(operand)
    elif isinstance(operand, (MaskedRegister, MemoryOperand)):
        return deepcopy(operand)
    elif isinstance(operand, (Argument, RIPRelativeOffset, Label)):
        return operand
    elif is_int(operand):
        if not is_int64(operand):
            raise ValueError(
                "The immediate operand %d is not representable as a 64-bit value"
            )
        return operand
    elif isinstance(operand, list):
        if len(operand) != 1:
            raise ValueError(
                "Memory operands must be represented by a list with only one element"
            )
        return MemoryOperand(operand[0])
    elif isinstance(operand, Constant):
        from copy import copy, deepcopy
        operand = copy(operand)
        import peachpy.common.function
        if peachpy.common.function.active_function:
            operand.name = deepcopy(
                operand.name,
                peachpy.common.function.active_function._names_memo)
        return MemoryOperand(operand)
    elif isinstance(operand, LocalVariable):
        return MemoryOperand(operand)
    elif isinstance(operand, set):
        if len(operand) != 1:
            raise ValueError(
                "Rounding control & suppress-all-errors operands must be represented by a set "
                "with only one element")
        return next(iter(operand))
    else:
        raise TypeError("Unsupported operand: %s" % str(operand))
コード例 #26
0
ファイル: section.py プロジェクト: GaZ3ll3/PeachPy
    def as_bytearray(self):
        from peachpy.encoder import Encoder
        from peachpy.util import is_int

        if is_int(self.name):
            header = Encoder.fixed_string("/" + str(self.name), 8)
        else:
            header = Encoder.fixed_string(self.name, 8)
        return header + \
            Encoder.uint32le(self.memory_size) + \
            Encoder.uint32le(self.memory_address) + \
            Encoder.uint32le(self.content_size) + \
            Encoder.uint32le(self.content_offset) + \
            Encoder.uint32le(self.relocations_offset or 0) + \
            Encoder.uint32le(self.line_numbers_offset or 0) + \
            Encoder.uint16le(self.relocations_count) + \
            Encoder.uint16le(self.line_numbers_count) + \
            Encoder.uint32le(self.flags)
コード例 #27
0
ファイル: instructions.py プロジェクト: alkeldi/PeachPy
 def format(self, assembly_format, indent=False, line_number=None):
     from peachpy.x86_64.operand import format_operand
     text = "\t" * self._indent_level if indent else ""
     if assembly_format == "peachpy":
         return text + str(self)
     elif assembly_format == "nasm":
         return text + str(self)
     elif assembly_format == "gas":
         if self.operands:
             from peachpy.x86_64.pseudo import Label
             if line_number is not None and len(
                     self.operands) == 1 and isinstance(
                         self.operands[0], Label
                     ) and self.operands[0].line_number is not None:
                 label = self.operands[0]
                 return "{indent}{mnemonic} {label_line}{direction} # {label_name}".format(
                     indent=text,
                     mnemonic=self.gas_name,
                     label_line=self.operands[0].line_number,
                     label_name=str(self.operands[0]),
                     direction="b"
                     if self.operands[0].line_number < line_number else "f")
             else:
                 return text + self.gas_name + " " + ", ".join(
                     format_operand(op, assembly_format)
                     for op in reversed(self.operands))
         else:
             return text + self.gas_name
     elif assembly_format == "go":
         if self.go_name:
             from peachpy.util import is_int
             if self.name == "CMP" and is_int(self.operands[1]):
                 # CMP instruction with an immediate operand has operands in normal (non-reversed) order
                 return text + str(self.go_name) + " " + \
                        ", ".join(format_operand(op, assembly_format) for op in self.operands)
             elif self.operands:
                 return text + str(self.go_name) + " " + \
                        ", ".join(format_operand(op, assembly_format) for op in reversed(self.operands))
             else:
                 return text + str(self.go_name)
         else:
             return text + "; ".join(
                 map(lambda b: "BYTE $0x%02X" % b,
                     self.encode())) + " // " + str(self)
コード例 #28
0
ファイル: symbol.py プロジェクト: pwaller/PeachPy
    def __init__(self, type, offset, symbol):
        from peachpy.util import is_int, is_uint32
        if not isinstance(type, RelocationType):
            raise TypeError(
                "Relocation type %s is not in RelocationType enumeration" %
                str(type))
        if not is_int(offset):
            raise TypeError("Offset %s is not an integer" % str(offset))
        if not is_uint32(offset):
            raise ValueError(
                "Offset %d can not be represented as a 32-bit unsigned integer"
                % offset)
        if not isinstance(symbol, Symbol):
            raise TypeError("Symbol %s is not an instance of Symbol type" %
                            str(symbol))

        self.type = type
        self.offset = offset
        self.symbol = symbol
コード例 #29
0
 def __add__(self, addend):
     from peachpy.x86_64.registers import GeneralPurposeRegister64, GeneralPurposeRegister32
     from peachpy.util import is_int, is_sint32
     if is_int(addend):
         if not is_sint32(addend):
             raise ValueError(
                 "The addend value (%d) is not representable as a signed 32-bit integer"
                 % addend)
         return MemoryAddress(self.base, self.index, self.scale,
                              self.displacement + addend)
     elif isinstance(addend,
                     (GeneralPurposeRegister64, GeneralPurposeRegister32)):
         if self.base is not None:
             raise TypeError(
                 "Can not add a general-purpose register to a memory operand with existing base"
             )
         if self.index.size != addend.size:
             raise TypeError(
                 "Index (%s) and addend (%s) registers have different size"
                 % (str(self.index), str(addend)))
         return MemoryAddress(addend, self.index, self.scale,
                              self.displacement)
     elif isinstance(addend, MemoryAddress):
         if self.base is not None and addend.base is not None:
             raise ValueError(
                 "Can not add memory address: both address expressions use base registers"
             )
         if self.index is not None and addend.index is not None:
             raise ValueError(
                 "Can not add memory address: both address expressions use index registers"
             )
         sum_base = self.base if self.base is not None else addend.base
         (sum_index, sum_scale) = (self.index, self.scale) \
             if self.index is not None else (addend.index, addend.scale)
         return MemoryAddress(sum_base, sum_index, sum_scale,
                              self.displacement + addend.displacement)
     else:
         raise TypeError("Can not add %s: unsupported addend type" %
                         str(addend))
コード例 #30
0
    def __init__(self, base=None, index=None, scale=None, displacement=0):
        from peachpy.x86_64.registers import GeneralPurposeRegister64, GeneralPurposeRegister32
        from peachpy.util import is_int, is_sint32

        # Check individual arguments
        if base is not None and not isinstance(
                base, (GeneralPurposeRegister32, GeneralPurposeRegister64)):
            raise TypeError(
                "Base register must be a 32- or 64-bit general-purpose register"
            )
        if index is not None and not isinstance(
                index, (GeneralPurposeRegister32, GeneralPurposeRegister64)):
            raise TypeError(
                "Index register must be a 32- or 64-bit general-purpose register"
            )
        if scale is not None and not is_int(scale):
            raise TypeError("Scale must be an integer")
        if scale is not None and int(scale) not in {1, 2, 4, 8}:
            raise TypeError("Scale must be 1, 2, 4, or 8")
        if not is_sint32(displacement):
            raise ValueError(
                "Displacement value (%s) is not representable as a signed 32-bit integer"
                % str(displacement))

        # Check relations of arguments
        if scale is not None and index is None or scale is None and index is not None:
            raise ValueError(
                "Either both of neither of scale and index must be defined")
        if base is not None and index is not None and base.size != index.size:
            raise TypeError(
                "Base (%s) and index (%s) registers have different size" %
                (str(base), str(index)))
        if index is None and base is None:
            raise ValueError("Either base or index * scale must be specified")

        self.base = base
        self.index = index
        self.scale = None if scale is None else int(scale)
        self.displacement = int(displacement)
コード例 #31
0
ファイル: instructions.py プロジェクト: staugust/PeachPy
 def format(self, assembly_format, indent):
     from peachpy.x86_64.operand import format_operand
     text = "\t" * self._indent_level if indent else ""
     if assembly_format == "peachpy":
         return text + str(self)
     elif assembly_format == "nasm":
         return text + str(self)
     elif assembly_format == "gas":
         return text + str(self)
     elif assembly_format == "go":
         if self.go_name:
             from peachpy.util import is_int
             if self.name == "CMP" and is_int(self.operands[1]):
                 # CMP instruction with an immediate operand has operands in normal (non-reversed) order
                 return text + str(self.go_name) + " " + \
                        ", ".join(format_operand(op, assembly_format) for op in self.operands)
             elif self.operands:
                 return text + str(self.go_name) + " " + \
                        ", ".join(format_operand(op, assembly_format) for op in reversed(self.operands))
             else:
                 return text + str(self.go_name)
         else:
             return text + "; ".join(map(lambda b: "BYTE $0x%02X" % b, self.encode())) + " // " + str(self)
コード例 #32
0
    def __init__(self, base=None, index=None, scale=None, displacement=0):
        from peachpy.x86_64.registers import GeneralPurposeRegister64, \
            XMMRegister, YMMRegister, ZMMRegister, MaskedRegister
        from peachpy.util import is_int, is_sint32

        # Check individual arguments
        if base is not None and not isinstance(base, GeneralPurposeRegister64):
            raise TypeError(
                "Base register must be a 64-bit general-purpose register")
        if index is not None and \
            not isinstance(index, (GeneralPurposeRegister64, XMMRegister, YMMRegister, ZMMRegister)) and not \
            (isinstance(index, MaskedRegister) and
                isinstance(index.register, (XMMRegister, YMMRegister, ZMMRegister)) and
                not index.mask.is_zeroing):
            raise TypeError(
                "Index register must be a 64-bit general-purpose register or an XMM/YMM/ZMM register"
            )
        if scale is not None and not is_int(scale):
            raise TypeError("Scale must be an integer")
        if scale is not None and int(scale) not in {1, 2, 4, 8}:
            raise TypeError("Scale must be 1, 2, 4, or 8")
        if not is_sint32(displacement):
            raise ValueError(
                "Displacement value (%s) is not representable as a signed 32-bit integer"
                % str(displacement))

        # Check relations of arguments
        if scale is not None and index is None or scale is None and index is not None:
            raise ValueError(
                "Either both of neither of scale and index must be defined")
        if index is None and base is None:
            raise ValueError("Either base or index * scale must be specified")

        self.base = base
        self.index = index
        self.scale = None if scale is None else int(scale)
        self.displacement = int(displacement)
コード例 #33
0
    def __init__(self, code_size, data_size=0):
        from peachpy.util import is_int
        if not is_int(code_size):
            raise TypeError("code size must be an integer")
        if not is_int(data_size):
            raise TypeError("data size must be an integer")
        if code_size <= 0:
            raise ValueError("code size must be positive")
        if data_size < 0:
            raise ValueError("data size must be non-negative")

        import mmap
        self.allocation_granularity = max(mmap.ALLOCATIONGRANULARITY, mmap.PAGESIZE)
        self.code_address = None
        self.code_size = self.allocation_size(code_size)
        self.data_address = None
        self.data_size = self.allocation_size(data_size)

        self._release_memory = None

        osname = sys.platform.lower()
        if osname == "darwin" or osname.startswith("linux"):
            import ctypes

            if osname == "darwin":
                libc = ctypes.cdll.LoadLibrary("libc.dylib")
            else:
                libc = ctypes.cdll.LoadLibrary("libc.so.6")

            # void* mmap(void* addr, size_t len, int prot, int flags, int fd, off_t offset)
            mmap_function = libc.mmap
            mmap_function.restype = ctypes.c_void_p
            mmap_function.argtype = [ctypes.c_void_p, ctypes.c_size_t,
                             ctypes.c_int, ctypes.c_int,
                             ctypes.c_int, ctypes.c_size_t]
            # int munmap(void* addr, size_t len)
            munmap_function = libc.munmap
            munmap_function.restype = ctypes.c_int
            munmap_function.argtype = [ctypes.c_void_p, ctypes.c_size_t]

            def munmap(address, size):
                munmap_result = munmap_function(address, size)
                assert munmap_result == 0

            self._release_memory = lambda address_size: munmap(address_size[0], address_size[1])

            # Allocate code segment
            code_address = mmap_function(None, self.code_size,
                                         mmap.PROT_READ | mmap.PROT_WRITE | mmap.PROT_EXEC,
                                         mmap.MAP_ANON | mmap.MAP_PRIVATE,
                                         -1, 0)
            if code_address == -1:
                raise OSError("Failed to allocate memory for code segment")
            self.code_address = code_address

            if self.data_size > 0:
                # Allocate data segment
                data_address = mmap_function(None, self.data_size,
                                             mmap.PROT_READ | mmap.PROT_WRITE,
                                             mmap.MAP_ANON | mmap.MAP_PRIVATE,
                                             -1, 0)
                if data_address == -1:
                    raise OSError("Failed to allocate memory for data segment")
                self.data_address = data_address
        elif osname == "win32":
            import ctypes

            # From WinNT.h
            PAGE_READWRITE = 0x04
            PAGE_EXECUTE_READWRITE = 0x40
            MEM_COMMIT = 0x1000
            MEM_RESERVE = 0x2000
            MEM_RELEASE = 0x8000

            # LPVOID WINAPI VirtualAlloc(LPVOID address, SIZE_T size, DWORD allocationType, DWORD protect)
            VirtualAlloc_function = ctypes.windll.kernel32.VirtualAlloc
            VirtualAlloc_function.restype = ctypes.c_void_p
            VirtualAlloc_function.argtype = [ctypes.c_void_p, ctypes.c_size_t, ctypes.c_ulong, ctypes.c_ulong]
            # BOOL WINAPI VirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD  dwFreeType)
            VirtualFree_function = ctypes.windll.kernel32.VirtualFree
            VirtualFree_function.restype = ctypes.c_int
            VirtualFree_function.argtype = [ctypes.c_void_p, ctypes.c_size_t, ctypes.c_ulong]

            def VirtualFree(address, size):
                VirtualFree_result = VirtualFree_function(address, size, MEM_RELEASE)
                assert VirtualFree_result != 0

            self._release_memory = lambda address_size: VirtualFree(address_size[0], address_size[1])

            # Allocate code segment
            code_address = VirtualAlloc_function(None, self.code_size,
                                                 MEM_RESERVE | MEM_COMMIT,
                                                 PAGE_EXECUTE_READWRITE)
            if not code_address:
                raise OSError("Failed to allocate memory for code segment")
            self.code_address = code_address

            if self.data_size > 0:
                # Allocate data segment
                data_address = VirtualAlloc_function(None, self.data_size,
                                                     MEM_RESERVE | MEM_COMMIT,
                                                     PAGE_READWRITE)
                if not data_address:
                    raise OSError("Failed to allocate memory for data segment")
                self.data_address = data_address
        elif osname == "nacl":
            import dynacl

            # Allocate code segment
            self.allocation = dynacl.allocate(self.code_size, self.data_size)
            self.code_address = self.allocation.code_address
            self.data_address = self.allocation.data_address
            self.copy_code = self._nacl_copy_code
        else:
            raise ValueError("Unknown host OS: " + osname)
コード例 #34
0
 def __init__(self, size):
     from peachpy.util import is_int
     assert is_int(size) and int(size) in SizeSpecification._size_name_map, \
         "Unsupported size: %d" % size
     self.size = size
コード例 #35
0
    def __init__(self, operand):
        super(Operand, self).__init__()
        import copy
        from peachpy import Constant
        from peachpy.arm.registers import Register, GeneralPurposeRegister, \
            GeneralPurposeRegisterWriteback, ShiftedGeneralPurposeRegister, DRegisterLanes
        from peachpy.arm.function import LocalVariable
        from peachpy.arm.pseudo import Label
        from peachpy.util import is_int

        if isinstance(operand, GeneralPurposeRegisterWriteback):
            self.type = Operand.AddressRegisterType
            self.register = copy.deepcopy(operand.register)
        elif isinstance(operand, Register):
            self.type = Operand.RegisterType
            self.register = copy.deepcopy(operand)
        elif isinstance(operand, DRegisterLanes):
            self.type = Operand.RegisterLanesType
            self.lanes = copy.deepcopy(operand)
        elif isinstance(operand, ShiftedGeneralPurposeRegister):
            self.type = Operand.ShiftedRegisterType
            self.register = copy.deepcopy(operand)
        elif isinstance(operand, tuple):
            if all(isinstance(element, Register) for element in operand):
                if len(
                        set((register.type, register.size)
                            for register in operand)) == 1:
                    self.type = Operand.RegisterListType
                    self.register_list = copy.deepcopy(operand)
                else:
                    raise TypeError(
                        'Register in the list {0} have different types'.format(
                            ", ".join(operand)))
            elif all(
                    isinstance(element, DRegisterLanes)
                    for element in operand):
                self.type = Operand.RegisterLanesListType
                self.register_list = copy.deepcopy(operand)
            else:
                raise TypeError('Unknown tuple elements {0}'.format(operand))
        elif is_int(operand):
            if -9223372036854775808 <= operand <= 18446744073709551615:
                self.type = Operand.ImmediateType
                self.immediate = operand
            else:
                raise ValueError(
                    'The immediate operand {0} is not a 64-bit value'.format(
                        operand))
        elif isinstance(operand, list):
            if len(operand) == 1 and (isinstance(
                    operand[0], GeneralPurposeRegister) or isinstance(
                        operand[0], GeneralPurposeRegisterWriteback)):
                self.type = Operand.MemoryType
                self.base = copy.deepcopy(operand[0])
                self.offset = None
            elif len(operand) == 2 and isinstance(
                    operand[0], GeneralPurposeRegister) and (isinstance(
                        operand[1], int) or isinstance(
                            operand[1], ShiftedGeneralPurposeRegister)):
                self.type = Operand.MemoryType
                self.base = copy.deepcopy(operand[0])
                self.offset = operand[1]
            else:
                raise ValueError(
                    'Memory operand must be a list with only one or two elements'
                )
        elif isinstance(operand, Constant):
            self.type = Operand.ConstantType
            self.constant = operand
            self.size = operand.size * operand.repeats
        elif isinstance(operand, LocalVariable):
            self.type = Operand.VariableType
            self.variable = operand
            self.size = operand.size * 8
        elif isinstance(operand, str):
            self.type = Operand.LabelType
            self.label = operand
        elif isinstance(operand, Label):
            self.type = Operand.LabelType
            self.label = operand.name
        elif operand is None:
            self.type = Operand.NoneType
        else:
            raise TypeError(
                'The operand {0} is not a valid assembly instruction operand'.
                format(operand))
コード例 #36
0
ファイル: encoding.py プロジェクト: pombredanne/PeachPy
def modrm_sib_disp(reg, rm, force_sib=False, min_disp=0, disp8xN=None):
    from peachpy.x86_64.operand import MemoryAddress
    from peachpy.x86_64.registers import rsp, rbp, r12, r13
    from peachpy.util import is_int, is_sint8, ilog2

    assert is_int(reg) and 0 <= reg <= 7, \
        "Constant reg value expected, got " + str(reg)
    assert isinstance(rm, (MemoryAddress, int))

    if disp8xN is None:
        disp8xN = 1
    assert disp8xN in [1, 2, 4, 8, 16, 32, 64]

    #                    ModR/M byte
    # +----------------+---------------+--------------+
    # | Bits 6-7: mode | Bits 3-5: reg | Bits 0-2: rm |
    # +----------------+---------------+--------------+
    #
    #                         SIB byte
    # +-----------------+-----------------+----------------+
    # | Bits 6-7: scale | Bits 3-5: index | Bits 0-2: base |
    # +-----------------+-----------------+----------------+
    if isinstance(rm, MemoryAddress):
        # TODO: support global addresses, including rip-relative addresses
        assert rm.base is not None or rm.index is not None, \
            "Global addressing is not yet supported"
        if not force_sib and rm.index is None and rm.base.lcode != 0b100:
            # No SIB byte
            if rm.displacement == 0 and rm.base != rbp and rm.base != r13 and min_disp <= 0:
                # ModRM.mode = 0 (no displacement)

                assert rm.base.lcode != 0b100, \
                    "rsp/r12 are not encodable as a base register (interpreted as SIB indicator)"
                assert rm.base.lcode != 0b101, \
                    "rbp/r13 is not encodable as a base register (interpreted as disp32 address)"
                return bytearray([(reg << 3) | rm.base.lcode])
            elif (rm.displacement % disp8xN == 0) and is_sint8(rm.displacement // disp8xN) and min_disp <= 1:
                # ModRM.mode = 1 (8-bit displacement)

                assert rm.base.lcode != 0b100, \
                    "rsp/r12 are not encodable as a base register (interpreted as SIB indicator)"
                return bytearray([0x40 | (reg << 3) | rm.base.lcode, (rm.displacement // disp8xN) & 0xFF])
            else:
                # ModRM.mode == 2 (32-bit displacement)

                assert rm.base.lcode != 0b100, \
                    "rsp/r12 are not encodable as a base register (interpreted as SIB indicator)"
                return bytearray([0x80 | (reg << 3) | rm.base.lcode,
                                 rm.displacement & 0xFF, (rm.displacement >> 8) & 0xFF,
                                 (rm.displacement >> 16) & 0xFF, (rm.displacement >> 24) & 0xFF])
        else:
            # All encodings below use ModRM.rm = 4 (0b100) to indicate the presence of SIB

            assert rsp != rm.index, "rsp is not encodable as an index register (interpreted as no index)"
            # Index = 4 (0b100) denotes no-index encoding
            index = 0x4 if rm.index is None else rm.index.lcode
            scale = 0 if rm.scale is None else ilog2(rm.scale)
            if rm.base is None:
                # SIB.base = 5 (0b101) and ModRM.mode = 0 indicates no-base encoding with disp32

                return bytearray([(reg << 3) | 0x4, (scale << 6) | (index << 3) | 0x5,
                                 rm.displacement & 0xFF, (rm.displacement >> 8) & 0xFF,
                                 (rm.displacement >> 16) & 0xFF, (rm.displacement >> 24) & 0xFF])
            else:
                if rm.displacement == 0 and rm.base.lcode != 0b101 and min_disp <= 0:
                    # ModRM.mode == 0 (no displacement)

                    assert rm.base.lcode != 0b101, \
                        "rbp/r13 is not encodable as a base register (interpreted as disp32 address)"
                    return bytearray([(reg << 3) | 0x4, (scale << 6) | (index << 3) | rm.base.lcode])
                elif (rm.displacement % disp8xN == 0) and is_sint8(rm.displacement // disp8xN) and min_disp <= 1:
                    # ModRM.mode == 1 (8-bit displacement)

                    return bytearray([(reg << 3) | 0x44, (scale << 6) | (index << 3) | rm.base.lcode,
                                      (rm.displacement // disp8xN) & 0xFF])
                else:
                    # ModRM.mode == 2 (32-bit displacement)

                    return bytearray([(reg << 3) | 0x84, (scale << 6) | (index << 3) | rm.base.lcode,
                                     rm.displacement & 0xFF, (rm.displacement >> 8) & 0xFF,
                                     (rm.displacement >> 16) & 0xFF, (rm.displacement >> 24) & 0xFF])
    else:
        # ModRM.mode == 0 and ModeRM.rm == 5 (0b101) indicates (rip + disp32) addressing
        return bytearray([0b00000101 | (reg << 3), rm & 0xFF, (rm >> 8) & 0xFF, (rm >> 16) & 0xFF, (rm >> 24) & 0xFF])
コード例 #37
0
ファイル: operand.py プロジェクト: hotelzululima/PeachPy
 def __init__(self, size):
     from peachpy.util import is_int
     assert is_int(size) and int(size) in SizeSpecification._size_name_map, \
         "Unsupported size: %d" % size
     self.size = size
コード例 #38
0
def modrm_sib_disp(reg, rm, force_sib=False, min_disp=0):
    from peachpy.x86_64.operand import MemoryAddress
    from peachpy.x86_64.registers import rsp, rbp, r12, r13
    from peachpy.util import is_int, is_sint8, ilog2

    assert is_int(reg) and 0 <= reg <= 7, \
        "Constant reg value expected, got " + str(reg)
    assert isinstance(rm, MemoryAddress)

    # TODO: support global addresses, including rip-relative addresses
    assert rm.base is not None or rm.index is not None, \
        "Global addressing is not yet supported"

    #                    ModR/M byte
    # +----------------+---------------+--------------+
    # | Bits 6-7: mode | Bits 3-5: reg | Bits 0-2: rm |
    # +----------------+---------------+--------------+
    #
    #                         SIB byte
    # +-----------------+-----------------+----------------+
    # | Bits 6-7: scale | Bits 3-5: index | Bits 0-2: base |
    # +-----------------+-----------------+----------------+
    if not force_sib and rm.index is None and rm.base.lcode != 0b100:
        # No SIB byte
        if rm.displacement == 0 and rm.base != rbp and rm.base != r13 and min_disp <= 0:
            # ModRM.mode = 0 (no displacement)

            assert rm.base.lcode != 0b100, "rsp/r12 are not encodable as a base register (interpreted as SIB indicator)"
            assert rm.base.lcode != 0b101, "rbp/r13 is not encodable as a base register (interpreted as disp32 address)"
            return bytearray([(reg << 3) | rm.base.lcode])
        elif is_sint8(rm.displacement) and min_disp <= 1:
            # ModRM.mode = 1 (8-bit displacement)

            assert rm.base.lcode != 0b100, "rsp/r12 are not encodable as a base register (interpreted as SIB indicator)"
            return bytearray(
                [0x40 | (reg << 3) | rm.base.lcode, rm.displacement & 0xFF])
        else:
            # ModRM.mode == 2 (32-bit displacement)

            assert rm.base.lcode != 0b100, "rsp/r12 are not encodable as a base register (interpreted as SIB indicator)"
            return bytearray([
                0x80 | (reg << 3) | rm.base.lcode, rm.displacement & 0xFF,
                (rm.displacement >> 8) & 0xFF, (rm.displacement >> 16) & 0xFF,
                (rm.displacement >> 24) & 0xFF
            ])
    else:
        # All encodings below use ModRM.rm = 4 (0b100) to indicate the presence of SIB

        assert rsp != rm.index, "rsp is not encodable as an index register (interpreted as no index)"
        # Index = 4 (0b100) denotes no-index encoding
        index = 0x4 if rm.index is None else rm.index.lcode
        scale = 0 if rm.scale is None else ilog2(rm.scale)
        if rm.base is None:
            # SIB.base = 5 (0b101) and ModRM.mode = 0 indicates no-base encoding with disp32

            return bytearray([(reg << 3) | 0x4,
                              (scale << 6) | (index << 3) | 0x5,
                              rm.displacement & 0xFF,
                              (rm.displacement >> 8) & 0xFF,
                              (rm.displacement >> 16) & 0xFF,
                              (rm.displacement >> 24) & 0xFF])
        else:
            if rm.displacement == 0 and rm.base.lcode != 0b101 and min_disp <= 0:
                # ModRM.mode == 0 (no displacement)

                assert rm.base.lcode != 0b101, \
                    "rbp/r13 is not encodable as a base register (interpreted as disp32 address)"
                return bytearray([(reg << 3) | 0x4,
                                  (scale << 6) | (index << 3) | rm.base.lcode])
            elif is_sint8(rm.displacement) and min_disp <= 1:
                # ModRM.mode == 1 (8-bit displacement)

                return bytearray([(reg << 3) | 0x44,
                                  (scale << 6) | (index << 3) | rm.base.lcode,
                                  rm.displacement & 0xFF])
            else:
                # ModRM.mode == 2 (32-bit displacement)

                return bytearray([(reg << 3) | 0x84,
                                  (scale << 6) | (index << 3) | rm.base.lcode,
                                  rm.displacement & 0xFF,
                                  (rm.displacement >> 8) & 0xFF,
                                  (rm.displacement >> 16) & 0xFF,
                                  (rm.displacement >> 24) & 0xFF])
コード例 #39
0
ファイル: loader.py プロジェクト: Rinoahu/PeachPy
    def __init__(self, code_size, data_size=0):
        from peachpy.util import is_int
        if not is_int(code_size):
            raise TypeError("code size must be an integer")
        if not is_int(data_size):
            raise TypeError("data size must be an integer")
        if code_size <= 0:
            raise ValueError("code size must be positive")
        if data_size < 0:
            raise ValueError("data size must be non-negative")

        import mmap
        self.allocation_granularity = max(mmap.ALLOCATIONGRANULARITY, mmap.PAGESIZE)
        self.code_address = None
        self.code_size = self.allocation_size(code_size)
        self.data_address = None
        self.data_size = self.allocation_size(data_size)

        self._release_memory = None

        osname = sys.platform.lower()
        if osname == "darwin" or osname.startswith("linux"):
            import ctypes

            if osname == "darwin":
                libc = ctypes.cdll.LoadLibrary("libc.dylib")
            else:
                libc = ctypes.cdll.LoadLibrary("libc.so.6")

            # void* mmap(void* addr, size_t len, int prot, int flags, int fd, off_t offset)
            mmap_function = libc.mmap
            mmap_function.restype = ctypes.c_void_p
            mmap_function.argtype = [ctypes.c_void_p, ctypes.c_size_t,
                             ctypes.c_int, ctypes.c_int,
                             ctypes.c_int, ctypes.c_size_t]
            # int munmap(void* addr, size_t len)
            munmap_function = libc.munmap
            munmap_function.restype = ctypes.c_int
            munmap_function.argtype = [ctypes.c_void_p, ctypes.c_size_t]

            def munmap(address, size):
                munmap_result = munmap_function(ctypes.c_void_p(address), size)
                assert munmap_result == 0

            self._release_memory = lambda address_size: munmap(address_size[0], address_size[1])

            # Allocate code segment
            code_address = mmap_function(None, self.code_size,
                                         mmap.PROT_READ | mmap.PROT_WRITE | mmap.PROT_EXEC,
                                         mmap.MAP_ANON | mmap.MAP_PRIVATE,
                                         -1, 0)
            if code_address == -1:
                raise OSError("Failed to allocate memory for code segment")
            self.code_address = code_address

            if self.data_size > 0:
                # Allocate data segment
                data_address = mmap_function(None, self.data_size,
                                             mmap.PROT_READ | mmap.PROT_WRITE,
                                             mmap.MAP_ANON | mmap.MAP_PRIVATE,
                                             -1, 0)
                if data_address == -1:
                    raise OSError("Failed to allocate memory for data segment")
                self.data_address = data_address
        elif osname == "win32":
            import ctypes

            # From WinNT.h
            PAGE_READWRITE = 0x04
            PAGE_EXECUTE_READWRITE = 0x40
            MEM_COMMIT = 0x1000
            MEM_RESERVE = 0x2000
            MEM_RELEASE = 0x8000

            # LPVOID WINAPI VirtualAlloc(LPVOID address, SIZE_T size, DWORD allocationType, DWORD protect)
            VirtualAlloc_function = ctypes.windll.kernel32.VirtualAlloc
            VirtualAlloc_function.restype = ctypes.c_void_p
            VirtualAlloc_function.argtype = [ctypes.c_void_p, ctypes.c_size_t, ctypes.c_ulong, ctypes.c_ulong]
            # BOOL WINAPI VirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD  dwFreeType)
            VirtualFree_function = ctypes.windll.kernel32.VirtualFree
            VirtualFree_function.restype = ctypes.c_int
            VirtualFree_function.argtype = [ctypes.c_void_p, ctypes.c_size_t, ctypes.c_ulong]

            def VirtualFree(address, size):
                VirtualFree_result = VirtualFree_function(address, size, MEM_RELEASE)
                assert VirtualFree_result != 0

            self._release_memory = lambda address_size: VirtualFree(address_size[0], address_size[1])

            # Allocate code segment
            code_address = VirtualAlloc_function(None, self.code_size,
                                                 MEM_RESERVE | MEM_COMMIT,
                                                 PAGE_EXECUTE_READWRITE)
            if not code_address:
                raise OSError("Failed to allocate memory for code segment")
            self.code_address = code_address

            if self.data_size > 0:
                # Allocate data segment
                data_address = VirtualAlloc_function(None, self.data_size,
                                                     MEM_RESERVE | MEM_COMMIT,
                                                     PAGE_READWRITE)
                if not data_address:
                    raise OSError("Failed to allocate memory for data segment")
                self.data_address = data_address
        elif osname == "nacl":
            import dynacl

            # Allocate code segment
            self.allocation = dynacl.allocate(self.code_size, self.data_size)
            self.code_address = self.allocation.code_address
            self.data_address = self.allocation.data_address
            self.copy_code = self._nacl_copy_code
        else:
            raise ValueError("Unknown host OS: " + osname)