def test_decoder_020(): c = b'\x68\x01\x02\x03\xff' i = cpu.disassemble(c) assert i.mnemonic == 'PUSH' assert i.operands[0].size == 32 assert i.operands[0] == 0xff030201 c = b'\x48\x68\x01\x02\x03\xff' i = cpu.disassemble(c) assert i.mnemonic == 'PUSH' assert i.operands[0].size == 64 assert i.operands[0] == 0xffffffffff030201
def test_mapper_000(): # create two instructions # movq %rcx, (%rip) # movq (%rip), %rcx i0 = cpu.disassemble(b"\x48\x89\x0d\x00\x00\x00\x00") i1 = cpu.disassemble(b"\x48\x8b\x0d\x00\x00\x00\x00") # modify the first instruction to insert a label, e.g. because # there is a relocation # movq %rcx, foo(%rip) i0.operands[0].a.disp = expressions.lab('foo', size=64) # evaluate those two instructions m = mapper() i0(m) i1(m) assert str(m[rcx]) == 'M64(rip+14)'
def test_decoder_019(): c = b'\xff\x35\x00\x00\x00\x00' i = cpu.disassemble(c) assert i.mnemonic == 'PUSH' assert i.operands[0].size == 64 assert i.operands[0].a.base == rip assert i.operands[0].a.disp == 0
def test_decoder_012(): c = codecs.decode('488b0d19000000', 'hex') i = cpu.disassemble(c) assert i.mnemonic == 'MOV' assert i.operands[0].ref == 'rcx' assert i.operands[1].a.base == rip assert i.operands[1].a.disp == 0x19
def test_decoder_013(): c = codecs.decode('8b5c240c', 'hex') i = cpu.disassemble(c) assert i.mnemonic == 'MOV' assert i.operands[0].ref == 'ebx' assert i.operands[1].size == 32 assert i.operands[1].a.base == rsp assert i.operands[1].a.disp == 0xc
def test_decoder_029(): i = cpu.disassemble(b'\x3e\xff\x34\x25\xd2\x04\x00\x00') assert i.mnemonic == 'PUSH' assert i.operands[0].size == 64 assert i.operands[0].a.base == 0x4d2 assert i.operands[0].a.disp == 0 assert i.operands[0].a.seg.ref == 'ds' assert str(i) == 'push qword ptr ds:[0x4d2]'
def test_decoder_025(): c = codecs.decode('4c69f1020000f0', 'hex') i = cpu.disassemble(c) assert i.mnemonic == 'IMUL' assert i.operands[0].ref == 'r14' assert i.operands[1].ref == 'rcx' assert i.operands[2].size == 64 assert i.operands[2] == cpu.cst(0xf0000002, 32).signextend(64)
def test_decoder_026(): c = b'\x66\x41\xc7\x84\x55\x11\x11\x11\x11\x22\x22' i = cpu.disassemble(c) assert i.mnemonic == 'MOV' assert i.operands[0]._is_mem assert i.operands[0].size == 16 assert i.operands[0].a.base == cpu.r13 + (cpu.rdx * 2) assert i.operands[0].a.disp == 0x11111111 assert i.operands[1] == cpu.cst(0x2222, 16)
def test_mapper_001(): # create three instructions # movq %rax, (%rip) # movl %eax, (%rip) # movq -16(%rbp), %rcx i0 = cpu.disassemble(b"\x48\x89\x05\x00\x00\x00\x00") i1 = cpu.disassemble(b"\x89\x05\x00\x00\x00\x00") i2 = cpu.disassemble(b"\x48\x8b\x4d\xf0") # modify the first two instructions to insert a label # movq %rax, foo(%rip) i0.operands[0].a.disp = expressions.lab('foo', size=64) # movb %eax, bar(%rip) i1.operands[0].a.disp = expressions.lab('bar', size=64) # evaluate those three instructions m = mapper() i0(m) i1(m) i2(m) assert str(m[rcx]) == 'M64(rbp-16)'
def from_bin(self, in_str, section): ''' binary input, in assembly format ''' self.section = section self.offset = in_str.offset from plasmasm.parse_bin import endofsection_address end_of_section = endofsection_address(self.symbols, section) end_of_instr = in_str.offset + cpu_amoco.disassemble.maxlen if end_of_instr > end_of_section: end_of_instr = end_of_section instr = cpu_amoco.disassemble(in_str[self.offset:end_of_instr]) log.debug("> %s", instr) if instr is None: instr = StubNone(self.offset, in_str[self.offset:self.offset + 1]) self.bytelen = instr.length in_str.offset = self.offset + self.bytelen self.amoco = instr return self
def test_decoder_005(): c = b'\x8b\x2c\x25\x00\x00\x00\x00' i = cpu.disassemble(c) assert i.operands[1].a.base == 0
def test_decoder_004(): c = b'\x64\x48\x8b\x04\x25\x28\0\0\0' i = cpu.disassemble(c) assert i.operands[1].a.base == 40
def test_decoder_003(): c = b'\x48\x8b\x04\xc5\0\0\0\0' i = cpu.disassemble(c) assert i.operands[1].a.base == (rax * 8)
def test_decoder_002(): c = b'\x48\x0f\xbe\xc0' i = cpu.disassemble(c) assert i.mnemonic == 'MOVSX' assert i.operands[0].ref == 'rax' assert i.operands[1].ref == 'al'
def test_decoder_028(): i = cpu.disassemble(b'f\x0f\x16\x15\x0c\x00\x00\x00') assert i.mnemonic == 'MOVHPD' assert i.operands[0].ref == 'xmm2' assert i.operands[1].size == 64
def test_decoder_015(): c = b'\x48\x63\xd2' i = cpu.disassemble(c) assert i.mnemonic == 'MOVSXD'
def test_decoder_016(): c = b'\x86\xf1' i = cpu.disassemble(c) assert i.mnemonic == 'XCHG' assert i.operands[0].ref == 'dh' assert i.operands[1].ref == 'cl'
def test_decoder_009(): c = b'\xf3\x0f\x2a\xc0' i = cpu.disassemble(c) assert i.mnemonic == 'CVTSI2SS' assert i.operands[1].ref == 'eax'
def test_decoder_001(): c = b'f\x0fo\x04%\xbc\x00`\x00' i = cpu.disassemble(c) assert i.mnemonic == 'MOVDQA' assert i.operands[0].ref == 'xmm0' assert i.operands[1].a.base == 0x6000bc
def test_decoder_021(): c = b'\x66\x68\x03\xff' i = cpu.disassemble(c) assert i.mnemonic == 'PUSH' assert i.operands[0].size == 16 assert i.operands[0] == 0xff03
def apply_reloc(self, pos, reloc): ''' 'reloc' is a relocation at offset 'pos' This function modifies the argument impacted by the relocation ''' # Step 1: find which arg is impacted pos -= self.offset b, = struct.unpack("B", self.amoco.bytes[pos:pos + 1]) b = struct.pack("B", (1 + b) % 256) o = cpu_amoco.disassemble(self.amoco.bytes) patched = self.amoco.bytes[:pos] + b + self.amoco.bytes[pos + 1:] p = cpu_amoco.disassemble(patched) if o is None or p is None or o.mnemonic != p.mnemonic: log.error("Relocation changes instruction! %s => %s", o, p) log.error(" at offset %r with reloc %r", pos, reloc) log.error(" for '%s' at %s, address=%s", self, self.section, self.offset) return # To find if an argument has changed, we compute the difference # and test if it is non-zero argpos = None for idx, (oa, na) in enumerate(zip(o.operands, p.operands)): try: d = na - oa except ValueError: log.error("Invalid relocation effect") log.error(" incompatible sizes %s %s", na, oa) log.error(" reloc %r for '%s'", reloc, self) return if d._is_cst and int(d) == 0: # Not changed continue if argpos is not None: log.error("Relocation touches many arguments") log.error(" reloc %r for '%s'", reloc, self) return argpos = idx if argpos is None: log.error("Relocation touches no argument") log.error(" reloc %r for '%s'", reloc, self) log.error("ARGPOS %s", argpos) return # Step 2: modify the argument by using the reloc data address = None # TODO SWITCH label_for_optimised_switch(self) if self.amoco.operands[argpos]._is_cst: offset = int(self.amoco.operands[argpos]) if offset >= (1 << (cpu_addrsize - 1)): offset -= 1 << cpu_addrsize # Signed self.amoco.operands[argpos] -= offset elif self.amoco.operands[argpos]._is_mem: base = self.amoco.operands[argpos].a.base if base._is_cst: offset = int(base) self.amoco.operands[argpos].a.base -= offset else: if base._is_eqn and base.op.symbol == '+': pass # We may want to extract the constant from an operation # (reg+imm), but normally it is stored as (base+disp) offset = self.amoco.operands[argpos].a.disp self.amoco.operands[argpos].a.disp -= offset else: log.error("Arg of type %s", self.amoco.operands[argpos].__class__) return if address is None: from plasmasm.get_symbols import analyze_reloc label, label_dif, offset, size = analyze_reloc( self, reloc, offset, pos, self.bytelen) r_type, data = reloc from elfesteem import elf if r_type[0] == 'ELF' and \ r_type[1] == elf.EM_X86_64 and \ r_type[2] in [ elf.R_X86_64_PC32, elf.R_X86_64_GOT32, elf.R_X86_64_PLT32, elf.R_X86_64_32S, ]: # The 32-bit reloc is expanded to 64-bit argument by amoco # but not with PUSH... # Note that the binutils syntax for PUSH immediate is very # inconsistent; objdump outputs: # 6a 08 (push one byte) => pushq $0x8 # 66 6a 08 (push two bytes) => pushw $0x8 # 66 68 08 00 (push two bytes) => pushw $0x8 # 68 08 00 00 00 (push four bytes) => pushq $0x8 # the latter being used for relocs # we would have expected either always pushq, or depending # on the argument size pushb, pushw, pushl if self.opname != 'push': size = 64 if r_type[0] == 'ELF' and \ r_type[1] == elf.EM_X86_64 and \ r_type[2] == elf.R_X86_64_PC32 and \ getattr(label, 'bind', None) == 'weak': # In some cases, a new label has to be generated, or we get # an error: 'relocation R_X86_64_PC32 against symbol ... can # not be used when making a shared object' label = label.symbols.find_symbol(name='.LTHUNK%d' % len(label.symbols.symbols), data={'set': label}) else: # Special case: offset to a switch table r_type, data = reloc TODO ext_label = expressions.lab(label, size=size) if label_dif is not None: NEVER ext_label -= expressions.lab(label_dif, size=size) if offset != 0: ext_label = ext_label + offset if self.amoco.operands[argpos]._is_cst: self.amoco.operands[argpos] += ext_label elif self.amoco.operands[argpos]._is_mem and self.amoco.operands[ argpos].a.base._is_cst: self.amoco.operands[argpos].a.base += ext_label elif self.amoco.operands[argpos]._is_mem: self.amoco.operands[argpos].a.disp += ext_label else: NEVER
def test_decoder_017(): c = b'\x2a\xf1' i = cpu.disassemble(c) assert i.mnemonic == 'SUB' assert i.operands[0].ref == 'dh' assert i.operands[1].ref == 'cl'
def test_decoder_007(): c = b'\x40\x80\xcc\x0c' i = cpu.disassemble(c) assert i.operands[0].ref == 'spl'
def test_decoder_011(): c = codecs.decode('41ffd7', 'hex') i = cpu.disassemble(c) assert i.mnemonic == 'CALL' assert i.operands[0].ref == 'r15'
def test_decoder_008(): c = codecs.decode('48B88877665544332211', 'hex') i = cpu.disassemble(c) assert i.operands[1] == 0x1122334455667788
def test_decoder_000(): c = b'\x90' i = cpu.disassemble(c) assert i.mnemonic == 'NOP'
def test_decoder_010(): c = codecs.decode('488d0c59', 'hex') i = cpu.disassemble(c) assert i.operands[1].a.base == ((rbx * 0x2) + rcx)
def test_decoder_027(): c = b'\xf2\x48\x0f\x2c\xf3' i = cpu.disassemble(c) assert i.mnemonic == 'CVTTSD2SI' assert i.operands[0].ref == 'rsi' assert i.operands[1].ref == 'xmm3'
def test_decoder_024(): c = b'\x66\x51' i = cpu.disassemble(c) assert i.mnemonic == 'PUSH' assert i.operands[0].ref == 'cx'
def test_decoder_014(): c = b'\x48\xa5' i = cpu.disassemble(c) assert i.mnemonic == 'MOVSQ'