#!/usr/bin/env python # -*- coding: utf-8 -*- import unittest import sys import shutil import tempfile import os import hashlib import subprocess import collections import time from manticore import Manticore, issymbolic from manticore import variadic from manticore.core.smtlib import BitVecVariable from manticore.core.cpu.abstractcpu import ConcretizeArgument, ConcretizeRegister, ConcretizeMemory from manticore.core.cpu.arm import Armv7Cpu, Armv7LinuxSyscallAbi, Armv7CdeclAbi from manticore.core.cpu.x86 import I386Cpu, AMD64Cpu, I386LinuxSyscallAbi, I386StdcallAbi, I386CdeclAbi, AMD64LinuxSyscallAbi, SystemVAbi from manticore.core.memory import SMemory32, Memory32, SMemory64 from manticore.core.smtlib import ConstraintSet, Operators class ABITests(unittest.TestCase): _multiprocess_can_split_ = True def setUp(self): mem32 = SMemory32(ConstraintSet()) mem32.mmap(0x1000, 0x1000, 'rw ') mem64 = SMemory64(ConstraintSet()) mem64.mmap(0x1000, 0x1000, 'rw ') self._cpu_arm = Armv7Cpu(mem32) self._cpu_arm.SP = 0x1080 self._cpu_arm.func_abi = Armv7CdeclAbi(self._cpu_arm) self._cpu_arm.syscall_abi = Armv7LinuxSyscallAbi(self._cpu_arm) self._cpu_x86 = I386Cpu(mem32) self._cpu_x86.ESP = 0x1080 self._cpu_x86.func_abi = I386CdeclAbi(self._cpu_x86) self._cpu_x86.syscall_abi = I386LinuxSyscallAbi(self._cpu_x86) self._cpu_x64 = AMD64Cpu(mem64) self._cpu_x64.RSP = 0x1080 self._cpu_x64.func_abi = SystemVAbi(self._cpu_x64) self._cpu_x64.syscall_abi = AMD64LinuxSyscallAbi(self._cpu_x64) def write(mem, where, val, size): mem[where:where+size/8] = [Operators.CHR(Operators.EXTRACT(val, offset, 8)) for offset in xrange(0, size, 8)] for val in range(0, 0x100, 4): write(mem32, 0x1000+val, val, 32) for val in range(0, 0x100, 8): write(mem64, 0x1000+val, val, 64) def test_executor(self): pass def test_arm_abi_simple(self): cpu = self._cpu_arm for i in range(4): cpu.write_register('R{}'.format(i), i) cpu.LR = 0x1234 def test(one, two, three, four): self.assertEqual(one, 0) self.assertEqual(two, 1) self.assertEqual(three, 2) self.assertEqual(four, 3) return 34 cpu.func_abi.invoke(test) # result is correctly captured self.assertEquals(cpu.R0, 34) # sp is unchanged self.assertEquals(cpu.SP, 0x1080) # returned correctly self.assertEquals(cpu.PC, cpu.LR) def test_arm_abi(self): cpu = self._cpu_arm for i in range(4): cpu.write_register('R{}'.format(i), i) cpu.LR = 0x1234 self.assertEqual(cpu.read_int(cpu.SP), 0x80) def test(one, two, three, four, five, six, seven): self.assertEqual(one, 0) self.assertEqual(two, 1) self.assertEqual(three, 2) self.assertEqual(four, 3) self.assertEqual(five, 0x80) self.assertEqual(six, 0x84) self.assertEqual(seven, 0x88) self.assertEqual(cpu.SP, 0x1080) return 34 cpu.func_abi.invoke(test) # result is correctly captured self.assertEquals(cpu.R0, 34) # sp is unchanged self.assertEquals(cpu.SP, 0x1080) # returned correctly self.assertEquals(cpu.PC, cpu.LR) def test_arm_abi_concretize_register(self): cpu = self._cpu_arm for i in range(4): cpu.write_register('R{}'.format(i), i) previous_r0 = cpu.R0 self.assertEqual(cpu.read_int(cpu.SP), 0x80) def test(one, two, three, four, five, six): raise ConcretizeArgument(cpu, 0) with self.assertRaises(ConcretizeRegister) as cr: cpu.func_abi.invoke(test) self.assertEquals(cpu.R0, previous_r0) self.assertEquals(cr.exception.reg_name, 'R0') self.assertEquals(cpu.SP, 0x1080) def test_arm_abi_concretize_memory(self): cpu = self._cpu_arm for i in range(4): cpu.write_register('R{}'.format(i), i) previous_r0 = cpu.R0 self.assertEqual(cpu.read_int(cpu.SP), 0x80) def test(one, two, three, four, five): raise ConcretizeArgument(cpu, 4) with self.assertRaises(ConcretizeMemory) as cr: cpu.func_abi.invoke(test) self.assertEquals(cpu.R0, previous_r0) self.assertEquals(cr.exception.address, cpu.SP) self.assertEquals(cpu.SP, 0x1080) def test_i386_cdecl(self): cpu = self._cpu_x86 base = cpu.ESP self.assertEqual(cpu.read_int(cpu.ESP), 0x80) cpu.push(0x1234, cpu.address_bit_size) def test(one, two, three, four, five): self.assertEqual(one, 0x80) self.assertEqual(two, 0x84) self.assertEqual(three, 0x88) self.assertEqual(four, 0x8c) self.assertEqual(five, 0x90) return 3 cpu.func_abi.invoke(test) self.assertEquals(cpu.EAX, 3) self.assertEquals(base, cpu.ESP) self.assertEquals(cpu.EIP, 0x1234) def test_i386_stdcall(self): cpu = self._cpu_x86 base = cpu.ESP bwidth = cpu.address_bit_size / 8 self.assertEqual(cpu.read_int(cpu.ESP), 0x80) cpu.push(0x1234, cpu.address_bit_size) def test(one, two, three, four, five): self.assertEqual(one, 0x80) self.assertEqual(two, 0x84) self.assertEqual(three, 0x88) self.assertEqual(four, 0x8c) self.assertEqual(five, 0x90) return 3 abi = I386StdcallAbi(cpu) abi.invoke(test) self.assertEquals(cpu.EAX, 3) self.assertEquals(base + bwidth * 5, cpu.ESP) self.assertEquals(cpu.EIP, 0x1234) def test_i386_stdcall_concretize(self): cpu = self._cpu_x86 bwidth = cpu.address_bit_size / 8 self.assertEqual(cpu.read_int(cpu.ESP), 0x80) cpu.push(0x1234, cpu.address_bit_size) eip = 0xDEADBEEF base = cpu.ESP cpu.EIP = eip def test(one, two, three, four, five): raise ConcretizeArgument(cpu, 2) abi = I386StdcallAbi(cpu) with self.assertRaises(ConcretizeMemory) as cr: abi.invoke(test) # Make sure ESP hasn't changed if exception was raised self.assertEquals(base, cpu.ESP) # Make sure EIP hasn't changed (i.e. return value wasn't popped) self.assertEquals(cpu.EIP, eip) def test_i386_cdecl_concretize(self): cpu = self._cpu_x86 base = cpu.ESP prev_eax = 0xcc cpu.EAX = prev_eax self.assertEqual(cpu.read_int(cpu.ESP), 0x80) cpu.push(0x1234, cpu.address_bit_size) def test(one, two, three, four, five): raise ConcretizeArgument(cpu, 0) # 0x1068 return 3 with self.assertRaises(ConcretizeMemory) as cr: cpu.func_abi.invoke(test) # Make sure we're concretizing self.assertEquals(cr.exception.address, 0x1080) # Make sure eax is unchanged self.assertEquals(cpu.EAX, prev_eax) # Make sure EIP wasn't popped self.assertEquals(base, cpu.ESP+4) self.assertNotEquals(cpu.EIP, 0x1234) def test_i386_vararg(self): cpu = self._cpu_x86 cpu.push(3, cpu.address_bit_size) cpu.push(2, cpu.address_bit_size) cpu.push(1, cpu.address_bit_size) # save return cpu.push(0x1234, cpu.address_bit_size) @variadic def test(params): for val, idx in zip(params, range(1, 4)): self.assertEqual(val, idx) cpu.func_abi.invoke(test) self.assertEquals(cpu.EIP, 0x1234) def test_amd64_basic_funcall(self): cpu = self._cpu_x64 cpu.RDI = 1 cpu.RSI = 2 cpu.RDX = 3 cpu.RCX = 4 cpu.R8 = 5 cpu.R9 = 6 cpu.push(0x1234, cpu.address_bit_size) def test(one, two, three, four, five, six): self.assertEqual(one, 1) self.assertEqual(two, 2) self.assertEqual(three, 3) self.assertEqual(four, 4) self.assertEqual(five, 5) self.assertEqual(six, 6) cpu.func_abi.invoke(test) self.assertEqual(cpu.RIP, 0x1234) def test_amd64_reg_mem_funcall(self): cpu = self._cpu_x64 cpu.RDI = 1 cpu.RSI = 2 cpu.RDX = 3 cpu.RCX = 4 cpu.R8 = 5 cpu.R9 = 6 cpu.push(0x1234, cpu.address_bit_size) def test(one, two, three, four, five, six, seven, eight): self.assertEqual(one, 1) self.assertEqual(two, 2) self.assertEqual(three, 3) self.assertEqual(four, 4) self.assertEqual(five, 5) self.assertEqual(six, 6) self.assertEqual(seven, 0x80) self.assertEqual(eight, 0x88) cpu.func_abi.invoke(test) self.assertEqual(cpu.RIP, 0x1234) def test_amd64_basic_funcall_concretize(self): cpu = self._cpu_x64 cpu.push(0x1234, cpu.address_bit_size) def test(one, two, three, four, five, six): raise ConcretizeArgument(cpu, 0) with self.assertRaises(ConcretizeRegister) as cr: cpu.func_abi.invoke(test) # Should not update RIP self.assertNotEqual(cpu.RIP, 0x1234) self.assertEquals(cr.exception.reg_name, 'RDI') def test_amd64_vararg(self): cpu = self._cpu_x64 cpu.RDI = 0 cpu.RSI = 1 cpu.RDX = 2 # save return cpu.push(0x1234, cpu.address_bit_size) @variadic def test(params): for val, idx in zip(params, range(3)): self.assertEqual(val, idx) cpu.func_abi.invoke(test) self.assertEquals(cpu.RIP, 0x1234) def test_i386_syscall(self): cpu = self._cpu_x86 cpu.EAX = 5 for idx, reg in enumerate(['EBX', 'ECX', 'EDX', 'ESI', 'EDI', 'EBP']): cpu.write_register(reg, idx) def test(one, two, three, four, five, six): self.assertEqual(one, 0) self.assertEqual(two, 1) self.assertEqual(three, 2) self.assertEqual(four, 3) self.assertEqual(five, 4) self.assertEqual(six, 5) return 34 self.assertEqual(cpu.syscall_abi.syscall_number(), 5) cpu.syscall_abi.invoke(test) self.assertEqual(cpu.EAX, 34) def test_amd64_syscall(self): cpu = self._cpu_x64 cpu.RAX = 5 for idx, reg in enumerate(['RDI', 'RSI', 'RDX', 'R10', 'R8', 'R9']): cpu.write_register(reg, idx) def test(one, two, three, four, five, six): self.assertEqual(one, 0) self.assertEqual(two, 1) self.assertEqual(three, 2) self.assertEqual(four, 3) self.assertEqual(five, 4) self.assertEqual(six, 5) return 34 self.assertEqual(cpu.syscall_abi.syscall_number(), 5) cpu.syscall_abi.invoke(test) self.assertEqual(cpu.RAX, 34) def test_test_prefix(self): cpu = self._cpu_x86 cpu.push(2, cpu.address_bit_size) cpu.push(0x1234, cpu.address_bit_size) def test(prefix, extracted): self.assertEquals(prefix, 1) self.assertEquals(extracted, 2) cpu.func_abi.invoke(test, prefix_args=(1,)) self.assertEquals(cpu.EIP, 0x1234) def test_fail_concretize_prefix_arg(self): cpu = self._cpu_x86 def test(prefix, extracted): raise ConcretizeArgument(cpu, 0) with self.assertRaises(AssertionError) as cr: cpu.func_abi.invoke(test, prefix_args=(1,)) def test_funcall_method(self): cpu = self._cpu_x86 cpu.push(2, cpu.address_bit_size) cpu.push(1, cpu.address_bit_size) cpu.push(0x1234, cpu.address_bit_size) class Kls(object): def method(self, a, b): return a+b obj = Kls() result = cpu.func_abi.invoke(obj.method) self.assertEquals(result, 3)