Skip to content

Hacking on Manticore

Eric Hennenfent edited this page Apr 29, 2020 · 21 revisions

Contributing guidelines

If you haven't already, please see our contribution guidelines

Developer Installation

For a dev install that includes dependencies for tests, run:

git clone https://github.com/trailofbits/manticore.git && cd manticore
pip3 install -e ".[dev-noks]"

The "noks" stands for "No Keystone". The Keystone assembler is only required if you're developing new instructions for a native architecture, and tends to be finicky about installing. If you need it, simply replace the above command with pip3 install -e ".[dev]".

The -e flag to pip will install the package in "editable" mode. This means you don't have to reinstall the package after making changes to the source.

Testing

You can run the tests with the commands below. The unittest module is built-in to python and can be used to conveniently run tests.

cd manticore
# all tests
python -m unittest
# just one file
python -m unittest tests/test_armv7cpu.py
# just one test class
python -m unittest tests/test_armv7cpu.py:Armv7CpuInstructions
# just one test
python -m unittest tests/test_armv7cpu.py:Armv7CpuInstructions.test_mov_imm_min

You can also use the pytest utility for additional functionality. As of 0.3.3, using the pytest-xdist module for parallel testing causes some tests to break, so use it at your own risk.

Event System

Manticore implements a synchronous publish/subscribe system for executing code when certain analysis events happen.

More reading: https://github.com/Mach-II/Mach-II-Framework/wiki/Introduction-to-Implicit-Invocation-Architectures#EventbasedImplicitInvocation

If you are implementing an event handler there are certain things you need to know about locking: https://github.com/trailofbits/manticore/pull/433#issuecomment-320056828

Existing events that get produced

The following classes produce the following events:

  • manticore.core.cpu.Cpu
    • will_write_register, arguments: register, value
    • did_write_register, arguments: register, value
    • will_read_register, arguments: register
    • did_read_register, arguments: register, value
    • will_write_memory, arguments: where, expression, size
    • did_write_memory, arguments: where, expression, size
    • will_read_memory, arguments: where, size
    • did_read_memory, arguments: where, value, size
    • will_decode_instruction, arguments: pc
    • will_execute_instruction, arguments: instruction
    • will_emulate_instruction, arguments: instruction
    • did_emulate_instruction, arguments: instruction
    • did_execute_instruction, arguments: instruction
  • manticore.core.Executor
    • did_add_state, arguments: state_id, state
    • will_generate_testcase, arguments: state, prefix, message
    • will_fork_state, arguments: state, expression, solutions, policy
    • forking_state, arguments: state, expression, new_value, policy
    • will_load_state, arguments: current_state, current_state_id
    • will_terminate_state, arguments: current_state, current_state_id, message or exception
    • will_finish_run
    • All events produced by currently-executing manticore.core.State
  • manticore.core.State
    • state_generate_inputs, arguments: name, message
    • All events produced by manticore.platforms.Platform
  • manticore.platforms.Platform
    • All events produced by manticore.core.cpus.Cpu

Adding a Syscall

To implement a Linux syscall:

  • Look up the name of your syscall in manticore/platforms/linux_syscalls.py to get the correct name of your syscall for the corresponding syscall number.
  • In manticore/platforms/linux.py, add a method to the SLinux (Symbolic Linux) class for your syscall. Name your method precisely the name above. The arguments to this method should be
    • 1: self (standard Python self variable)
    • 2: cpu (manticore.core.abstractcpu.Cpu object representing current cpu state)
    • 3+: arguments to the syscall
  • Implement the logic of the syscall in this method, using the Cpu APIs as needed
  • The method should return the value returned by the syscall

Note on syscalls

When adding syscalls, make sure you're implementing the semantics defined by the system call, and not the similarly-named libc implementation. This mostly entails how you communicate error, for example, returning a negative errno value instead of returning -1 and setting a global. Check the linux source for the uses of SYSCALL_DEFINEn (where n is number of arguments. For more information, see adding-syscalls.rst) macros.

Adding an Instruction

To implement a cpu instruction:

  • Open the file according to the architecture for this instruction
    • x86 is in manticore/core/cpu/x86.py
    • armv7 is in manticore/core/cpu/arm.py
  • Add a method to the Cpu class in either of those files that subclasses Cpu
    • Decorate it with the @instruction decorator
    • The arguments to the method should be
      • 1: self
      • 2+ one argument for every operand in instruction.operands as decoded by Capstone. The types of these arguments are manticore.core.abstractcpu.Operand which is a light wrapper over a Capstone operand object (e.g. ArmOp)) and notably support convenience .read and .write methods.
  • Implement the instruction's effects

Using PDB

You can use pdb to debug your Manticore hooks. However, you must run Manticore in single-process mode (i.e. call Manticore.run(procs=1), or don't specify it at all) for this to work. Doing so when executing a multi-worker analysis run will cause pdb.set_trace() and other interactive commands to fail.

Building the html docs

  • Do a Manticore dev install (see README), or just install Sphinx
  • cd docs
  • make html