-
Notifications
You must be signed in to change notification settings - Fork 471
Hacking on Manticore
If you haven't already, please see our contribution guidelines
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.
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.
Manticore implements a synchronous publish/subscribe system for executing code when certain analysis events happen.
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
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
orexception
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
- All events produced by
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 theSLinux
(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
- 1:
- 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
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.
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
- x86 is in
- 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 aremanticore.core.abstractcpu.Operand
which is a light wrapper over a Capstone operand object (e.g. ArmOp)) and notably support convenience.read
and.write
methods.
- 1:
- Decorate it with the
- Implement the instruction's effects
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.
- Do a Manticore dev install (see README), or just install Sphinx
cd docs
make html