Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Symbolic start #2604

Draft
wants to merge 49 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
7d5b087
Use my capstone dev branch until fixes are merged into next
ekilmer May 8, 2020
f177ce8
Fix aarch64
ekilmer May 8, 2020
5ee1f15
Fix ARM
ekilmer May 8, 2020
10e49bd
Update Capstone commit to fix arm64 LD1 instruction immediates
ekilmer May 10, 2020
4f69dbc
Ignore coverage tracking for defensive assertions and exceptions
ekilmer May 26, 2020
f35744f
Merge branch 'master' into capstone-5-dev
feliam Jul 9, 2020
4b738bf
ENDBR64 as nop
feliam Jul 9, 2020
be9bdd1
Add lacking x86 tests
feliam Jul 14, 2020
6c24f8d
New x86 instrution test
feliam Jul 14, 2020
be00705
Merge branch 'master' into capstone-5-dev
ekilmer Aug 5, 2020
85b3bbb
Merge branch 'master' into capstone-5-dev
ekilmer Aug 11, 2020
4751e11
Disable write back once we hit our stop in Unicorn emulation
ekilmer Aug 3, 2020
3f21e92
Make emulator reinitialize after write backs are disabled
Sep 14, 2020
416b8b8
Merge branch 'master' into fix-emulate-step
Sep 14, 2020
cfafb6d
Fix linting on test_general
Sep 14, 2020
548fe47
Add a Rust/Unicorn resumption test
Sep 22, 2020
255eb70
Make rusticorn binary actually check behavior
Sep 22, 2020
d689bdd
Merge branch 'fix-emulate-step' into chess
ekilmer Sep 25, 2020
3e646f7
Merge branch 'master' into capstone-5-dev
ekilmer Sep 28, 2020
454a65f
Merge branch 'capstone-5-dev' into chess
ekilmer Sep 28, 2020
a21ea0f
Run CI on chess branch
ekilmer Sep 28, 2020
fd4a63d
Support for pread64 syscall
ekilmer Oct 6, 2020
8d6134f
Delete duplicated test method
Oct 14, 2020
fcbc2de
Merge branch 'master' into fix-emulate-step
Oct 14, 2020
565b35c
Fix addresses and improve error handling
Oct 14, 2020
20c1526
Merge branch 'master' into chess
ekilmer Nov 9, 2020
df4baa7
Fix issue with sphinx autodoc
ekilmer Nov 30, 2020
065516f
Add last_executed_pc property to abstract CPU
ekilmer Jan 20, 2021
cceeb1f
Optionally skip publishing mem read/writes in CPU
ekilmer Jan 21, 2021
6079bce
Shallow copy AMD64RegFile but keep concrete register values
ekilmer Jan 21, 2021
0db7011
Merge branch 'master' into chess
ekilmer Mar 29, 2021
d54307c
Remove call to pkg_resources that breaks custom installation
ekilmer Apr 7, 2021
e0d5f3a
Fix mypy
ekilmer Apr 7, 2021
8577543
Merge branch 'master' into chess
ekilmer Apr 7, 2021
a659442
Merge branch 'fix-emulate-step' into chess
ekilmer Apr 8, 2021
c3d7885
Merge branch 'master' into fix-emulate-step
ekilmer Apr 10, 2021
702260c
Fix Unicorn resume
ekilmer Apr 10, 2021
ac9be30
Merge branch 'fix-emulate-step' into chess
ekilmer Apr 14, 2021
dc64f11
Fix test missed during merge
ekilmer Apr 14, 2021
101596e
Fix more tests missed during merge
ekilmer Apr 15, 2021
ba5597c
staticmethods to get syscall info
ekilmer Apr 30, 2021
5fa3f94
Rework some logging
ekilmer May 27, 2021
bb5d00d
Better logging initialization
ekilmer May 27, 2021
5529d86
Remember to set manticore property on state __enter__
ekilmer Jun 4, 2021
f879bfd
Better log message in sys_recvfrom
ekilmer Jun 4, 2021
f9bcc15
Chess heap tracking work (#2458)
sschriner Jun 4, 2021
b3ecaf6
corrected read_arg in hook_malloc_library
sschriner Jun 4, 2021
27e0754
Add location to alloc info and remove some debugging statements (#2463)
sschriner Jun 23, 2021
d8243ac
start
sschriner Jul 1, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ exclude_lines =

# We don't bother testing code that's explicitly unimplemented
raise NotImplementedError
raise AssertionError
raise Aarch64InvalidInstruction
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: CI
on:
push:
branches:
- master
- chess
pull_request:
schedule:
# run CI every day even if no PRs/merges occur
Expand Down
17 changes: 10 additions & 7 deletions manticore/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ def main() -> None:
"""
Dispatches execution into one of Manticore's engines: evm or native.
"""
# Only print with Manticore's logger
logging.getLogger().handlers = []
log.init_logging()
args = parse_arguments()

if args.no_colors:
Expand Down Expand Up @@ -101,13 +104,13 @@ def positive(value):
help=("A folder name for temporaries and results." "(default mcore_?????)"),
)

current_version = pkg_resources.get_distribution("manticore").version
parser.add_argument(
"--version",
action="version",
version=f"Manticore {current_version}",
help="Show program version information",
)
# current_version = pkg_resources.get_distribution("manticore").version
# parser.add_argument(
# "--version",
# action="version",
# version=f"Manticore {current_version}",
# help="Show program version information",
# )
parser.add_argument(
"--config",
type=str,
Expand Down
12 changes: 10 additions & 2 deletions manticore/core/smtlib/solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,8 +231,16 @@ def send(self, cmd: str) -> None:
"""
if self._debug:
logger.debug(">%s", cmd)
self._proc.stdout.flush() # type: ignore
self._proc.stdin.write(f"{cmd}\n") # type: ignore
try:
self._proc.stdout.flush() # type: ignore
self._proc.stdin.write(f"{cmd}\n") # type: ignore
except (BrokenPipeError, IOError) as e:
logger.critical(
f"Solver encountered an error trying to send commands: {e}.\n"
f"\tOutput: {self._proc.stdout}\n\n"
f"\tStderr: {self._proc.stderr}"
)
raise e

def recv(self) -> str:
"""Reads the response from the smtlib solver"""
Expand Down
36 changes: 36 additions & 0 deletions manticore/core/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ def __enter__(self):
new_state._input_symbols = list(self._input_symbols)
new_state._context = copy.copy(self._context)
new_state._id = None
new_state.manticore = self.manticore
new_state._total_exec = self._total_exec
self.copy_eventful_state(new_state)

Expand Down Expand Up @@ -593,3 +594,38 @@ def symbolicate_buffer(
else:
assert b != 0
return data

def constrain_and_symbolicate_buffer(
self, data, label="INPUT", constraints={}, string=False, taint=frozenset()
):
# NOTE(sonya): this constraint dict should expanded to accommodate regex
# constraints is of the form {'wildcard char': [list of 'not' chars]}
# this function should be very useful for constraining input patterns in polling loops and other program arguments

if constraints:
size = len(data)
symb = self._constraints.new_array(
name=label, index_max=size, taint=taint, avoid_collisions=True
)
self._input_symbols.append(symb)

tmp = []
for i in range(size):
if data[i] in constraints:
tmp.append(symb[i])
logger.error(f"Constraint{constraints[data[i]]}")
for c in constraints[data[i]]:
logger.error(f"Constraint {c}")
self._constraints.add(tmp[i] != c)
else:
tmp.append(data[i])

data = tmp

if string:
for b in data:
if issymbolic(b):
self._constraints.add(b != 0)
else:
assert b != 0
return data
81 changes: 19 additions & 62 deletions manticore/native/cpu/aarch64.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import warnings
from typing import NamedTuple
from inspect import signature as inspect_signature

import capstone as cs
import collections
Expand All @@ -16,7 +17,6 @@
Operand,
instruction,
)
from .arm import HighBit, Armv7Operand
from .bitwise import SInt, UInt, ASR, LSL, LSR, ROR, Mask, GetNBits
from .register import Register
from ...core.smtlib import Operators
Expand Down Expand Up @@ -299,45 +299,7 @@ def canonicalize_instruction_name(insn):
# work for B.cond. Instead of being set to something like 'b.eq',
# it just returns 'b'.
name = insn.mnemonic.upper()
name = OP_NAME_MAP.get(name, name)
ops = insn.operands
name_list = name.split(".")

# Make sure MOV (bitmask immediate) and MOV (register) go through 'MOV'.
if (
name == "ORR"
and len(ops) == 3
and ops[1].type == cs.arm64.ARM64_OP_REG
and ops[1].reg in ["WZR", "XZR"]
and not ops[2].is_shifted()
):
name = "MOV"
insn._raw.mnemonic = name.lower().encode("ascii")
del ops[1]

# Map all B.cond variants to a single implementation.
elif len(name_list) == 2 and name_list[0] == "B" and insn.cc != cs.arm64.ARM64_CC_INVALID:
name = "B_cond"

# XXX: BFI is only valid when Rn != 11111:
# https://github.com/aquynh/capstone/issues/1441
elif (
name == "BFI"
and len(ops) == 4
and ops[1].type == cs.arm64.ARM64_OP_REG
and ops[1].reg in ["WZR", "XZR"]
):
name = "BFC"
insn._raw.mnemonic = name.lower().encode("ascii")
del ops[1]

# XXX: CMEQ incorrectly sets the type to 'ARM64_OP_FP' for
# 'cmeq v0.16b, v1.16b, #0':
# https://github.com/aquynh/capstone/issues/1443
elif name == "CMEQ" and len(ops) == 3 and ops[2].type == cs.arm64.ARM64_OP_FP:
ops[2]._type = cs.arm64.ARM64_OP_IMM

return name
return OP_NAME_MAP.get(name, name)

@property
def insn_bit_str(self):
Expand Down Expand Up @@ -2366,13 +2328,15 @@ def _CMEQ_zero(cpu, res_op, reg_op, imm_op):
cpu._cmeq(res_op, reg_op, imm_op, register=False)

@instruction
def CMEQ(cpu, res_op, reg_op, reg_imm_op):
def CMEQ(cpu, res_op, reg_op, reg_imm_op, _bug=0):
"""
Combines CMEQ (register) and CMEQ (zero).

:param res_op: destination register.
:param reg_op: source register.
:param reg_imm_op: source register or immediate (zero).

:param bug: Buggy extra operand https://github.com/aquynh/capstone/issues/1629
"""
assert res_op.type is cs.arm64.ARM64_OP_REG
assert reg_op.type is cs.arm64.ARM64_OP_REG
Expand Down Expand Up @@ -3648,17 +3612,6 @@ def _MOV_to_general(cpu, res_op, reg_op):

# XXX: Check if trapped.

# XXX: Capstone doesn't set 'vess' for this alias:
# https://github.com/aquynh/capstone/issues/1452
if res_op.size == 32:
reg_op.op.vess = cs.arm64.ARM64_VESS_S

elif res_op.size == 64:
reg_op.op.vess = cs.arm64.ARM64_VESS_D

else:
raise Aarch64InvalidInstruction

# The 'instruction' decorator advances PC, so call the original
# method.
cpu.UMOV.__wrapped__(cpu, res_op, reg_op)
Expand Down Expand Up @@ -3851,7 +3804,7 @@ def MRS(cpu, res_op, reg_op):
:param reg_op: source system register.
"""
assert res_op.type is cs.arm64.ARM64_OP_REG
assert reg_op.type is cs.arm64.ARM64_OP_REG_MRS
assert reg_op.type is cs.arm64.ARM64_OP_SYS

insn_rx = "1101010100"
insn_rx += "1" # L
Expand All @@ -3877,7 +3830,7 @@ def MSR(cpu, res_op, reg_op):
:param res_op: destination system register.
:param reg_op: source register.
"""
assert res_op.type is cs.arm64.ARM64_OP_REG_MSR
assert res_op.type is cs.arm64.ARM64_OP_SYS
assert reg_op.type is cs.arm64.ARM64_OP_REG

insn_rx = "1101010100"
Expand Down Expand Up @@ -5168,18 +5121,18 @@ def UMOV(cpu, res_op, reg_op):

reg = reg_op.read()
index = reg_op.op.vector_index
vess = reg_op.op.vess
vas = reg_op.op.vas

if vess == cs.arm64.ARM64_VESS_B:
if vas == cs.arm64.ARM64_VAS_1B:
elem_size = 8

elif vess == cs.arm64.ARM64_VESS_H:
elif vas == cs.arm64.ARM64_VAS_1H:
elem_size = 16

elif vess == cs.arm64.ARM64_VESS_S:
elif vas == cs.arm64.ARM64_VAS_1S:
elem_size = 32

elif vess == cs.arm64.ARM64_VESS_D:
elif vas == cs.arm64.ARM64_VAS_1D:
elem_size = 64

else:
Expand Down Expand Up @@ -5302,6 +5255,9 @@ def get_arguments(self):
for address in self.values_from(self._cpu.STACK):
yield address

def get_return_reg(self):
return "X0"

def write_result(self, result):
self._cpu.X0 = result

Expand Down Expand Up @@ -5339,6 +5295,7 @@ def __init__(self, cpu, op, **kwargs):
cs.arm64.ARM64_OP_MEM,
cs.arm64.ARM64_OP_IMM,
cs.arm64.ARM64_OP_FP,
cs.arm64.ARM64_OP_SYS,
cs.arm64.ARM64_OP_BARRIER,
):
raise NotImplementedError(f"Unsupported operand type: '{self.op.type}'")
Expand Down Expand Up @@ -5386,7 +5343,7 @@ def is_extended(self):
def read(self):
if self.type == cs.arm64.ARM64_OP_REG:
return self.cpu.regfile.read(self.reg)
elif self.type == cs.arm64.ARM64_OP_REG_MRS:
elif self.type == cs.arm64.ARM64_OP_REG_MRS or self.type == cs.arm64.ARM64_OP_SYS:
name = SYS_REG_MAP.get(self.op.sys)
if not name:
raise NotImplementedError(f"Unsupported system register: '0x{self.op.sys:x}'")
Expand All @@ -5399,7 +5356,7 @@ def read(self):
def write(self, value):
if self.type == cs.arm64.ARM64_OP_REG:
self.cpu.regfile.write(self.reg, value)
elif self.type == cs.arm64.ARM64_OP_REG_MSR:
elif self.type == cs.arm64.ARM64_OP_REG_MSR or cs.arm64.ARM64_OP_SYS:
name = SYS_REG_MAP.get(self.op.sys)
if not name:
raise NotImplementedError(f"Unsupported system register: '0x{self.op.sys:x}'")
Expand Down
Loading