├── .codeclimate.yml ├── .coveragerc ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── config.yml │ └── feature_request.md ├── dependabot.yml └── workflows │ ├── ci.yml │ ├── osx.yml │ ├── pip-audit.yml │ └── release.yml ├── .gitignore ├── CHANGELOG.md ├── CITATION.cff ├── CODEOWNERS ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE ├── README.md ├── docs ├── Makefile ├── base.rst ├── conf.py ├── evm.rst ├── gotchas.rst ├── images │ └── manticore.png ├── index.rst ├── make.bat ├── native.rst ├── plugins.rst ├── requirements.txt ├── states.rst ├── utilities.rst ├── verifier.rst ├── wasm.rst └── worker.rst ├── examples ├── README.md ├── cgc │ ├── simple │ │ ├── Makefile │ │ └── main.c │ ├── stack │ │ ├── Makefile │ │ └── main.c │ └── strncmp │ │ ├── Makefile │ │ └── main.c ├── evm │ ├── asm.py │ ├── asm_to_smtlib.py │ ├── complete.py │ ├── coverage.py │ ├── coverage.sol │ ├── mappingchallenge.py │ ├── minimal-json.py │ ├── minimal.py │ ├── minimal_bytecode_only.py │ ├── reentrancy_concrete.py │ ├── reentrancy_symbolic.py │ ├── simple_int_overflow.sol │ ├── simple_mapping.py │ ├── simple_multi_func.sol │ ├── simple_value_check.sol │ ├── two_tx_ovf.sol │ ├── umd_example.sol │ └── use_def.py ├── linux │ ├── .gitignore │ ├── Makefile │ ├── arguments.c │ ├── baby-re.c │ ├── basic.c │ ├── basic_state_merging.c │ ├── binaries │ │ ├── concrete_solve.py │ │ ├── corruption │ │ ├── multiple-styles │ │ └── symbolic_solve.py │ ├── crackme.py │ ├── fclose.c │ ├── fileio.c │ ├── helloworld.c │ ├── ibranch.c │ ├── indexhell.c │ ├── introspect_state.py │ ├── ioctl_bogus.c │ ├── ioctl_socket.c │ ├── lava.c │ ├── nostdlib.c │ ├── sendmail.c │ ├── simple_copy.c │ ├── simpleassert.c │ ├── sindex.c │ └── strncmp.c ├── script │ ├── aarch64 │ │ ├── basic │ │ ├── basic.c │ │ ├── basic.py │ │ ├── hello42 │ │ ├── hello42.c │ │ └── hello42.py │ ├── basic_statemerging.py │ ├── concolic.py │ ├── count_instructions.py │ ├── introduce_symbolic_bytes.py │ ├── lads-baby-re.py │ ├── run_hook.py │ ├── run_simple.py │ ├── src │ │ └── state_explore.c │ ├── state_control.py │ ├── symbolic_file.py │ └── test_run_simple.c └── wasm │ ├── collatz │ ├── collatz.c │ ├── collatz.py │ ├── collatz.wasm │ └── collatz.wat │ └── if_check │ ├── if_check.c │ ├── if_check.wasm │ └── solve.py ├── lgtm.yml ├── manticore ├── __init__.py ├── __main__.py ├── binary │ ├── __init__.py │ └── binary.py ├── core │ ├── __init__.py │ ├── manticore.py │ ├── parser │ │ ├── __init__.py │ │ └── parser.py │ ├── plugin.py │ ├── smtlib │ │ ├── __init__.py │ │ ├── constraints.py │ │ ├── expression.py │ │ ├── operators.py │ │ ├── solver.py │ │ └── visitors.py │ ├── state.proto │ ├── state.py │ ├── state_pb2.py │ ├── worker.py │ └── workspace.py ├── ethereum │ ├── __init__.py │ ├── abi.py │ ├── abitypes.py │ ├── account.py │ ├── cli.py │ ├── detectors.py │ ├── manticore.py │ ├── parsetab.py │ ├── plugins.py │ ├── solidity.py │ ├── state.py │ └── verifier.py ├── exceptions.py ├── native │ ├── __init__.py │ ├── cli.py │ ├── cpu │ │ ├── __init__.py │ │ ├── aarch64.py │ │ ├── abstractcpu.py │ │ ├── arm.py │ │ ├── bitwise.py │ │ ├── cpufactory.py │ │ ├── disasm.py │ │ ├── register.py │ │ └── x86.py │ ├── manticore.py │ ├── mappings.py │ ├── memory.py │ ├── models.py │ ├── plugins.py │ ├── state.py │ └── state_merging.py ├── platforms │ ├── __init__.py │ ├── cgcrandom.py │ ├── decree.py │ ├── evm.py │ ├── linux.py │ ├── linux_syscall_stubs.py │ ├── linux_syscalls.py │ ├── platform.py │ └── wasm.py ├── utils │ ├── __init__.py │ ├── command_line.py │ ├── config.py │ ├── deprecated.py │ ├── emulate.py │ ├── enums.py │ ├── event.py │ ├── fallback_emulator.py │ ├── helpers.py │ ├── install_helper.py │ ├── log.py │ └── nointerrupt.py └── wasm │ ├── __init__.py │ ├── cli.py │ ├── executor.py │ ├── manticore.py │ ├── state.py │ ├── structure.py │ └── types.py ├── mypy.ini ├── pyproject.toml ├── readthedocs.yml ├── scripts ├── binaryninja │ ├── README.md │ └── manticore_viz │ │ ├── __init__.py │ │ └── plugin.json ├── compare_traces.py ├── extract_syscalls.py ├── follow_trace.py ├── gdb.py ├── prof.py ├── pyfile_exists.py ├── qemu.py ├── run_tests.sh ├── sandshrew │ ├── README.md │ ├── TUTORIAL.md │ ├── WRITING_TEST_CASES.md │ ├── examples │ │ ├── Makefile │ │ ├── test_openssl_bnsqr.c │ │ ├── test_openssl_md5.c │ │ └── test_tweetnacl_scalarmult.c │ └── sandshrew.py ├── stats.py └── verify.py ├── server ├── .gitignore ├── README.md ├── justfile ├── manticore_server │ ├── ManticoreServer.proto │ ├── ManticoreServer_pb2.py │ ├── ManticoreServer_pb2.pyi │ ├── ManticoreServer_pb2_grpc.py │ ├── __init__.py │ ├── evm_utils.py │ ├── introspect_plugin.py │ ├── manticore_server.py │ ├── native_plugin.py │ └── native_utils.py ├── pyproject.toml ├── setup.py └── tests │ ├── __init__.py │ ├── contracts │ └── adder.sol │ ├── mock_classes.py │ ├── test_ethereum.py │ └── test_native.py ├── setup.py ├── tests ├── README.md ├── __init__.py ├── auto_generators │ ├── Readme.md │ ├── flags.py │ ├── make_VMTests.py │ ├── make_dump.py │ ├── make_tests.py │ └── trace.py ├── conftest.py ├── ethereum │ ├── __init__.py │ ├── contracts │ │ ├── 1102.sol │ │ ├── 676.sol │ │ ├── 678.sol │ │ ├── 701.sol │ │ ├── 705.sol │ │ ├── 714.sol │ │ ├── 735.sol │ │ ├── 760.sol │ │ ├── 780.sol │ │ ├── 795.sol │ │ ├── 799.sol │ │ ├── 807.sol │ │ ├── 808.sol │ │ ├── absurdrepetition.sol │ │ ├── detectors │ │ │ ├── balance_not_ok.sol │ │ │ ├── balance_ok.sol │ │ │ ├── delegatecall_not_ok.sol │ │ │ ├── delegatecall_not_ok1.sol │ │ │ ├── delegatecall_ok.sol │ │ │ ├── delegatecall_ok1.sol │ │ │ ├── delegatecall_ok2.sol │ │ │ ├── delegatecall_ok3.sol │ │ │ ├── etherleak_true_neg.sol │ │ │ ├── etherleak_true_neg1.sol │ │ │ ├── etherleak_true_neg2.sol │ │ │ ├── etherleak_true_neg3.sol │ │ │ ├── etherleak_true_pos_argument.sol │ │ │ ├── etherleak_true_pos_argument1.sol │ │ │ ├── etherleak_true_pos_argument2.sol │ │ │ ├── etherleak_true_pos_msgsender.sol │ │ │ ├── etherleak_true_pos_msgsender1.sol │ │ │ ├── predictable_not_ok.sol │ │ │ ├── race_condition.sol │ │ │ ├── race_condition2.sol │ │ │ ├── retval_crazy.sol │ │ │ ├── retval_insane.sol │ │ │ ├── retval_lunatic.sol │ │ │ ├── retval_not_ok.sol │ │ │ ├── retval_ok.sol │ │ │ ├── selfdestruct_true_neg.sol │ │ │ ├── selfdestruct_true_neg1.sol │ │ │ ├── selfdestruct_true_pos.sol │ │ │ └── selfdestruct_true_pos1.sol │ │ ├── imp.sol │ │ ├── imports_issue │ │ │ ├── main │ │ │ │ └── main.sol │ │ │ └── utils │ │ │ │ ├── DirImported.sol │ │ │ │ └── DirImported2.sol │ │ ├── int_overflow.sol │ │ ├── prop_verifier.sol │ │ ├── reached.sol │ │ └── simple_int_overflow.sol │ ├── data │ │ ├── MetaCoin.json │ │ └── verbose_trace_plugin_out │ ├── test_detectors.py │ ├── test_general.py │ ├── test_plugins.py │ ├── test_regressions.py │ └── test_sha3.py ├── ethereum_bench │ ├── __init__.py │ ├── consensys_benchmark │ │ ├── assert_constructor.sol │ │ ├── assert_minimal.sol │ │ ├── assert_multitx_1.sol │ │ ├── assert_multitx_2.sol │ │ ├── assert_require.sol │ │ ├── assert_sym.sol │ │ ├── attribute_store.sol │ │ ├── eth_tx_order_dependence_multitx_1.sol │ │ ├── integer_overflow_add.sol │ │ ├── integer_overflow_benign_1.sol │ │ ├── integer_overflow_benign_2.sol │ │ ├── integer_overflow_bytes_param.sol │ │ ├── integer_overflow_dynarray.sol │ │ ├── integer_overflow_mapping_mapping.sol │ │ ├── integer_overflow_mapping_staticarray.sol │ │ ├── integer_overflow_mapping_strkey.sol │ │ ├── integer_overflow_mapping_struct.sol │ │ ├── integer_overflow_mapping_sym_1.sol │ │ ├── integer_overflow_mapping_sym_2.sol │ │ ├── integer_overflow_mapping_word.sol │ │ ├── integer_overflow_minimal.sol │ │ ├── integer_overflow_mul.sol │ │ ├── integer_overflow_multitx_multifunc_feasible.sol │ │ ├── integer_overflow_multitx_onefunc_feasible.sol │ │ ├── integer_overflow_multitx_onefunc_infeasible.sol │ │ ├── integer_overflow_path_1.sol │ │ ├── integer_overflow_staticarray.sol │ │ ├── integer_overflow_storageinvariant.sol │ │ ├── integer_overflow_storagepacking.sol │ │ ├── reentrancy_dao.sol │ │ ├── reentrancy_dao_fixed.sol │ │ └── reentrancy_nostateeffect.sol │ └── test_consensys_benchmark.py ├── native │ ├── __init__.py │ ├── aarch64cpu_asm_cache.py │ ├── binaries │ │ ├── arguments │ │ ├── arguments_linux_amd64 │ │ ├── arguments_linux_armv7 │ │ ├── basic_linux_amd64 │ │ ├── basic_linux_armv7 │ │ ├── basic_state_merging │ │ ├── brk_static_amd64 │ │ ├── cadet_decree_x86 │ │ ├── epoll │ │ ├── epoll.c │ │ ├── fclose_linux_amd64 │ │ ├── fileio_linux_amd64 │ │ ├── hello_world │ │ ├── ioctl_bogus_linux_amd64 │ │ ├── ioctl_socket_linux_amd64 │ │ ├── rusticorn │ │ ├── str_model_tests │ │ │ ├── sym_strcpy_test │ │ │ ├── sym_strcpy_test.c │ │ │ ├── sym_strlen_test │ │ │ ├── sym_strlen_test.c │ │ │ ├── sym_strncpy_test │ │ │ └── sym_strncpy_test.c │ │ ├── symbolic_length_recv │ │ ├── symbolic_length_recv.c │ │ ├── symbolic_read_count │ │ ├── symbolic_read_count.c │ │ └── thumb_mode_entrypoint │ ├── test_aarch64cpu.py │ ├── test_aarch64rf.py │ ├── test_abi.py │ ├── test_armv7_bitwise.py │ ├── test_armv7cpu.py │ ├── test_armv7rf.py │ ├── test_armv7unicorn.py │ ├── test_binary_package.py │ ├── test_cpu_automatic.py │ ├── test_cpu_manual.py │ ├── test_driver.py │ ├── test_dyn.py │ ├── test_integration_native.py │ ├── test_lazy_memory.py │ ├── test_linux.py │ ├── test_logging.py │ ├── test_manticore.py │ ├── test_memory.py │ ├── test_models.py │ ├── test_register.py │ ├── test_resume.py │ ├── test_rust.py │ ├── test_slam_regre.py │ ├── test_state.py │ ├── test_syscalls.py │ ├── test_unicorn_concrete.py │ ├── test_workspace.py │ ├── test_x86.py │ └── test_x86_pcmpxstrx.py ├── other │ ├── __init__.py │ ├── test_fork.py │ ├── test_locking.py │ ├── test_smtlibv2.py │ ├── test_state_introspection.py │ ├── test_tui_api.py │ └── utils │ │ ├── __init__.py │ │ ├── test_config.py │ │ └── test_events.py ├── wasm │ ├── generate_tests.sh │ ├── inputs │ │ ├── br_if.wasm │ │ ├── br_if.wast │ │ ├── br_table.wasm │ │ ├── br_table.wast │ │ ├── call_indirect.wasm │ │ ├── call_indirect.wast │ │ ├── if.wasm │ │ └── if.wast │ ├── json2mc.py │ ├── skipped_test_sets │ ├── test_callbacks.skip │ ├── test_examples.py │ ├── test_execution.py │ ├── test_stack_supplemental.py │ ├── test_state_saving.py │ └── test_template.jinja2 └── wasm_sym │ ├── generate_symbolic_tests.sh │ ├── json2smc.py │ ├── skipped_test_sets │ └── symbolic_test_template.jinja2 └── tox.ini /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | checks: 3 | argument-count: 4 | enabled: true 5 | config: 6 | threshold: 12 7 | complex-logic: 8 | enabled: true 9 | config: 10 | threshold: 4 11 | file-lines: 12 | enabled: true 13 | config: 14 | threshold: 9000 15 | method-complexity: 16 | enabled: false 17 | config: 18 | threshold: 40 19 | method-count: 20 | enabled: false 21 | config: 22 | threshold: 45 23 | method-lines: 24 | enabled: true 25 | config: 26 | threshold: 53 27 | nested-control-flow: 28 | enabled: true 29 | config: 30 | threshold: 10 31 | return-statements: 32 | enabled: true 33 | config: 34 | threshold: 5 35 | similar-code: 36 | enabled: true 37 | config: 38 | threshold: 210 39 | identical-code: 40 | enabled: true 41 | config: 42 | threshold: 65 43 | plugins: 44 | pep8: 45 | enabled: true 46 | checks: 47 | E712: 48 | enabled: false 49 | E701: 50 | enabled: false 51 | E203: 52 | enabled: false 53 | W503: 54 | enabled: false 55 | sonar-python: 56 | enabled: false 57 | config: 58 | minimum_severity: critical 59 | radon: 60 | enabled: false 61 | config: 62 | python_version: 3 63 | threshold: "D" 64 | exclude_patterns: 65 | - "docs/" 66 | - "examples/" 67 | - "scripts/" 68 | - "tests/" 69 | - "mcore_*/" 70 | - ".tox/" 71 | - "manticore/ethereum/parsetab.py" 72 | 73 | -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | source = manticore 3 | omit = 4 | *__init__.py 5 | 6 | [report] 7 | exclude_lines = 8 | # Have to re-enable the standard pragma 9 | pragma: no cover 10 | 11 | # Don't try to cover special syntax "..." in abstract class 12 | @abstractmethod 13 | 14 | # Ignore informational/debugging log statements 15 | logger.info 16 | logger.debug 17 | 18 | # We don't bother testing code that's explicitly unimplemented 19 | raise NotImplementedError 20 | raise AssertionError 21 | raise Aarch64InvalidInstruction 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve Manticore 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Summary of the problem 11 | 12 | 13 | ### Manticore version 14 | 15 | 16 | ### Python version 17 | 18 | 19 | ### OS / Environment 20 | 21 | 22 | ### Dependencies 23 | 24 | 25 | ### Step to reproduce the behavior 26 | 27 | 28 | ### Expected behavior 29 | 30 | 31 | ### Actual behavior 32 | 33 | 34 | ### Any relevant logs 35 | 36 | 37 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Ask a Question 4 | url: https://github.com/trailofbits/manticore/discussions/new 5 | about: Ask for help or clarification from the developers 6 | - name: Join our Slack 7 | url: https://empirehacking.slack.com/archives/C3PTWK7UM 8 | about: Engage with other users of Manticore -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest a new feature for Manticore 4 | title: '' 5 | labels: idea 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | updates: 4 | - package-ecosystem: github-actions 5 | directory: / 6 | schedule: 7 | interval: daily 8 | -------------------------------------------------------------------------------- /.github/workflows/osx.yml: -------------------------------------------------------------------------------- 1 | name: MacOS Tests 2 | 3 | on: 4 | schedule: 5 | # Run every day at 11 PM. 6 | - cron: '0 23 * * *' 7 | 8 | jobs: 9 | tests: 10 | runs-on: macos-latest 11 | strategy: 12 | fail-fast: false 13 | matrix: 14 | type: ["ethereum_truffle", "ethereum_bench", "ethereum", "ethereum_vm", "wasm", "wasm_sym", "other"] 15 | steps: 16 | - uses: actions/checkout@v3 17 | - name: Set up Python 3.7 18 | uses: actions/setup-python@v4 19 | with: 20 | python-version: 3.7 21 | - name: Install NPM 22 | uses: actions/setup-node@v3 23 | with: 24 | node-version: '16.x' 25 | - name: Install dependencies 26 | env: 27 | TEST_TYPE: ${{ matrix.type }} 28 | run: | 29 | EXTRAS="dev-noks" 30 | pip install -e .[$EXTRAS] 31 | - name: Install Mac Dependencies 32 | run: | 33 | brew install bash 34 | brew install wabt 35 | brew install SRI-CSL/sri-csl/yices2 36 | brew tap cvc4/cvc4 37 | brew install cvc4/cvc4/cvc4 38 | pip install solc-select 39 | solc-select install 0.4.26 40 | solc-select use 0.4.26 41 | - name: Run Tests 42 | env: 43 | TEST_TYPE: ${{ matrix.type }} 44 | run: | 45 | cp scripts/run_tests.sh . 46 | ./run_tests.sh 47 | -------------------------------------------------------------------------------- /.github/workflows/pip-audit.yml: -------------------------------------------------------------------------------- 1 | name: pip-audit 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | schedule: [ cron: "0 7 * * 2" ] 9 | 10 | jobs: 11 | audit: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout repository 15 | uses: actions/checkout@v3 16 | - name: Set up Python 3.10 17 | uses: actions/setup-python@v4 18 | with: 19 | python-version: "3.10" 20 | - name: Install Manticore 21 | run: | 22 | python -m pip install --upgrade pip setuptools 23 | python -m pip install . 24 | - name: Run pip-audit 25 | uses: pypa/gh-action-pip-audit@v1.0.6 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *,cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # dotenv 80 | .env 81 | 82 | # virtualenv 83 | .venv 84 | venv/ 85 | ENV/ 86 | venvpy27/ 87 | 88 | # Spyder project settings 89 | .spyderproject 90 | 91 | # Rope project settings 92 | .ropeproject 93 | 94 | # macOS Finder files 95 | .DS_Store 96 | 97 | # PyCharm files 98 | .idea/ 99 | 100 | # mypy cache 101 | .mypy_cache/ 102 | -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | # YAML 1.2 2 | --- 3 | abstract: "An effective way to maximize code coverage in software tests is through dynamic symbolic execution-a technique that uses constraint solving to systematically explore a program's state space. We introduce an open-source dynamic symbolic execution framework called Manticore for analyzing binaries and Ethereum smart contracts. Manticore's flexible architecture allows it to support both traditional and exotic execution environments, and its API allows users to customize their analysis. Here, we discuss Manticore's architecture and demonstrate the capabilities we have used to find bugs and verify the correctness of code for our commercial clients." 4 | authors: 5 | - 6 | affiliation: "Trail of Bits" 7 | family-names: Mossberg 8 | given-names: Mark 9 | - 10 | affiliation: "Trail of Bits" 11 | family-names: Manzano 12 | given-names: Felipe 13 | - 14 | affiliation: "Trail of Bits" 15 | family-names: Hennenfent 16 | given-names: Eric 17 | - 18 | affiliation: "Trail of Bits" 19 | family-names: Groce 20 | given-names: Alex 21 | - 22 | affiliation: "Trail of Bits" 23 | family-names: Greico 24 | given-names: Gustavo 25 | - 26 | affiliation: "Trail of Bits" 27 | family-names: Feist 28 | given-names: Josselin 29 | - 30 | affiliation: "Trail of Bits" 31 | family-names: Brunson 32 | given-names: Trent 33 | - 34 | affiliation: "Trail of Bits" 35 | family-names: Dinaburg 36 | given-names: Artem 37 | cff-version: "1.1.0" 38 | date-released: 2019-11-11 39 | doi: "10.1109/ASE.2019.00133" 40 | keywords: 41 | - "symbolic execution" 42 | - "binary analysis" 43 | - ethereum 44 | license: "AGPL-3.0" 45 | message: "If you use this software in an academic work, please cite our paper." 46 | repository-code: "https://github.com/trailofbits/manticore" 47 | title: "Manticore: A User-Friendly Symbolic Execution Framework for Binaries and Smart Contracts" 48 | ... 49 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @ekilmer 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | 3 | LABEL name=Manticore 4 | LABEL src="https://github.com/trailofbits/manticore" 5 | LABEL creator="Trail of Bits" 6 | LABEL dockerfile_maintenance=trailofbits 7 | 8 | ENV LANG C.UTF-8 9 | 10 | RUN apt-get -y update && DEBIAN_FRONTEND=noninteractive apt-get -y install python3 python3-dev python3-pip git wget 11 | 12 | # Install solc 0.4.25 and validate it 13 | RUN wget https://github.com/ethereum/solidity/releases/download/v0.4.25/solc-static-linux \ 14 | && chmod +x solc-static-linux \ 15 | && mv solc-static-linux /usr/bin/solc 16 | 17 | # If this fails, the solc-static-linux binary has changed while it should not. 18 | RUN [ "c9b268750506b88fe71371100050e9dd1e7edcf8f69da34d1cd09557ecb24580 /usr/bin/solc" = "$(sha256sum /usr/bin/solc)" ] 19 | 20 | RUN python3 -m pip install -U pip 21 | 22 | ADD . /manticore 23 | RUN cd manticore && python3 -m pip install .[native] 24 | 25 | CMD ["/bin/bash"] 26 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SPHINXPROJ = Manticore 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /docs/base.rst: -------------------------------------------------------------------------------- 1 | ManticoreBase 2 | ============= 3 | 4 | .. autoclass:: manticore.core.manticore.ManticoreBase 5 | :members: 6 | :special-members: __init__ 7 | :exclude-members: all_states, ready_states, count_ready_states, count_busy_states, killed_states, count_killed_states, terminated_states, count_terminated_states 8 | -------------------------------------------------------------------------------- /docs/evm.rst: -------------------------------------------------------------------------------- 1 | EVM 2 | --- 3 | 4 | ABI 5 | ^^^ 6 | 7 | .. autoclass:: manticore.ethereum.ABI 8 | :members: 9 | :undoc-members: 10 | 11 | Manager 12 | ^^^^^^^ 13 | 14 | .. autoclass:: manticore.ethereum.ManticoreEVM 15 | :members: 16 | :undoc-members: 17 | 18 | EVM 19 | ^^^ 20 | 21 | .. automodule:: manticore.platforms.evm 22 | :exclude-members: ADD, ADDMOD, ADDRESS, AND, BALANCE, BLOCKHASH, BYTE, CALL, CALLCODE, CALLDATACOPY, CALLDATALOAD, CALLDATASIZE, CALLER, CALLVALUE, CODECOPY, CODESIZE, COINBASE, CREATE, DELEGATECALL, DIFFICULTY, DIV, DUP, EQ, EXP, EXP_gas, EXTCODECOPY, EXTCODESIZE, GAS, GASLIMIT, GASPRICE, GETPC, GT, INVALID, ISZERO, JUMP, JUMPDEST, JUMPI, LT, MLOAD, MOD, MSIZE, MSTORE, MSTORE8, MUL, MULMOD, NOT, NUMBER, OR, ORIGIN, POP, PUSH, RETURN, SDIV, SELFDESTRUCT, SGT, SHA3, SIGNEXTEND, SLOAD, SLT, SMOD, SSTORE, STATICCALL, STOP, SUB, SWAP, TIMESTAMP, XOR, BALANCE_gas, CALLCODE_gas, CALLDATACOPY_gas, CALL_gas, CODECOPY_gas, CREATE_gas, DELEGATECALL_gas, EXTCODECOPY_gas, LOG, LOG_gas, MLOAD_gas, MSTORE8_gas, MSTORE_gas, PC, RETURNDATACOPY, RETURNDATACOPY_gas, RETURNDATASIZE, RETURN_gas, REVERT, REVERT_gas, SHA3_gas, SSTORE_gas, STATICCALL_gas, THROW 23 | :members: 24 | :undoc-members: 25 | -------------------------------------------------------------------------------- /docs/gotchas.rst: -------------------------------------------------------------------------------- 1 | Gotchas 2 | ======= 3 | 4 | Manticore has a number of "gotchas": quirks or little things you need to do in a certain way otherwise you'll have crashes and other unexpected results. 5 | 6 | Mutable context entries 7 | ----------------------- 8 | 9 | Something like ``m.context['flag'].append('a')`` inside a hook will not work. You need to (unfortunately, for now) do ``m.context['flag'] += ['a']``. This is related to 10 | Manticore's built in support for parallel analysis and use of the `multiprocessing` library. This gotcha is specifically related to this note from the Python 11 | `documentation `_ : 12 | 13 | "Note: Modifications to mutable values or items in dict and list proxies will not be propagated through the manager, because the proxy has no way of knowing when its values or items are modified. To modify such an item, you can re-assign the modified object to the container proxy" 14 | 15 | 16 | Context locking 17 | --------------- 18 | 19 | Manticore natively supports parallel analysis; if this is activated, client code should always be careful to properly lock the global context when accessing it. 20 | 21 | An example of a global context race condition, when modifying two context entries.:: 22 | 23 | m.context['flag1'] += ['a'] 24 | --- interrupted by other worker 25 | m.context['flag2'] += ['b'] 26 | 27 | Client code should use the :meth:`~manticore.core.ManticoreBase.locked_context` API:: 28 | 29 | with m.locked_context() as global_context: 30 | global_context['flag1'] += ['a'] 31 | global_context['flag2'] += ['b'] 32 | 33 | 34 | "Random" Policy 35 | --------------- 36 | 37 | The `random` policy, which is the Manticore default, is not actually random and is instead deterministically seeded. This means that running the same analysis twice should return the same results (and get stuck in the same places). 38 | -------------------------------------------------------------------------------- /docs/images/manticore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/docs/images/manticore.png -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to Manticore's documentation! 2 | ===================================== 3 | 4 | Manticore is a symbolic execution tool for analysis of binaries and smart contracts. 5 | 6 | 7 | 8 | .. toctree:: 9 | :maxdepth: 2 10 | :caption: Contents: 11 | 12 | verifier 13 | base 14 | worker 15 | states 16 | evm 17 | native 18 | wasm 19 | plugins 20 | gotchas 21 | utilities 22 | 23 | 24 | Indices and tables 25 | ------------------ 26 | 27 | * :ref:`genindex` 28 | * :ref:`modindex` 29 | * :ref:`search` 30 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | set SPHINXPROJ=Manticore 13 | 14 | if "%1" == "" goto help 15 | 16 | %SPHINXBUILD% >NUL 2>NUL 17 | if errorlevel 9009 ( 18 | echo. 19 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 20 | echo.installed, then set the SPHINXBUILD environment variable to point 21 | echo.to the full path of the 'sphinx-build' executable. Alternatively, you 22 | echo.may add the Sphinx directory to PATH. 23 | echo. 24 | echo.If you don't have Sphinx installed, grab it from 25 | echo.http://sphinx-doc.org/ 26 | exit /b 1 27 | ) 28 | 29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 30 | goto end 31 | 32 | :help 33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 34 | 35 | :end 36 | popd 37 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | Sphinx==4.3.0 2 | -------------------------------------------------------------------------------- /docs/states.rst: -------------------------------------------------------------------------------- 1 | States 2 | ====== 3 | 4 | Accessing 5 | --------- 6 | 7 | .. autoclass:: manticore.core.manticore.ManticoreBase 8 | :noindex: 9 | :undoc-members: 10 | :members: all_states, ready_states, count_ready_states, count_busy_states, killed_states, count_killed_states, terminated_states, count_terminated_states 11 | 12 | Operations 13 | ---------- 14 | 15 | .. autoclass:: manticore.core.state.StateBase 16 | :members: 17 | :undoc-members: 18 | :exclude-members: all_states, ready_states, count_ready_states, count_busy_states, killed_states, count_killed_states, terminated_states, count_terminated_states 19 | 20 | 21 | Inspecting 22 | ---------- 23 | 24 | .. autoclass:: manticore.core.plugin.StateDescriptor 25 | :members: 26 | :undoc-members: 27 | -------------------------------------------------------------------------------- /docs/utilities.rst: -------------------------------------------------------------------------------- 1 | Utilities 2 | --------- 3 | 4 | Logging 5 | ^^^^^^^ 6 | 7 | .. autofunction:: manticore.utils.log.init_logging 8 | .. autofunction:: manticore.utils.log.get_manticore_logger_names 9 | .. autofunction:: manticore.utils.log.set_verbosity 10 | .. autofunction:: manticore.utils.log.default_handler 11 | -------------------------------------------------------------------------------- /docs/wasm.rst: -------------------------------------------------------------------------------- 1 | Web Assembly 2 | ------------ 3 | 4 | 5 | ManticoreWASM 6 | ^^^^^^^^^^^^^ 7 | 8 | .. automodule:: manticore.wasm.manticore 9 | :members: 10 | :undoc-members: 11 | 12 | 13 | WASM World 14 | ^^^^^^^^^^ 15 | 16 | .. automodule:: manticore.platforms.wasm 17 | :members: 18 | :undoc-members: 19 | 20 | 21 | Executor 22 | ^^^^^^^^ 23 | 24 | .. automodule:: manticore.wasm.executor 25 | :members: 26 | :undoc-members: 27 | 28 | 29 | Module Structure 30 | ^^^^^^^^^^^^^^^^^ 31 | 32 | .. automodule:: manticore.wasm.structure 33 | :members: 34 | :undoc-members: 35 | 36 | 37 | Types 38 | ^^^^^ 39 | 40 | .. automodule:: manticore.wasm.types 41 | :members: 42 | :undoc-members: 43 | -------------------------------------------------------------------------------- /docs/worker.rst: -------------------------------------------------------------------------------- 1 | Workers 2 | ------- 3 | 4 | .. autoclass:: manticore.core.worker.Worker 5 | :undoc-members: 6 | :members: 7 | 8 | .. autoclass:: manticore.core.worker 9 | :members: 10 | :undoc-members: 11 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Manticore Examples 2 | 3 | ## Quickstart 4 | 5 | Install and try Manticore in a few shell commands: 6 | 7 | ```bash 8 | # (Recommended) Create a virtual environment for Manticore 9 | virtualenv -p `which python3` mcenv 10 | source mcenv/bin/activate 11 | 12 | # Install Manticore and its dependencies 13 | pip install manticore[native] 14 | 15 | # Download the examples 16 | git clone https://github.com/trailofbits/manticore.git && cd manticore/examples/linux 17 | 18 | # Build the examples 19 | make 20 | 21 | # Use the Manticore CLI 22 | manticore basic 23 | cat mcore_*/*0.stdin | ./basic 24 | cat mcore_*/*1.stdin | ./basic 25 | 26 | # Use the Manticore API 27 | cd ../script 28 | python count_instructions.py ../linux/helloworld 29 | ``` 30 | 31 | You can also use Docker to quickly install and try Manticore: 32 | 33 | ```bash 34 | # Run container with a shared examples/ directory 35 | # Note that `--rm` will make the container be deleted if you exit it 36 | # (if you want to persist data from the container, use docker volumes) 37 | # (we need to increase maximum stack size, so we use ulimit for that) 38 | $ docker run --rm -it --ulimit stack=100000000:100000000 trailofbits/manticore bash 39 | 40 | # Change to examples directory 41 | manticore@8d456f662d0f:~$ cd manticore/examples/linux/ 42 | 43 | # Build the examples 44 | manticore@8d456f662d0f:~/manticore/examples/linux$ make 45 | 46 | # Use the Manticore CLI 47 | manticore@8d456f662d0f:~/manticore/examples/linux$ manticore basic 48 | 49 | 50 | manticore@8d456f662d0f:~/manticore/examples/linux$ cat mcore_*/*0.stdin | ./basic 51 | manticore@8d456f662d0f:~/manticore/examples/linux$ cat mcore_*/*1.stdin | ./basic 52 | 53 | # Use the Manticore API 54 | manticore@8d456f662d0f:~/manticore/examples/linux$ cd ../script 55 | manticore@8d456f662d0f:~/manticore/examples/script$ python3.7 count_instructions.py ../linux/helloworld 56 | ``` 57 | -------------------------------------------------------------------------------- /examples/cgc/simple/Makefile: -------------------------------------------------------------------------------- 1 | PROGRAM_NAME=simple 2 | SRCS = $(wildcard *.S *.c ) 3 | LDFLAGS = -nostdlib -lcgc -L/usr/lib -static -s 4 | CGC_CFLAGS = -m32 -nostdlib -fno-builtin -nostdinc -nostartfiles -nodefaultlibs -Iinclude -Ilib -I/usr/include $(CFLAGS) 5 | PATH := /usr/i386-linux-cgc/bin:$(PATH) 6 | LD = ld 7 | LLC = llc-3.4 8 | CLANG = clang 9 | 10 | COBJS = $(SRCS:.c=.o) 11 | OBJS = $(COBJS:.S=.o) 12 | 13 | #cc -c -m32 -nostdlib -fno-builtin -nostdinc -nostartfiles -nodefaultlibs -Iinclude -Ilib -I/usr/include -o build/src/main.o src/main.c 14 | #ld -nostdlib -lcgc -L/usr/lib -static -s -o bin/array_index_validation_01 build/src/main.o 15 | 16 | 17 | all: $(PROGRAM_NAME) 18 | 19 | 20 | $(PROGRAM_NAME): $(OBJS) 21 | $(LD) $(LDFLAGS) -o $(PROGRAM_NAME) $^ 22 | 23 | %.o: %.c 24 | $(CC) -c $(CGC_CFLAGS) -o $@ $< 25 | 26 | %.o: %.S 27 | $(CC) -c $(CGC_CFLAGS) -o $@ $< 28 | 29 | clean: 30 | -rm -rf $(PROGRAM_NAME) $(OBJS) 31 | 32 | .PHONY: all build clean 33 | 34 | 35 | -------------------------------------------------------------------------------- /examples/cgc/simple/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #define msg1 "It's a number\n" 3 | #define msg2 "Not a number\n" 4 | 5 | int main(void) { 6 | char local=0; 7 | receive(STDIN, &local, 1, NULL); 8 | 9 | if (local >= '0') 10 | { 11 | if (local <= '9') 12 | transmit(STDOUT, msg1, sizeof(msg1), NULL); 13 | else 14 | transmit(STDOUT, msg2, sizeof(msg2), NULL); 15 | } 16 | else 17 | transmit(STDOUT, msg2, sizeof(msg2), NULL); 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /examples/cgc/stack/Makefile: -------------------------------------------------------------------------------- 1 | PROGRAM_NAME=stack 2 | SRCS = $(wildcard *.S *.c ) 3 | LDFLAGS = -nostdlib -lcgc -L/usr/lib -static -s 4 | CGC_CFLAGS = -m32 -nostdlib -fno-builtin -nostdinc -nostartfiles -nodefaultlibs -Iinclude -Ilib -I/usr/include $(CFLAGS) 5 | PATH := /usr/i386-linux-cgc/bin:$(PATH) 6 | LD = ld 7 | LLC = llc-3.4 8 | CLANG = clang 9 | 10 | COBJS = $(SRCS:.c=.o) 11 | OBJS = $(COBJS:.S=.o) 12 | 13 | #cc -c -m32 -nostdlib -fno-builtin -nostdinc -nostartfiles -nodefaultlibs -Iinclude -Ilib -I/usr/include -o build/src/main.o src/main.c 14 | #ld -nostdlib -lcgc -L/usr/lib -static -s -o bin/array_index_validation_01 build/src/main.o 15 | 16 | 17 | all: $(PROGRAM_NAME) 18 | 19 | 20 | $(PROGRAM_NAME): $(OBJS) 21 | $(LD) $(LDFLAGS) -o $(PROGRAM_NAME) $^ 22 | 23 | %.o: %.c 24 | $(CC) -c $(CGC_CFLAGS) -o $@ $< 25 | 26 | %.o: %.S 27 | $(CC) -c $(CGC_CFLAGS) -o $@ $< 28 | 29 | clean: 30 | -rm -rf $(PROGRAM_NAME) $(OBJS) 31 | 32 | .PHONY: all build clean 33 | 34 | 35 | -------------------------------------------------------------------------------- /examples/cgc/stack/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #define msg1 "Passed" 3 | #define msg2 "Failed" 4 | 5 | int check(int value){ 6 | if (value == 0x41424344) 7 | return 1; 8 | return 0; 9 | } 10 | 11 | void parser(){ 12 | size_t rx_bytes; 13 | int checksum = 0; 14 | struct { 15 | char buffer[32]; 16 | char checksum; 17 | } value; 18 | 19 | if (receive(STDIN, &value, 64 /* sizeof(value)*/, &rx_bytes)) 20 | _terminate(-1); 21 | 22 | for (; rx_bytes > 0; rx_bytes--) 23 | checksum += value.buffer[rx_bytes-1]; 24 | 25 | if (value.checksum != checksum) 26 | _terminate(-2); 27 | 28 | transmit(STDOUT, msg1, sizeof(msg1), NULL); 29 | } 30 | int main(void) { 31 | int value = 0; 32 | receive(STDIN, &value, sizeof(value), NULL); 33 | 34 | if (check(value)) 35 | parser(); 36 | else 37 | transmit(STDOUT, msg2, sizeof(msg2), NULL); 38 | 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /examples/cgc/strncmp/Makefile: -------------------------------------------------------------------------------- 1 | PROGRAM_NAME=strncmp 2 | SRCS = $(wildcard *.S *.c ) 3 | LDFLAGS = -nostdlib -lcgc -L/usr/lib -static -s 4 | CGC_CFLAGS = -m32 -nostdlib -fno-builtin -nostdinc -nostartfiles -nodefaultlibs -Iinclude -Ilib -I/usr/include $(CFLAGS) 5 | PATH := /usr/i386-linux-cgc/bin:$(PATH) 6 | LD = ld 7 | LLC = llc-3.4 8 | CLANG = clang 9 | 10 | COBJS = $(SRCS:.c=.o) 11 | OBJS = $(COBJS:.S=.o) 12 | 13 | #cc -c -m32 -nostdlib -fno-builtin -nostdinc -nostartfiles -nodefaultlibs -Iinclude -Ilib -I/usr/include -o build/src/main.o src/main.c 14 | #ld -nostdlib -lcgc -L/usr/lib -static -s -o bin/array_index_validation_01 build/src/main.o 15 | 16 | 17 | all: $(PROGRAM_NAME) 18 | 19 | 20 | $(PROGRAM_NAME): $(OBJS) 21 | $(LD) $(LDFLAGS) -o $(PROGRAM_NAME) $^ 22 | 23 | %.o: %.c 24 | $(CC) -c $(CGC_CFLAGS) -o $@ $< 25 | 26 | %.o: %.S 27 | $(CC) -c $(CGC_CFLAGS) -o $@ $< 28 | 29 | clean: 30 | -rm -rf $(PROGRAM_NAME) $(OBJS) 31 | 32 | .PHONY: all build clean 33 | 34 | 35 | -------------------------------------------------------------------------------- /examples/cgc/strncmp/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #define message1 "TOKEN found\n" 3 | #define message2 "TOKEN Not fount\n" 4 | #define TOKEN "HATTORIHANZO" 5 | int strcmp(const char* s1, const char* s2) 6 | { 7 | while(*s1 && (*s1==*s2)) 8 | s1++,s2++; 9 | return *(const unsigned char*)s1-*(const unsigned char*)s2; 10 | } 11 | 12 | int global_int = 0; 13 | int main(void) { 14 | char local_buffer[32]; 15 | receive(STDIN, &local_buffer, sizeof(local_buffer), NULL); 16 | 17 | if (strcmp(local_buffer, TOKEN) == 0) 18 | transmit(STDOUT, message1, sizeof(message1)-1, NULL); 19 | else 20 | transmit(STDOUT, message2, sizeof(message2)-1, NULL); 21 | 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /examples/evm/asm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # TODO: move this to pyevmasm 4 | # EVM disassembler 5 | import pyevmasm as ea 6 | from binascii import hexlify 7 | 8 | 9 | def printi(instruction): 10 | print(f"Instruction: {instruction}") 11 | print("\tdescription:", instruction.description) 12 | print("\tgroup:", instruction.group) 13 | print("\taddress:", instruction.pc) 14 | print("\tsize:", instruction.size) 15 | print("\thas_operand:", instruction.has_operand) 16 | print("\toperand_size:", instruction.operand_size) 17 | print("\toperand:", instruction.operand) 18 | print("\tsemantics:", instruction.semantics) 19 | print("\tpops:", instruction.pops) 20 | print("\tpushes:", instruction.pushes) 21 | print(f"\tbytes: 0x" + hexlify(instruction.bytes).decode()) 22 | print("\twrites to stack:", instruction.writes_to_stack) 23 | print("\treads from stack:", instruction.reads_from_stack) 24 | print("\twrites to memory:", instruction.writes_to_memory) 25 | print("\treads from memory:", instruction.reads_from_memory) 26 | print("\twrites to storage:", instruction.writes_to_storage) 27 | print("\treads from storage:", instruction.reads_from_storage) 28 | print("\tis terminator", instruction.is_terminator) 29 | 30 | 31 | instruction = ea.disassemble_one("\x60\x10") 32 | printi(instruction) 33 | 34 | instruction = ea.assemble_one("PUSH1 0x10") 35 | printi(instruction) 36 | 37 | for instruction in ea.disassemble_all("\x30\x31"): 38 | printi(instruction) 39 | 40 | for instruction in ea.assemble_all("ADDRESS\nBALANCE"): 41 | printi(instruction) 42 | 43 | 44 | # High level simple assembler/disassembler 45 | print( 46 | ea.assemble_hex( 47 | """PUSH1 0x60 48 | BLOCKHASH 49 | MSTORE 50 | PUSH1 0x2 51 | PUSH2 0x100 52 | """ 53 | ) 54 | ) 55 | 56 | 57 | print(ea.disassemble_hex("0x606040526002610100")) 58 | -------------------------------------------------------------------------------- /examples/evm/complete.py: -------------------------------------------------------------------------------- 1 | from manticore.ethereum import ManticoreEVM 2 | 3 | ################ Script ####################### 4 | 5 | m = ManticoreEVM() 6 | # And now make the contract account to analyze 7 | source_code = """ 8 | contract C { 9 | uint n; 10 | function C(uint x) { 11 | n = x; 12 | } 13 | function f(uint x) payable returns (bool) { 14 | if (x == n) { 15 | return true; 16 | } 17 | else{ 18 | return false; 19 | } 20 | } 21 | } 22 | """ 23 | 24 | user_account = m.create_account(balance=1000) 25 | print("[+] Creating a user account", user_account) 26 | 27 | contract_account = m.solidity_create_contract(source_code, owner=user_account, args=[42]) 28 | print("[+] Creating a contract account", contract_account) 29 | print("[+] Source code:") 30 | print(source_code) 31 | 32 | print("[+] Now the symbolic values") 33 | symbolic_data = m.make_symbolic_buffer(320) 34 | symbolic_value = m.make_symbolic_value(name="value") 35 | m.transaction( 36 | caller=user_account, address=contract_account, value=symbolic_value, data=symbolic_data 37 | ) 38 | 39 | print("[+] Resulting balances are:") 40 | for state in m.all_states: 41 | balance = state.platform.get_balance(int(user_account)) 42 | print(state.solve_one(balance)) 43 | 44 | m.finalize() 45 | print(f"[+] Look for results in {m.workspace}") 46 | -------------------------------------------------------------------------------- /examples/evm/coverage.py: -------------------------------------------------------------------------------- 1 | from manticore.ethereum import ManticoreEVM 2 | 3 | m = ManticoreEVM() 4 | m.verbosity(3) 5 | # And now make the contract account to analyze 6 | with open("coverage.sol") as f: 7 | source_code = f.read() 8 | 9 | user_account = m.create_account(balance=1000) 10 | 11 | bytecode = m.compile(source_code) 12 | # Initialize contract 13 | contract_account = m.create_contract(owner=user_account, balance=0, init=bytecode) 14 | 15 | m.transaction( 16 | caller=user_account, 17 | address=contract_account, 18 | value=m.make_symbolic_value(), 19 | data=m.make_symbolic_buffer(164), 20 | ) 21 | 22 | # Up to here we get only ~30% coverage. 23 | # We need 2 transactions to fully explore the contract 24 | m.transaction( 25 | caller=user_account, 26 | address=contract_account, 27 | value=m.make_symbolic_value(), 28 | data=m.make_symbolic_buffer(164), 29 | ) 30 | 31 | print(f"[+] There are {m.count_terminated_states()} reverted states now") 32 | print(f"[+] There are {m.count_busy_states()} alive states now") 33 | # for state_id in m.running_state_ids: 34 | # print(m.report(state_id)) 35 | 36 | print(f"[+] Global coverage: {contract_account.address:x}") 37 | print(m.global_coverage(contract_account)) 38 | -------------------------------------------------------------------------------- /examples/evm/mappingchallenge.py: -------------------------------------------------------------------------------- 1 | from manticore.ethereum import Detector, ManticoreEVM 2 | 3 | ################ Script ####################### 4 | 5 | m = ManticoreEVM() 6 | m.verbosity(3) 7 | # And now make the contract account to analyze 8 | # https://capturetheether.com/challenges/math/mapping/ 9 | source_code = """ 10 | pragma solidity ^0.4.21; 11 | 12 | contract MappingChallenge { 13 | bool public isComplete; 14 | uint256[] map; 15 | 16 | function set(uint256 key, uint256 value) public payable { 17 | // Expand dynamic array as needed 18 | if (map.length <= key) { 19 | map.length = key + 1; 20 | } 21 | 22 | map[key] = value; 23 | } 24 | } 25 | """ 26 | print("Source code:\n", source_code) 27 | 28 | 29 | class StopAtDepth(Detector): 30 | """This just aborts explorations that are too deep""" 31 | 32 | def will_run_callback(self, *args): 33 | with self.manticore.locked_context("seen_rep", dict) as reps: 34 | reps.clear() 35 | 36 | def will_decode_instruction_callback(self, state, pc): 37 | world = state.platform 38 | with self.manticore.locked_context("seen_rep", dict) as reps: 39 | item = ( 40 | world.current_transaction.sort == "CREATE", 41 | world.current_transaction.address, 42 | pc, 43 | ) 44 | if not item in reps: 45 | reps[item] = 0 46 | reps[item] += 1 47 | if reps[item] > 2: 48 | state.abandon() 49 | 50 | 51 | m.register_plugin(StopAtDepth()) 52 | 53 | owner_account = m.create_account(balance=1000) 54 | user_account = m.create_account(balance=1000) 55 | target_account = m.create_account(balance=1000) 56 | contract_account = m.solidity_create_contract(source_code, owner=user_account) 57 | 58 | contract_account.set(m.make_symbolic_value(name="A"), 1) 59 | contract_account.set(m.make_symbolic_value(name="B"), 1) 60 | 61 | for st in m.all_states: 62 | flag_storage_slot = 0 63 | flag_value = st.platform.get_storage_data(contract_account.address, flag_storage_slot) 64 | if st.can_be_true(flag_value != 0): 65 | print("Flag Found! Check ", m.workspace) 66 | st.constraints.add(flag_value != 0) 67 | m.generate_testcase(st, "Flag Found") 68 | -------------------------------------------------------------------------------- /examples/evm/minimal.py: -------------------------------------------------------------------------------- 1 | from manticore import ManticoreEVM 2 | 3 | ################ Script ####################### 4 | 5 | m = ManticoreEVM() 6 | 7 | # And now make the contract account to analyze 8 | # cat | solc --bin 9 | source_code = """ 10 | contract NoDistpatcher { 11 | event Log(string); 12 | 13 | function named_func(uint x) public returns (uint) { 14 | return 5 + x; 15 | } 16 | 17 | function() external payable { 18 | if (msg.data[0] == 'A') { 19 | emit Log("Got an A"); 20 | } 21 | else{ 22 | emit Log("Got something else"); 23 | } 24 | } 25 | } 26 | """ 27 | user_account = m.create_account(balance=m.make_symbolic_value(), name="user_account") 28 | print("[+] Creating a user account", user_account.name_) 29 | 30 | contract_account = m.solidity_create_contract( 31 | source_code, owner=user_account, name="contract_account" 32 | ) 33 | print("[+] Creating a contract account", contract_account.name_) 34 | contract_account.named_func(1) 35 | 36 | print("[+] Now the symbolic values") 37 | symbolic_data = m.make_symbolic_buffer(320) 38 | symbolic_value = m.make_symbolic_value(name="VALUE") 39 | symbolic_address = m.make_symbolic_value(name="ADDRESS") 40 | symbolic_caller = m.make_symbolic_value(name="CALLER") 41 | m.transaction( 42 | caller=symbolic_caller, address=symbolic_address, data=symbolic_data, value=symbolic_value 43 | ) 44 | 45 | # Let seth know we are not sending more transactions 46 | m.finalize() 47 | print(f"[+] Look for results in {m.workspace}") 48 | -------------------------------------------------------------------------------- /examples/evm/minimal_bytecode_only.py: -------------------------------------------------------------------------------- 1 | from manticore.ethereum import evm, ManticoreEVM 2 | from binascii import unhexlify, hexlify 3 | 4 | ################ Script ####################### 5 | # Bytecode only based analysis 6 | # No solidity, no compiler, no metadata 7 | 8 | m = ManticoreEVM() 9 | init_bytecode = unhexlify( 10 | b"608060405234801561001057600080fd5b506101cc806100206000396000f30060806040527f41000000000000000000000000000000000000000000000000000000000000006000366000818110151561003557fe5b905001357f010000000000000000000000000000000000000000000000000000000000000090047f0100000000000000000000000000000000000000000000000000000000000000027effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161415610135577fcf34ef537ac33ee1ac626ca1587a0a7e8e51561e5514f8cb36afa1c5102b3bab6040518080602001828103825260088152602001807f476f7420616e204100000000000000000000000000000000000000000000000081525060200191505060405180910390a161019e565b7fcf34ef537ac33ee1ac626ca1587a0a7e8e51561e5514f8cb36afa1c5102b3bab6040518080602001828103825260128152602001807f476f7420736f6d657468696e6720656c7365000000000000000000000000000081525060200191505060405180910390a15b0000a165627a7a72305820fd5ec850d8409e19cfe593b9ee3276cc3ac12b0e3406d965317dc9c1aeb7f2670029" 11 | ) 12 | 13 | user_account = m.create_account(balance=1000) 14 | print("[+] Creating a user account", user_account) 15 | 16 | print("[+] Init bytecode:", hexlify(init_bytecode)) 17 | print("[+] EVM init assembler:") 18 | for instr in evm.EVMAsm.disassemble_all(init_bytecode[:-44]): 19 | print(hex(instr.pc), instr) 20 | 21 | contract_account = m.create_contract(owner=user_account, init=init_bytecode) 22 | print("[+] Creating a contract account", contract_account) 23 | 24 | print("[+] Now the symbolic values") 25 | symbolic_data = m.make_symbolic_buffer(320) 26 | symbolic_value = m.make_symbolic_value() 27 | m.transaction( 28 | caller=user_account, address=contract_account, data=symbolic_data, value=symbolic_value 29 | ) 30 | 31 | # Let seth know we are not sending more transactions 32 | m.finalize() 33 | print(f"[+] Look for results in {m.workspace}") 34 | -------------------------------------------------------------------------------- /examples/evm/simple_int_overflow.sol: -------------------------------------------------------------------------------- 1 | contract Overflow { 2 | uint private sellerBalance=0; 3 | 4 | function add(uint value) returns (bool, uint){ 5 | sellerBalance += value; // complicated math with possible overflow 6 | 7 | // possible auditor assert 8 | assert(sellerBalance >= value); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/evm/simple_mapping.py: -------------------------------------------------------------------------------- 1 | from manticore.ethereum import ManticoreEVM 2 | 3 | m = ManticoreEVM() 4 | m.verbosity(2) 5 | # And now make the contract account to analyze 6 | # cat | solc --bin 7 | source_code = """ 8 | pragma solidity ^0.4.13; 9 | 10 | contract Test { 11 | event Log(string); 12 | mapping(address => uint) private balances; 13 | 14 | function Test(){ 15 | balances[0x1111111111111111111111111111111111111111] = 10; 16 | balances[0x2222222222222222222222222222222222222222] = 20; 17 | balances[0x3333333333333333333333333333333333333333] = 30; 18 | balances[0x4444444444444444444444444444444444444444] = 40; 19 | balances[0x5555555555555555555555555555555555555555] = 50; 20 | } 21 | 22 | function target(address key) returns (bool){ 23 | if (balances[key] > 20) 24 | Log("Balance greater than 20"); 25 | else 26 | Log("Balance less or equal than 20"); 27 | } 28 | 29 | } 30 | """ 31 | # Initialize accounts 32 | user_account = m.create_account(balance=1000) 33 | contract_account = m.solidity_create_contract(source_code, owner=user_account) 34 | 35 | symbolic_data = m.make_symbolic_buffer(64) 36 | symbolic_value = 0 37 | m.transaction( 38 | caller=user_account, address=contract_account, value=symbolic_value, data=symbolic_data 39 | ) 40 | 41 | m.finalize() 42 | print(f"[+] Look for results in {m.workspace}") 43 | -------------------------------------------------------------------------------- /examples/evm/simple_multi_func.sol: -------------------------------------------------------------------------------- 1 | contract Test { 2 | event Log(string); 3 | mapping(address => uint) private balances; 4 | 5 | function Test() {} 6 | function target1() public {} 7 | function target2() internal {} 8 | function target3() private {} 9 | function() {} 10 | 11 | } 12 | -------------------------------------------------------------------------------- /examples/evm/simple_value_check.sol: -------------------------------------------------------------------------------- 1 | 2 | contract Test { 3 | event Log(string); 4 | 5 | function target() payable public { 6 | if (msg.value > 10) 7 | emit Log("Value greater than 10"); 8 | else 9 | emit Log("Value less or equal than 10"); 10 | 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /examples/evm/two_tx_ovf.sol: -------------------------------------------------------------------------------- 1 | contract SymExExample { 2 | uint did_init = 0; 3 | 4 | event Log(string); 5 | 6 | // function id: 0x13371337 7 | function test_me(int input) { 8 | if (did_init == 0) { 9 | did_init = 1; 10 | emit Log("initialized"); 11 | return; 12 | } 13 | 14 | if (input < 42) { 15 | // safe 16 | emit Log("safe"); 17 | return; 18 | } else { 19 | // overflow possibly! 20 | int could_overflow = input + 1; 21 | emit Log("overflow"); 22 | } 23 | 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /examples/evm/umd_example.sol: -------------------------------------------------------------------------------- 1 | // Smart contract based on a classic symbolic execution example from slides 2 | // by Michael Hicks, University of Maryland. 3 | // https://www.cs.umd.edu/~mwh/se-tutorial/symbolic-exec.pdf 4 | 5 | contract SymExExample { 6 | 7 | 8 | function test_me(int a, int b, int c) public pure { 9 | int x = 0; 10 | int y = 0; 11 | int z = 0; 12 | 13 | if (a != 0) { 14 | x = -2; 15 | } 16 | 17 | if (b < 5) { 18 | if (a == 0 && c != 0) { 19 | y = 1; 20 | } 21 | z = 2; 22 | } 23 | 24 | // will fail when: a == 0 && b < 5 && c != 0 25 | assert(x + y + z != 3); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /examples/linux/.gitignore: -------------------------------------------------------------------------------- 1 | arguments 2 | basic 3 | crackme 4 | crackme.c 5 | fclose 6 | fileio 7 | helloworld 8 | ibranch 9 | indexhell 10 | nostdlib 11 | sendmail 12 | simple_copy 13 | simpleassert 14 | sindex 15 | strncmp 16 | -------------------------------------------------------------------------------- /examples/linux/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-O3 -static 3 | NOSTDLIBFLAGS=-fno-builtin -static -nostdlib -fomit-frame-pointer -fno-stack-protector 4 | PYTHON=python3 5 | 6 | EXAMPLES= \ 7 | arguments \ 8 | basic \ 9 | crackme \ 10 | fclose \ 11 | fileio \ 12 | helloworld \ 13 | ibranch \ 14 | indexhell \ 15 | ioctl_bogus \ 16 | ioctl_socket \ 17 | sendmail \ 18 | simpleassert \ 19 | simple_copy \ 20 | sindex \ 21 | strncmp \ 22 | 23 | OTHER_EXAMPLES=nostdlib 24 | 25 | all: $(EXAMPLES) $(OTHER_EXAMPLES) 26 | 27 | arm: CC=arm-linux-gnueabi-gcc 28 | arm: $(EXAMPLES) 29 | 30 | .PHONY: list clean 31 | list: 32 | @echo $(EXAMPLES) 33 | 34 | clean: 35 | rm -rf $(EXAMPLES) $(OTHER_EXAMPLES) crackme.c 36 | 37 | % : %.c 38 | $(CC) $(CFLAGS) $< -o $@ 39 | 40 | nostdlib: nostdlib.c 41 | $(CC) -m32 $(NOSTDLIBFLAGS) $< -o $@ 42 | 43 | # simpleassert needs -O0 44 | simpleassert: simpleassert.c 45 | $(CC) $(CFLAGS) -O0 $< -o $@ 46 | 47 | # crackme needs to be generated 48 | crackme.c: crackme.py 49 | $(PYTHON) crackme.py > $@ 50 | 51 | crackme: crackme.c 52 | $(CC) $(CFLAGS) -O0 $< -o $@ 53 | -------------------------------------------------------------------------------- /examples/linux/basic.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Symbolic values are read from stdin using standard libc calls. 3 | * Program checks if a binary packed integer at the input is 0x41 or less. 4 | * 5 | * Compile with : 6 | * $ gcc -static -Os basic.c -o basic 7 | * 8 | * Analyze it with: 9 | * $ manticore basic 10 | * 11 | * - By default, Manticore will consider all input of stdin to be symbolic 12 | * 13 | * Expected output: 14 | * $ manticore basic 15 | * 2017-04-22 10:35:52,789: [9309] MAIN:INFO: Loading program: ['basic'] 16 | * 2017-04-22 10:35:52,792: [9309] MAIN:INFO: Workspace: ./mcore_IJ2sPb 17 | * 2017-04-22 10:36:24,386: [9359][3] EXECUTOR:INFO: Generating testcase No. 1 for state No.3 - Program finished correctly 18 | * 2017-04-22 10:36:28,452: [9359][5] EXECUTOR:INFO: Generating testcase No. 2 for state No.5 - Program finished correctly 19 | * 20 | * Look at ./mcore_IJ2sPb for results, you will find something like this: 21 | * $ hexdump -C test_00000001.stdin 22 | * 00000000 00 80 00 20 |... | 23 | * 24 | * $ hexdump -C test_00000002.stdin 25 | * 00000000 41 00 00 00 |A...| 26 | * 27 | * You can try out the values like this: 28 | * 29 | * $ printf "\x00\x80\x00\x20" | ./basic 30 | * Message: It is greater than 0x41 31 | * 32 | * $ printf "\x41\x00\x00\x00" | ../basic 33 | * Message: It is smaller or equal than 0x41 34 | */ 35 | 36 | #include 37 | #include 38 | #include 39 | 40 | int main(int argc, char* argv[], char* envp[]){ 41 | unsigned int cmd; 42 | 43 | if (read(0, &cmd, sizeof(cmd)) != sizeof(cmd)) 44 | { 45 | printf("Error reading stdin!"); 46 | exit(-1); 47 | } 48 | 49 | if (cmd > 0x41) 50 | { 51 | printf("Message: It is greater than 0x41\n"); 52 | } 53 | else 54 | { 55 | printf("Message: It is less than or equal to 0x41\n"); 56 | } 57 | 58 | return 0; 59 | } 60 | 61 | 62 | -------------------------------------------------------------------------------- /examples/linux/basic_state_merging.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Symbolic values are read from stdin using standard libc calls. 3 | * Program compares if two binary packed integers at the input with 0x41. 4 | * 5 | * Compile with : 6 | * $ gcc -static -Os basic_statemerging.c -o basic_statemerging 7 | * 8 | * Analyze it with: 9 | * $ python examples/script/basic_statemerging.py examples/linux/basic_statemerging 10 | * 11 | * The Merger plugin used in basic_statemerging.py will find two states with state IDs 2, 4 to be at the same program 12 | * location (0x40060d) and merge their CPU states which should only require the value for RDI to be merged. 13 | * 14 | * Expected output: 15 | * $ python /Users/vaibhav/git_repos/manticore/examples/script/basic_statemerging.py examples/linux/basic_statemerging-Os 16 | about to load state_id = 0 17 | loaded state_id = 0 at cpu = 0x4008e0 18 | about to load state_id = 1 19 | loaded state_id = 1 at cpu = 0x400604 20 | about to load state_id = 2 21 | Merged registers: 22 | RDI 23 | at PC = 0x40060d, merge succeeded for state id = 2 and 4 24 | loaded state_id = 2 at cpu = 0x40060d 25 | about to load state_id = 3 26 | loaded state_id = 3 at cpu = 0x400612 27 | * 28 | */ 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | int main(int argc, char* argv[], char* envp[]){ 36 | unsigned int cmd1, cmd2; 37 | unsigned int cmdChanged = 0; 38 | 39 | if (read(0, &cmd1, sizeof(cmd1)) != sizeof(cmd1)) 40 | { 41 | printf("Error reading stdin!"); 42 | exit(-1); 43 | } 44 | if (read(0, &cmd2, sizeof(cmd2)) != sizeof(cmd2)) 45 | { 46 | printf("Error reading stdin!"); 47 | exit(-1); 48 | } 49 | 50 | if (cmd1 > 0x41) 51 | { 52 | cmdChanged = cmd1 - 0x42; 53 | } 54 | if (cmd2 < 0x41) 55 | { 56 | cmdChanged = cmd2 + 0x42; 57 | } 58 | 59 | if (cmdChanged == 0) printf("equal\n"); 60 | else printf("not equal\n"); 61 | 62 | return 0; 63 | } -------------------------------------------------------------------------------- /examples/linux/binaries/concrete_solve.py: -------------------------------------------------------------------------------- 1 | from manticore import Manticore 2 | 3 | 4 | def fixme(): 5 | raise Exception("Fill in the blanks!") 6 | 7 | 8 | # Let's initialize the manticore control object 9 | m = Manticore("multiple-styles") 10 | 11 | # First, let's give it some fake data for the input. Anything the same size as 12 | # the real flag should work fine! 13 | m.concrete_data = "infiltrate miami!" 14 | 15 | # Now we're going to want to execute a few different hooks and share data, so 16 | # let's use the m.context dict to keep our solution in 17 | m.context["solution"] = "" 18 | 19 | # Now we want to hook that compare instruction that controls the main loop. 20 | # Where is it again? 21 | @m.hook(fixme()) 22 | def solve(state): 23 | # Our actual flag should have something to do with AL at this point, let's 24 | # just read it out real quick 25 | flag_byte = state.cpu.AL - fixme() 26 | 27 | m.context["solution"] += chr(flag_byte) 28 | 29 | # But how can we make the comparison pass? There are a couple solutions here 30 | fixme() 31 | 32 | 33 | # play with these numbers! 34 | m.verbosity = 0 35 | procs = 1 36 | 37 | m.run(procs) 38 | print(m.context["solution"]) 39 | -------------------------------------------------------------------------------- /examples/linux/binaries/corruption: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/examples/linux/binaries/corruption -------------------------------------------------------------------------------- /examples/linux/binaries/multiple-styles: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/examples/linux/binaries/multiple-styles -------------------------------------------------------------------------------- /examples/linux/binaries/symbolic_solve.py: -------------------------------------------------------------------------------- 1 | from manticore import Manticore 2 | 3 | 4 | def fixme(): 5 | raise Exception("Fill in the blanks!") 6 | 7 | 8 | # Let's initialize the manticore control object 9 | m = Manticore("multiple-styles") 10 | 11 | # Now, we can hook the success state and figure out the flag! `fixme()` here 12 | # should be an address we'd like to get to 13 | @m.hook(fixme()) 14 | def solve(state): 15 | # Where is the flag in memory? It's probably offset from the base pointer 16 | # somehow 17 | flag_base = state.cpu.RBP - fixme() 18 | 19 | # We're going to build a solution later 20 | solution = "" 21 | 22 | # How big is the flag? We should be able to figure this out from traditional 23 | # static analysis 24 | for i in range(fixme()): 25 | # We can get the symbolic flag out 26 | symbolic_character = state.cpu.read_int(flag_base + i, 8) 27 | # And now we just need to solve for it in z3. How might we do that? 28 | # Perhaps `grep -r "def solve" manticore` can help our case 29 | concrete_character = fixme() 30 | solution += chr(concrete_character) 31 | 32 | # And this should give us a solution, after which we're done! 33 | print(solution) 34 | m.terminate() 35 | 36 | 37 | # play with these numbers! 38 | m.verbosity = 0 39 | procs = 1 40 | 41 | m.run(procs) 42 | -------------------------------------------------------------------------------- /examples/linux/fclose.c: -------------------------------------------------------------------------------- 1 | // This example closes file descriptors 0, 1, and 2 (which correspond to stdin, 2 | // stdout, and stderr in most environments). 3 | // 4 | // This serves as a reduced testcase for what most of the programs in GNU 5 | // coreutils do. See #1602 and #1604 on GitHub. 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | int main(int argc, char **argv) { 12 | if (argc >= 2 && strcmp(argv[1], "--close") == 0) { 13 | fprintf(stdout, "Closing file handles!\n"); 14 | 15 | int rc = 0; 16 | if (fclose(stdin) != 0) { 17 | rc += 1; 18 | } 19 | if (fclose(stdout) != 0) { 20 | rc += 2; 21 | } 22 | if (fclose(stderr) != 0) { 23 | rc += 4; 24 | } 25 | 26 | return rc; 27 | } else { 28 | fprintf(stdout, "Not doing anything.\n"); 29 | return 0; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /examples/linux/fileio.c: -------------------------------------------------------------------------------- 1 | // This example demonstrates reading & writing from files. 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, const char **argv) { 8 | if (argc != 2) { 9 | fprintf(stderr, "Usage: %s FILE\n", argv[0]); 10 | return 0; 11 | } 12 | 13 | const char *fname = argv[1]; 14 | FILE *infile = fopen(fname, "r"); 15 | if (!infile) { 16 | fprintf(stderr, "Error opening %s: %s\n", fname, strerror(errno)); 17 | return 2; 18 | } 19 | 20 | char *line; 21 | size_t line_size; 22 | ssize_t nread = getline(&line, &line_size, infile); 23 | if (nread == -1) { 24 | fprintf(stderr, "Error reading from %s: %s\n", fname, strerror(errno)); 25 | return 3; 26 | } 27 | 28 | if (strcmp("open sesame", line) == 0) { 29 | fprintf(stdout, "Welcome!\n"); 30 | return 0; 31 | } else { 32 | fprintf(stdout, "Access denied.\n"); 33 | return 4; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /examples/linux/helloworld.c: -------------------------------------------------------------------------------- 1 | #include 2 | int main(int argc, const char *argv[]) 3 | { 4 | puts("Hello, world!"); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /examples/linux/ibranch.c: -------------------------------------------------------------------------------- 1 | /* The symbolic input is taken from command line argument and it is 2 | * used as an index in a function pointer table. Analysis should explore 3 | * both functions. 4 | * 5 | * Compile with : 6 | * $ gcc -static -Os ibranch.c -o ibranch 7 | * 8 | * Analyze it with: 9 | * $ manticore ibranch + 10 | * 11 | * - The character + at the argument will be replaced by a free symbolic byte 12 | * 13 | * Expected output: 14 | * $ manticore ibranch + 15 | * 2017-04-24 12:05:09,089: [13266] MAIN:INFO: Loading program: ['ibranch', '+'] 16 | * 2017-04-24 12:05:09,090: [13266] MAIN:INFO: Workspace: ./mcore_1DLM6g 17 | * 2017-04-24 12:05:19,750: [13316][0] MEMORY:INFO: Reading 8 bytes from symbolic address 18 | * 2017-04-24 12:05:27,061: [13316][3] EXECUTOR:INFO: Generating testcase No. 1 for state No.3 - Program finished correctly 19 | * 2017-04-24 12:05:28,577: [13316][5] EXECUTOR:INFO: Generating testcase No. 2 for state No.5 - Program finished correctly 20 | * 21 | * Look at ./mcore_1DLM6g for results, you will find something like this: 22 | * $ cat *.stdout 23 | * Function g 24 | * Function f 25 | * - It found two finishing paths and explore both functions. - 26 | * 27 | */ 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | void f(){ 34 | printf("Function f\n"); 35 | } 36 | void g(){ 37 | printf("Function g\n"); 38 | } 39 | 40 | 41 | int main(int argc, char* argv[], char* envp[]){ 42 | int i; 43 | void (*funcs[2])( ); 44 | 45 | funcs[0] = f; 46 | funcs[1] = g; 47 | 48 | if (argc > 1) 49 | funcs[argv[1][0] == 'g'](); 50 | 51 | 52 | return 0; 53 | } 54 | 55 | 56 | -------------------------------------------------------------------------------- /examples/linux/indexhell.c: -------------------------------------------------------------------------------- 1 | /* This programs reads a M bytes from stdin, scrambles them, and sums them all. 2 | * Only some buffers make the program print "You won!". 3 | * Increasing the number of symbolic bytes can generate path constraints too hard to solve. 4 | * 5 | * Compile with : 6 | * $ gcc -static -Os indexhell.c -o indexhell 7 | * 8 | * Analyze it with: 9 | * $ manticore indexhell 10 | * 11 | * - By default, Manticore will consider all input of stdin to be symbolic 12 | * 13 | * 2017-04-24 12:46:46,227: [15880] MAIN:INFO: Loading program: ['indexhell'] 14 | * 2017-04-24 12:46:46,228: [15880] MAIN:INFO: Workspace: ./mcore_72BTxZ 15 | * 2017-04-24 12:46:53,302: [15934][0] MEMORY:INFO: Reading 1 bytes from symbolic address 16 | * 2017-04-24 12:46:54,093: [15934][0] MEMORY:INFO: Reading 1 bytes from symbolic address 17 | * 2017-04-24 12:46:54,944: [15934][0] MEMORY:INFO: Reading 1 bytes from symbolic address 18 | * 2017-04-24 12:46:55,907: [15934][0] MEMORY:INFO: Reading 1 bytes from symbolic address 19 | * 2017-04-24 12:46:56,678: [15934][0] MEMORY:INFO: Reading 1 bytes from symbolic address 20 | * 2017-04-24 12:46:57,497: [15934][0] MEMORY:INFO: Reading 1 bytes from symbolic address 21 | * 2017-04-24 12:47:06,520: [15934][3] EXECUTOR:INFO: Generating testcase No. 1 for state No.3 - Program finished correctly 22 | * 2017-04-24 12:47:09,693: [15934][5] EXECUTOR:INFO: Generating testcase No. 2 for state No.5 - Program finished correctly 23 | * 24 | * Look at ./mcore_72BTxZ for results, you will find something like this: 25 | * hexdump -C test_00000001.stdin 26 | * 00000000 23 80 26 ff 4f 56 |#.&.OV| 27 | * 28 | * cat mcore_72BTxZ/test_00000001 | ./indexhell 29 | * You won! 30 | */ 31 | 32 | #include 33 | #define M 6 34 | 35 | main(){ 36 | int i,count; 37 | unsigned char buffer[M]; 38 | read(0, buffer, M); 39 | 40 | for (i=0; i 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | // stropts not included in Ubuntu 20.04+ 11 | // #include 12 | #define FLUSHRW 0x03 13 | #define __SID ('S' << 8) 14 | #define I_FLUSH (__SID | 5) 15 | 16 | int main() { 17 | // try bogus ioctl on a non-open file descriptor 18 | int rc = ioctl(42, I_FLUSH, FLUSHRW); 19 | if (rc == -1) { 20 | fprintf(stderr, "got expected error: %s\n", strerror(errno)); 21 | return 0; 22 | } else { 23 | fprintf(stdout, "unexpectedly succeeded!\n"); 24 | return 1; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/linux/ioctl_socket.c: -------------------------------------------------------------------------------- 1 | // This example demonstrates a particular syscall that fails at runtime. 2 | // Used primarily as a test of Manticore's file-related syscall implementation. 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | // stropts not included in Ubuntu 20.04+ 11 | // #include 12 | #define FLUSHRW 0x03 13 | #define __SID ('S' << 8) 14 | #define I_FLUSH (__SID | 5) 15 | 16 | int main() { 17 | // try bogus ioctl on a socket 18 | int sockfd = socket(AF_INET, SOCK_STREAM, 0); 19 | if (sockfd < 0) { 20 | fprintf(stderr, "error opening socket: %s\n", strerror(errno)); 21 | return 1; 22 | } 23 | 24 | int rc = ioctl(sockfd, I_FLUSH, FLUSHRW); 25 | if (rc == -1) { 26 | fprintf(stderr, "got expected error calling ioctl: %s\n", strerror(errno)); 27 | return 0; 28 | } else { 29 | fprintf(stdout, "unexpectedly succeeded!\n"); 30 | return 2; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/linux/nostdlib.c: -------------------------------------------------------------------------------- 1 | /* Minimal toy example with some input output no stdlib 2 | * Symbolic values are read from stdin using int80 or syscall. The program has 2 possible paths 3 | * 4 | * Compile with : 5 | * $ gcc -fno-builtin -static -nostdlib -m32 -fomit-frame-pointer toy001.c -o toy001 6 | * 7 | * Analyze it with: 8 | * $ python system.py --sym stdin examples/toy001-nostdlib 9 | */ 10 | 11 | 12 | /* Linux takes system call arguments in registers: 13 | syscall number %eax call-clobbered 14 | arg 1 %ebx call-saved 15 | arg 2 %ecx call-clobbered 16 | arg 3 %edx call-clobbered 17 | arg 4 %esi call-saved 18 | arg 5 %edi call-saved 19 | arg 6 %ebp call-saved 20 | */ 21 | static inline 22 | int syscall(int syscall_number, int arg1, int arg2, int arg3) { 23 | int ret; 24 | asm volatile ( 25 | "pushl %%ebp\n\t" 26 | "movl %1, %%eax\n\t" 27 | "movl %2, %%eax\n\t" 28 | "movl %3, %%ebx\n\t" 29 | "movl %4, %%ecx\n\t" 30 | //"movl %4, %%edx\n\t" 31 | "int $0x80\n\t" 32 | "popl %%ebp\n\t" 33 | : "=a"(ret) 34 | : "g"(syscall_number), "g"(arg1), "g"(arg2), "g"(arg3) 35 | : "%ebx", "%ecx", "%edx", "%esi", "%edi" 36 | ); 37 | return ret; 38 | } 39 | 40 | int write(int fd, void* buffer, unsigned int size){ 41 | return syscall(4, fd, (int) buffer, size); 42 | } 43 | 44 | int read(int fd, void* buffer, unsigned int size){ 45 | return syscall(3, fd, (int) buffer, size); 46 | } 47 | 48 | int exit(int errorlevel){ 49 | return syscall(1, errorlevel,0,0); 50 | } 51 | 52 | void _start(){ 53 | unsigned char cmd; 54 | read(0,&cmd,1); 55 | 56 | if (cmd > 0x7f) 57 | { 58 | write(1, "Message: It is greater than 0x7f\n", 33); 59 | } 60 | else 61 | { 62 | write(1, "Message: It is smaller or equal than 0x7f\n", 42); 63 | } 64 | 65 | exit(0); 66 | } 67 | 68 | 69 | -------------------------------------------------------------------------------- /examples/linux/sendmail.c: -------------------------------------------------------------------------------- 1 | //http://2015.hackitoergosum.org/slides/HES2015-10-29%20Cracking%20Sendmail%20crackaddr.pdf 2 | #define BUFFERSIZE 200 3 | #define TRUE 1 4 | #define FALSE 0 5 | int 6 | copy_it (char *input, unsigned int length) 7 | { 8 | char c, localbuf[BUFFERSIZE]; 9 | unsigned int upperlimit = BUFFERSIZE - 10; 10 | unsigned int quotation = FALSE; 11 | unsigned int roundquote = FALSE; 12 | unsigned int inputIndex = 0; 13 | unsigned int outputIndex = 0; 14 | while (inputIndex < length) 15 | { 16 | c = input[inputIndex++]; 17 | if ((c == '<') && (!quotation)) 18 | { 19 | quotation = TRUE; 20 | upperlimit --; 21 | } 22 | if ((c == '>') && (quotation)) 23 | { 24 | quotation = FALSE; 25 | upperlimit++; 26 | } 27 | if ((c == '(') && (!quotation) && !roundquote) 28 | { 29 | roundquote = TRUE; 30 | upperlimit--; // decrementation was missing in bug 31 | } 32 | if ((c == ')') && (!quotation) && roundquote) 33 | { 34 | roundquote = FALSE; 35 | upperlimit++; 36 | } 37 | // If there is sufficient space in the buffer , write the character . 38 | if (outputIndex < upperlimit) 39 | { 40 | localbuf[outputIndex] = c; 41 | //prove that outputIndex < BUFFERSIZE holds 42 | outputIndex++; 43 | } 44 | } 45 | if (roundquote) 46 | { 47 | //prove that invariant outputIndex < BUFFERSIZE holds 48 | localbuf[outputIndex] = ')'; 49 | outputIndex++; 50 | } 51 | if (quotation) 52 | { 53 | //prove that invariant outputIndex < BUFFERSIZE holds 54 | localbuf[outputIndex] = '>'; 55 | outputIndex++; 56 | } 57 | } 58 | 59 | 60 | int 61 | main(int argc, char argv[]){ 62 | char buffer[200]; 63 | read(0,buffer,200); 64 | copy_it(buffer, 200); 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /examples/linux/simple_copy.c: -------------------------------------------------------------------------------- 1 | /* Simple program that copies data and makes decisions about it. 2 | * All data is concrete 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | int main(int argc, char* argv[], char* envp[]){ 9 | unsigned int cmd = argc; 10 | 11 | printf("About to compare\n"); 12 | 13 | if (cmd > 0x41) 14 | { 15 | printf("Message: It is greater than 0x41\n"); 16 | } 17 | else 18 | { 19 | printf("Message: It is smaller or equal than 0x41\n"); 20 | } 21 | 22 | return 0; 23 | } 24 | 25 | 26 | -------------------------------------------------------------------------------- /examples/linux/simpleassert.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Manticore should find 5 paths, one of which should be the `return -1` error 3 | * path. 4 | * 5 | * This code is based on the symbolic execution example in these slides: 6 | * https://www.cs.umd.edu/~mwh/se-tutorial/symbolic-exec.pdf 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | int main(int argc, char* argv[], char* envp[]){ 14 | int a; 15 | int b; 16 | int c; 17 | 18 | int x = 0; 19 | int y = 0; 20 | int z = 0; 21 | 22 | if (read(0, &a, sizeof(a)) != sizeof(a)) 23 | { 24 | printf("Error reading stdin!"); 25 | exit(-1); 26 | } 27 | if (read(0, &b, sizeof(b)) != sizeof(b)) 28 | { 29 | printf("Error reading stdin!"); 30 | exit(-1); 31 | } 32 | if (read(0, &c, sizeof(c)) != sizeof(c)) 33 | { 34 | printf("Error reading stdin!"); 35 | exit(-1); 36 | } 37 | 38 | if (a) { 39 | x = -2; 40 | } 41 | 42 | if (b < 5) { 43 | if (!a && c) { 44 | y = 1; 45 | } 46 | z = 2; 47 | } 48 | 49 | if (x + y + z == 3) { 50 | return -1; 51 | } 52 | 53 | return 0; 54 | } 55 | 56 | 57 | -------------------------------------------------------------------------------- /examples/script/aarch64/basic: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/examples/script/aarch64/basic -------------------------------------------------------------------------------- /examples/script/aarch64/basic.c: -------------------------------------------------------------------------------- 1 | // gcc -g -static -o basic basic.c 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char* argv[], char* envp[]){ 8 | unsigned int cmd; 9 | 10 | if (read(0, &cmd, sizeof(cmd)) != sizeof(cmd)) 11 | { 12 | printf("Error reading stdin!"); 13 | exit(-1); 14 | } 15 | 16 | if (cmd > 0x41) 17 | { 18 | printf("Message: It is greater than 0x41\n"); 19 | } 20 | else 21 | { 22 | printf("Message: It is less than or equal to 0x41\n"); 23 | } 24 | 25 | return 0; 26 | } 27 | 28 | 29 | -------------------------------------------------------------------------------- /examples/script/aarch64/basic.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import struct 5 | import sys 6 | 7 | from manticore.native import Manticore 8 | 9 | # Examples: 10 | # printf "\x41\x00\x00\x00" | PYTHONPATH=. ./examples/script/aarch64/basic.py 11 | # printf "++\x00\x00" | PYTHONPATH=. ./examples/script/aarch64/basic.py 12 | # printf "++++" | PYTHONPATH=. ./examples/script/aarch64/basic.py 13 | # printf "ffffff" | PYTHONPATH=. ./examples/script/aarch64/basic.py 14 | 15 | DIR = os.path.dirname(__file__) 16 | FILE = os.path.join(DIR, "basic") 17 | STDIN = sys.stdin.readline() 18 | 19 | # Avoid writing anything to 'STDIN' here. Do it in the 'init' hook as that's 20 | # more flexible. 21 | m = Manticore(FILE, concrete_start="", stdin_size=0) 22 | 23 | 24 | @m.init 25 | def init(state): 26 | state.platform.input.write(state.symbolicate_buffer(STDIN, label="STDIN")) 27 | 28 | 29 | # Hook the 'if' case. 30 | @m.hook(0x4006BC) 31 | def hook_if(state): 32 | print("hook if") 33 | state.abandon() 34 | 35 | 36 | # Hook the 'else' case. 37 | @m.hook(0x4006CC) 38 | def hook_else(state): 39 | print("hook else") 40 | # See how the constraints are affected by input. 41 | print_constraints(state, 6) 42 | 43 | w0 = state.cpu.W0 44 | 45 | if isinstance(w0, int): # concrete 46 | print(hex(w0)) 47 | else: 48 | print(w0) # symbolic 49 | 50 | solved = state.solve_one(w0) 51 | print(struct.pack("= nlines: 66 | break 67 | print(c) 68 | i += 1 69 | 70 | 71 | m.run() 72 | -------------------------------------------------------------------------------- /examples/script/aarch64/hello42: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/examples/script/aarch64/hello42 -------------------------------------------------------------------------------- /examples/script/aarch64/hello42.c: -------------------------------------------------------------------------------- 1 | // gcc -g -static -o hello42 hello42.c 2 | #include 3 | 4 | int main() 5 | { 6 | puts("hello"); 7 | return 42; 8 | } 9 | -------------------------------------------------------------------------------- /examples/script/aarch64/hello42.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | 5 | from manticore.native import Manticore 6 | 7 | # Modified 'count_instructions.py' to demonstrate execution of a 8 | # statically-linked "Hello, world!" AArch64 binary. 9 | 10 | DIR = os.path.dirname(__file__) 11 | FILE = os.path.join(DIR, "hello42") 12 | 13 | if __name__ == "__main__": 14 | m = Manticore(FILE) 15 | 16 | with m.locked_context() as context: 17 | context["count"] = 0 18 | 19 | @m.hook(None) 20 | def explore(state): 21 | with m.locked_context() as context: 22 | context["count"] += 1 23 | 24 | if state.cpu.PC == 0x406F10: # puts 25 | s = state.cpu.read_string(state.cpu.X0) 26 | assert s == "hello" 27 | print(f"puts argument: {s}") 28 | 29 | elif state.cpu.PC == 0x40706C: # puts result 30 | result = state.cpu.X0 31 | assert result >= 0 32 | print(f"puts result: {result}") 33 | 34 | elif state.cpu.PC == 0x415E50: # exit 35 | status = state.cpu.X0 36 | syscall = state.cpu.X8 37 | assert syscall == 94 # sys_exit_group 38 | print(f"exit status: {status}") 39 | 40 | def execute_instruction(self, insn, msg): 41 | print(f"{msg}: 0x{insn.address:x}: {insn.mnemonic} {insn.op_str}") 42 | 43 | m.subscribe( 44 | "will_execute_instruction", 45 | lambda self, state, pc, insn: execute_instruction(self, insn, "next"), 46 | ) 47 | m.subscribe( 48 | "did_execute_instruction", 49 | lambda self, state, last_pc, pc, insn: execute_instruction(self, insn, "done"), 50 | ) 51 | 52 | m.run() 53 | 54 | print(f"Executed {m.context['count']} instructions") 55 | -------------------------------------------------------------------------------- /examples/script/basic_statemerging.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | 5 | from manticore.native.plugins import Merger 6 | from manticore.utils import config 7 | 8 | from manticore.native import Manticore 9 | from manticore import set_verbosity 10 | 11 | """ 12 | Demonstrates the ability to do state merging on a simple program by merging states with id 2, 4 that happen to be 13 | at the same program location 0x40060d. This script uses the Merger plugin to apply opportunistic state merging. 14 | """ 15 | if __name__ == "__main__": 16 | config.get_group("core").seed = 2 17 | config.get_group("core").mprocessing = config.get_group("core").mprocessing.single 18 | path = sys.argv[1] 19 | m = Manticore(path, policy="random") 20 | 21 | def will_load_state_callback(_mc, state_id): 22 | print("about to load state_id = " + str(state_id)) 23 | 24 | def did_load_state_callback(_mc, state): 25 | print("loaded state_id = " + str(state.id) + " at cpu = " + hex(state.cpu.PC)) 26 | 27 | m.subscribe("will_load_state", will_load_state_callback) 28 | m.subscribe("did_load_state", did_load_state_callback) 29 | m.register_plugin(Merger()) 30 | m.run() 31 | -------------------------------------------------------------------------------- /examples/script/count_instructions.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | from manticore.native import Manticore 5 | 6 | """ 7 | Count the number of emulated instructions. 8 | 9 | This example uses the context property of the Manticore object to store data 10 | that's updated by the hook function. Manticore.context is needed to properly 11 | share data when running with multiple worker processes. 12 | """ 13 | 14 | if __name__ == "__main__": 15 | if len(sys.argv) < 2: 16 | sys.stderr.write(f"Usage: {sys.argv[0]} [binary]\n") 17 | sys.exit(2) 18 | 19 | m = Manticore(sys.argv[1]) 20 | with m.locked_context() as context: 21 | context["count"] = 0 22 | 23 | @m.hook(None) 24 | def explore(state): 25 | with m.locked_context() as context: 26 | context["count"] += 1 27 | 28 | m.run() 29 | 30 | print(f"Executed {m.context['count']} instructions.") 31 | -------------------------------------------------------------------------------- /examples/script/lads-baby-re.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | 5 | from manticore.native import Manticore 6 | 7 | """ 8 | Solves modified version of baby-re, compiled for arm. 9 | """ 10 | 11 | if __name__ == "__main__": 12 | path = sys.argv[1] 13 | m = Manticore(path) 14 | 15 | @m.hook(0x109F0) 16 | def myhook(state): 17 | flag = "" 18 | cpu = state.cpu 19 | arraytop = cpu.R11 20 | base = arraytop - 0x18 21 | for i in range(4): 22 | symbolic_input = cpu.read_int(base + i * 4) 23 | # TODO apis to constrain input to ascii 24 | concrete_input = state.solve_one(symbolic_input) 25 | flag += chr(concrete_input & 0xFF) 26 | print("flag is:", flag) 27 | m.terminate() 28 | 29 | m.run() 30 | -------------------------------------------------------------------------------- /examples/script/run_hook.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | from manticore.native import Manticore 5 | 6 | """ 7 | Demonstrates the ability to set a basic hook on a specific program counter and 8 | the ability to read from memory. 9 | """ 10 | 11 | if __name__ == "__main__": 12 | path = sys.argv[1] 13 | pc = int(sys.argv[2], 0) 14 | 15 | m = Manticore(path) 16 | 17 | # Trigger an event when PC reaches a certain value 18 | @m.hook(pc) 19 | def reached_goal(state): 20 | cpu = state.cpu 21 | 22 | assert cpu.PC == pc 23 | 24 | instruction = cpu.read_int(cpu.PC) 25 | print("Execution goal reached.") 26 | print(f"Instruction bytes: {instruction:08x}") 27 | 28 | m.run() 29 | -------------------------------------------------------------------------------- /examples/script/run_simple.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | from manticore.native import Manticore 5 | 6 | # This example demonstrates loading a simple binary in Manticore, 7 | # running it to completion without any callbacks or instrumentation 8 | # and producing basic information about the paths explored 9 | 10 | 11 | if __name__ == "__main__": 12 | path = sys.argv[1] 13 | # Create a new Manticore object 14 | m = Manticore(path) 15 | m.run() 16 | -------------------------------------------------------------------------------- /examples/script/src/state_explore.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /** 4 | * Example code for the state state_control.py and introduce_symbolic_bytes.py 5 | * examples. 6 | * 7 | * See scripts for more information. 8 | */ 9 | 10 | void 11 | fill_from_stdin(int *value) 12 | { 13 | read(0, value, sizeof *value); 14 | } 15 | 16 | int 17 | main(int argc, char *argv[]) 18 | { 19 | int value; 20 | 21 | /** 22 | * If we don't receive any arguments, read value from stdin. If we do 23 | * receive an argument, treat `value` as uninitialized. 24 | */ 25 | if (argc < 2) { 26 | fill_from_stdin(&value); 27 | } 28 | 29 | if ((value & 0xff) != 0) { 30 | if (value >= 0x40) { 31 | write(1, "1", 1); 32 | if (value == 0x41) { 33 | write(1, "a", 1); 34 | } else if (value == 0x42) { 35 | write(1, "b", 1); 36 | } else if (value == 0x43) { 37 | write(1, "c", 1); 38 | } else if (value == 0x44) { 39 | write(1, "d", 1); 40 | } else { 41 | write(1, "e", 1); 42 | } 43 | } else { 44 | write(1, "2", 1); 45 | } 46 | } else if ((value & 0xff00) != 0) { 47 | if (value > 0x1000) { 48 | write(1, "3", 1); 49 | } else { 50 | write(1, "4", 1); 51 | } 52 | } else if ((value & 0xff0000) != 0) { 53 | if (value > 0xf0000) { 54 | write(1, "5", 1); 55 | } else { 56 | write(1, "6", 1); 57 | } 58 | } 59 | write(1, "\n", 2); 60 | 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /examples/script/state_control.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | from manticore.native import Manticore 5 | 6 | """ 7 | Demonstrates the ability to guide Manticore's state exploration. In this case, 8 | abandoning a state we're no longer interested in. 9 | 10 | Usage: 11 | 12 | $ gcc -static -g src/state_explore.c -o state_explore # -static is optional 13 | $ ADDRESS=0x$(objdump -S state_explore | grep -A 1 'value == 0x41' | tail -n 1 | sed 's|^\s*||g' | cut -f1 -d:) 14 | $ python ./state_control.py state_explore $ADDRESS 15 | 16 | """ 17 | 18 | if __name__ == "__main__": 19 | if len(sys.argv) < 3: 20 | sys.stderr.write(f"Usage: {sys.argv[0]} [binary] [address]\n") 21 | sys.exit(2) 22 | 23 | m = Manticore(sys.argv[1]) 24 | 25 | # Uncomment to see debug output 26 | # m.verbosity = 2 27 | 28 | # Set to the address of the conditional at state_explore.c:38, which will be 29 | # abandoned. If line 36 of this script is commented out, Manticore will 30 | # explore all reachable states. 31 | to_abandon = int(sys.argv[2], 0) 32 | 33 | @m.hook(to_abandon) 34 | def explore(state): 35 | print(f"Abandoning state at PC: {state.cpu.PC:x}") 36 | state.abandon() 37 | 38 | print(f"Adding hook to: {to_abandon:x}") 39 | 40 | m.run() 41 | -------------------------------------------------------------------------------- /examples/script/test_run_simple.c: -------------------------------------------------------------------------------- 1 | #include 2 | int main(){return 0;} 3 | -------------------------------------------------------------------------------- /examples/wasm/collatz/collatz.c: -------------------------------------------------------------------------------- 1 | int collatz(int x){ 2 | if (x <= 1){ 3 | return 0; 4 | } 5 | if (x % 2 == 0){ 6 | return collatz(x / 2) + 1; 7 | } 8 | else{ 9 | return collatz(3 * x + 1) + 1; 10 | } 11 | } 12 | 13 | int main() { 14 | return collatz(getchar(">")); 15 | } -------------------------------------------------------------------------------- /examples/wasm/collatz/collatz.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/examples/wasm/collatz/collatz.wasm -------------------------------------------------------------------------------- /examples/wasm/collatz/collatz.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (type $FUNCSIG$i (func (result i32))) 3 | (type $FUNCSIG$ii (func (param i32) (result i32))) 4 | (import "env" "getchar" (func $getchar (param i32) (result i32))) 5 | (table 0 anyfunc) 6 | (memory $0 1) 7 | (data (i32.const 16) ">\00") 8 | (export "memory" (memory $0)) 9 | (export "collatz" (func $collatz)) 10 | (export "main" (func $main)) 11 | (func $collatz (; 1 ;) (param $0 i32) (result i32) 12 | (local $1 i32) 13 | (set_local $1 14 | (i32.const 0) 15 | ) 16 | (block $label$0 17 | (br_if $label$0 18 | (i32.lt_s 19 | (get_local $0) 20 | (i32.const 2) 21 | ) 22 | ) 23 | (set_local $1 24 | (i32.const 0) 25 | ) 26 | (loop $label$1 27 | (set_local $1 28 | (i32.add 29 | (get_local $1) 30 | (i32.const 1) 31 | ) 32 | ) 33 | (br_if $label$1 34 | (i32.gt_s 35 | (tee_local $0 36 | (select 37 | (i32.add 38 | (i32.mul 39 | (get_local $0) 40 | (i32.const 3) 41 | ) 42 | (i32.const 1) 43 | ) 44 | (i32.shr_u 45 | (get_local $0) 46 | (i32.const 1) 47 | ) 48 | (i32.and 49 | (get_local $0) 50 | (i32.const 1) 51 | ) 52 | ) 53 | ) 54 | (i32.const 1) 55 | ) 56 | ) 57 | ) 58 | ) 59 | (get_local $1) 60 | ) 61 | (func $main (; 2 ;) (result i32) 62 | (local $0 i32) 63 | (local $1 i32) 64 | (set_local $1 65 | (i32.const 0) 66 | ) 67 | (block $label$0 68 | (br_if $label$0 69 | (i32.lt_s 70 | (tee_local $0 71 | (call $getchar 72 | (i32.const 16) 73 | ) 74 | ) 75 | (i32.const 2) 76 | ) 77 | ) 78 | (set_local $1 79 | (i32.const 0) 80 | ) 81 | (loop $label$1 82 | (set_local $1 83 | (i32.add 84 | (get_local $1) 85 | (i32.const 1) 86 | ) 87 | ) 88 | (br_if $label$1 89 | (i32.gt_s 90 | (tee_local $0 91 | (select 92 | (i32.add 93 | (i32.mul 94 | (get_local $0) 95 | (i32.const 3) 96 | ) 97 | (i32.const 1) 98 | ) 99 | (i32.shr_u 100 | (get_local $0) 101 | (i32.const 1) 102 | ) 103 | (i32.and 104 | (get_local $0) 105 | (i32.const 1) 106 | ) 107 | ) 108 | ) 109 | (i32.const 1) 110 | ) 111 | ) 112 | ) 113 | ) 114 | (get_local $1) 115 | ) 116 | ) -------------------------------------------------------------------------------- /examples/wasm/if_check/if_check.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | uint8_t i = getchar(); 7 | 8 | int branch_counter = 1; 9 | if (!(128 & i)){ branch_counter++; 10 | if (64 & i){ branch_counter++; 11 | if (!(32 & i)){ branch_counter++; 12 | if (16 & i){ branch_counter++; 13 | if (8 & i){ branch_counter++; 14 | if (!(4 & i)){ branch_counter++; 15 | if (!(2 & i)){ branch_counter++; 16 | if (!(1 & i)){ branch_counter++; 17 | printf("You got it!\n"); 18 | return 0; 19 | } 20 | } 21 | } 22 | } 23 | } 24 | } 25 | } 26 | } 27 | 28 | printf("You lose :/\n"); 29 | return -1 * branch_counter; 30 | 31 | } -------------------------------------------------------------------------------- /examples/wasm/if_check/if_check.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/examples/wasm/if_check/if_check.wasm -------------------------------------------------------------------------------- /examples/wasm/if_check/solve.py: -------------------------------------------------------------------------------- 1 | from manticore.wasm import ManticoreWASM 2 | from manticore.core.plugin import Plugin 3 | 4 | 5 | def getchar(state): 6 | """Symbolic `getchar` implementation. Returns an arbitrary single byte""" 7 | res = state.new_symbolic_value(32, "getchar_res") 8 | state.constrain(0 < res) 9 | state.constrain(res < 256) 10 | return [res] 11 | 12 | 13 | class PrintRetPlugin(Plugin): 14 | """A plugin that looks for states that returned zero and solves for their inputs""" 15 | 16 | def will_terminate_state_callback(self, state, *args): 17 | retval = state.stack.peek() 18 | if retval == 0: 19 | print("Solution found!") 20 | for sym in state.input_symbols: 21 | solved = state.solve_one(sym) 22 | print(f"{sym.name}: {chr(solved)} --> Return {retval}") 23 | 24 | 25 | # Pass our symbolic implementation of the `getchar` function into the WASM environment 26 | # as an import. 27 | m = ManticoreWASM("if_check.wasm", env={"getchar": getchar}) 28 | 29 | # Register our state termination callback 30 | m.register_plugin(PrintRetPlugin()) 31 | 32 | # Run the main function, which will call getchar 33 | m.main() 34 | 35 | # Save a copy of the inputs to the disk 36 | m.finalize() 37 | -------------------------------------------------------------------------------- /lgtm.yml: -------------------------------------------------------------------------------- 1 | queries: 2 | - exclude: py/clear-text-logging-sensitive-data 3 | 4 | path_classifiers: 5 | examples: 6 | - examples/ 7 | -------------------------------------------------------------------------------- /manticore/__init__.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | if sys.version_info < (3, 7): 4 | print("Manticore requires Python 3.7 or higher.") 5 | sys.exit(-1) 6 | 7 | from .utils import config, log 8 | from .utils.log import set_verbosity 9 | from .core.smtlib import issymbolic, istainted 10 | from .ethereum.manticore import ManticoreEVM 11 | from .core.plugin import Plugin 12 | from .exceptions import ManticoreError 13 | 14 | __all__ = [ 15 | issymbolic.__name__, 16 | istainted.__name__, 17 | ManticoreEVM.__name__, 18 | set_verbosity.__name__, 19 | ManticoreError.__name__, 20 | ] 21 | -------------------------------------------------------------------------------- /manticore/binary/__init__.py: -------------------------------------------------------------------------------- 1 | """ Common binary formats interface 2 | Ideally you should be able to do something like 3 | 4 | from binary import Binary 5 | binary = Binary(filename) 6 | assert cpu.machine == binary.arch, "Not matching cpu" 7 | logger.info(f"Loading {filename} as a {binary.arch} elf") 8 | for mm in binary.maps(): 9 | cpu.mem.mmapFile( mm ) 10 | for th in binary.threads(): 11 | setup(th) 12 | 13 | But there are difference between format that makes it difficult to find a simple 14 | and common API. interpreters? linkers? linked DLLs? 15 | 16 | """ 17 | 18 | from .binary import Binary, CGCElf, Elf # noqa 19 | 20 | 21 | if __name__ == "__main__": 22 | import sys 23 | 24 | print(list(Binary(sys.argv[1]).threads())) 25 | print(list(Binary(sys.argv[1]).maps())) 26 | -------------------------------------------------------------------------------- /manticore/core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/manticore/core/__init__.py -------------------------------------------------------------------------------- /manticore/core/parser/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/manticore/core/parser/__init__.py -------------------------------------------------------------------------------- /manticore/core/smtlib/__init__.py: -------------------------------------------------------------------------------- 1 | from .expression import Expression, Bool, BitVec, Array, BitVecConstant, issymbolic # noqa 2 | from .constraints import ConstraintSet # noqa 3 | from .solver import * # noqa 4 | from . import operators as Operators # noqa 5 | 6 | import logging 7 | 8 | logger = logging.getLogger(__name__) 9 | -------------------------------------------------------------------------------- /manticore/core/state.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package mserialize; 4 | 5 | message LogMessage{ 6 | string content = 1; 7 | } 8 | 9 | message State{ 10 | 11 | enum StateType{ 12 | READY = 0; 13 | BUSY = 1; 14 | KILLED = 2; 15 | TERMINATED = 3; 16 | } 17 | 18 | int32 id = 2; // state ID 19 | StateType type = 3; // Type of state 20 | string reason = 4; // Reason for execution stopping 21 | int32 num_executing = 5; // number of executing instructions 22 | int32 wait_time = 6; 23 | } 24 | 25 | message StateList{ 26 | repeated State states = 7; 27 | } 28 | 29 | message MessageList{ 30 | repeated LogMessage messages = 8; 31 | } 32 | -------------------------------------------------------------------------------- /manticore/ethereum/__init__.py: -------------------------------------------------------------------------------- 1 | # Exports (for `from manticore.ethereum import ...`) 2 | from .abi import ABI 3 | from .manticore import ManticoreEVM, config 4 | from .state import State 5 | from .detectors import ( 6 | Detector, 7 | DetectEnvInstruction, 8 | DetectExternalCallAndLeak, 9 | DetectReentrancySimple, 10 | DetectSuicidal, 11 | DetectUnusedRetVal, 12 | DetectDelegatecall, 13 | DetectIntegerOverflow, 14 | DetectInvalid, 15 | DetectReentrancyAdvanced, 16 | DetectUninitializedMemory, 17 | DetectUninitializedStorage, 18 | DetectRaceCondition, 19 | DetectManipulableBalance, 20 | ) 21 | from .account import EVMAccount, EVMContract 22 | from .solidity import SolidityMetadata 23 | 24 | from ..exceptions import NoAliveStates, EthereumError 25 | from ..platforms import evm 26 | -------------------------------------------------------------------------------- /manticore/ethereum/state.py: -------------------------------------------------------------------------------- 1 | from ..core.state import StateBase 2 | from ..core.plugin import StateDescriptor 3 | 4 | 5 | class State(StateBase): 6 | def execute(self): 7 | super().execute() 8 | return self._platform.execute() 9 | 10 | def _update_state_descriptor(self, descriptor: StateDescriptor, *args, **kwargs): 11 | """ 12 | Called on execution_intermittent to update the descriptor for this state. 13 | This one should apply any EVM-specific information to the descriptor. 14 | 15 | :param descriptor: StateDescriptor for this state 16 | """ 17 | super()._update_state_descriptor(descriptor, *args, **kwargs) 18 | descriptor.pc = (self.platform.current_vm.address, self.platform.current_vm.pc) 19 | -------------------------------------------------------------------------------- /manticore/exceptions.py: -------------------------------------------------------------------------------- 1 | """ 2 | Public subclasses of Exception 3 | """ 4 | 5 | 6 | class ManticoreError(Exception): 7 | """ 8 | Top level Exception object for custom exception hierarchy 9 | """ 10 | 11 | pass 12 | 13 | 14 | class ExecutorError(ManticoreError): 15 | pass 16 | 17 | 18 | # Smtlib 19 | 20 | 21 | class SmtlibError(ManticoreError): 22 | pass 23 | 24 | 25 | class Z3NotFoundError(SmtlibError): 26 | pass 27 | 28 | 29 | class SolverError(SmtlibError): 30 | pass 31 | 32 | 33 | class SolverUnknown(SolverError): 34 | pass 35 | 36 | 37 | class TooManySolutions(SolverError): 38 | def __init__(self, solutions): 39 | super().__init__("Max number of different solutions hit") 40 | self.solutions = solutions 41 | 42 | 43 | # Ethereum 44 | 45 | 46 | class EthereumError(ManticoreError): 47 | pass 48 | 49 | 50 | class DependencyError(EthereumError): 51 | def __init__(self, lib_names): 52 | super().__init__( 53 | "You must pre-load and provide libraries addresses{ libname:address, ...} for %r" 54 | % lib_names 55 | ) 56 | self.lib_names = lib_names 57 | 58 | 59 | class NoAliveStates(EthereumError): 60 | pass 61 | -------------------------------------------------------------------------------- /manticore/native/__init__.py: -------------------------------------------------------------------------------- 1 | from ..utils import install_helper 2 | 3 | install_helper.ensure_native_deps() 4 | 5 | # Exports (for `from manticore.native import ...`) 6 | from .manticore import Manticore 7 | from .models import variadic 8 | from . import cpu 9 | -------------------------------------------------------------------------------- /manticore/native/cli.py: -------------------------------------------------------------------------------- 1 | from .manticore import Manticore 2 | from ..core.plugin import InstructionCounter, Visited, Tracer, RecordSymbolicBranches 3 | 4 | 5 | def native_main(args, _logger): 6 | env = {key: val for key, val in [env[0].split("=") for env in args.env]} 7 | 8 | m = Manticore( 9 | args.argv[0], 10 | argv=args.argv[1:], 11 | env=env, 12 | entry_symbol=args.entrysymbol, 13 | workspace_url=args.workspace, 14 | policy=args.policy, 15 | concrete_start=args.data, 16 | pure_symbolic=args.pure_symbolic, 17 | ) 18 | 19 | # Default plugins for now.. FIXME REMOVE! 20 | m.register_plugin(InstructionCounter()) 21 | m.register_plugin(Visited(args.coverage)) 22 | m.register_plugin(Tracer()) 23 | m.register_plugin(RecordSymbolicBranches()) 24 | 25 | if args.names is not None: 26 | m.apply_model_hooks(args.names) 27 | 28 | if args.assertions: 29 | m.load_assertions(args.assertions) 30 | 31 | @m.init 32 | def init(state): 33 | for file in args.files: 34 | state.platform.add_symbolic_file(file) 35 | 36 | with m.kill_timeout(): 37 | m.run() 38 | 39 | m.finalize() 40 | -------------------------------------------------------------------------------- /manticore/native/cpu/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/manticore/native/cpu/__init__.py -------------------------------------------------------------------------------- /manticore/native/cpu/cpufactory.py: -------------------------------------------------------------------------------- 1 | from .aarch64 import Aarch64Cpu, Aarch64CdeclAbi, Aarch64LinuxSyscallAbi 2 | from .arm import Armv7Cpu, Armv7CdeclAbi, Armv7LinuxSyscallAbi 3 | from .x86 import ( 4 | AMD64Cpu, 5 | I386Cpu, 6 | AMD64LinuxSyscallAbi, 7 | I386LinuxSyscallAbi, 8 | I386CdeclAbi, 9 | SystemVAbi, 10 | ) 11 | from .abstractcpu import Abi, Cpu, SyscallAbi 12 | 13 | 14 | class CpuFactory: 15 | _cpus = {"i386": I386Cpu, "amd64": AMD64Cpu, "armv7": Armv7Cpu, "aarch64": Aarch64Cpu} 16 | 17 | _linux_abis = { 18 | "i386": I386CdeclAbi, 19 | "amd64": SystemVAbi, 20 | "armv7": Armv7CdeclAbi, 21 | "aarch64": Aarch64CdeclAbi, 22 | } 23 | 24 | _linux_syscalls_abis = { 25 | "i386": I386LinuxSyscallAbi, 26 | "amd64": AMD64LinuxSyscallAbi, 27 | "armv7": Armv7LinuxSyscallAbi, 28 | "aarch64": Aarch64LinuxSyscallAbi, 29 | } 30 | 31 | @staticmethod 32 | def get_cpu(mem, machine: str) -> Cpu: 33 | cpu = CpuFactory._cpus[machine](mem) 34 | mem.cpu = cpu 35 | return cpu 36 | 37 | @staticmethod 38 | def get_function_abi(cpu: Cpu, os: str, machine: str) -> Abi: 39 | if os != "linux" or machine not in CpuFactory._linux_abis: 40 | raise NotImplementedError(f"OS and machine combination not supported: {os}/{machine}") 41 | 42 | return CpuFactory._linux_abis[machine](cpu) 43 | 44 | @staticmethod 45 | def get_syscall_abi(cpu: Cpu, os: str, machine: str) -> SyscallAbi: 46 | if os != "linux" or machine not in CpuFactory._linux_syscalls_abis: 47 | raise NotImplementedError(f"OS and machine combination not supported: {os}/{machine}") 48 | 49 | return CpuFactory._linux_syscalls_abis[machine](cpu) 50 | -------------------------------------------------------------------------------- /manticore/native/cpu/disasm.py: -------------------------------------------------------------------------------- 1 | from abc import abstractmethod 2 | 3 | import capstone as cs 4 | 5 | 6 | class Instruction: 7 | """Capstone-like instruction to be used internally""" 8 | 9 | @property 10 | @abstractmethod 11 | def address(self) -> int: 12 | pass 13 | 14 | @property 15 | @abstractmethod 16 | def mnemonic(self) -> str: 17 | pass 18 | 19 | @property 20 | @abstractmethod 21 | def op_str(self) -> str: 22 | pass 23 | 24 | @property 25 | @abstractmethod 26 | def size(self) -> int: 27 | pass 28 | 29 | @property 30 | @abstractmethod 31 | def operands(self): 32 | pass 33 | 34 | # FIXME (theo) eliminate one of the two of insn_name, name 35 | @property 36 | @abstractmethod 37 | def insn_name(self) -> str: 38 | pass 39 | 40 | @property 41 | @abstractmethod 42 | def name(self) -> str: 43 | pass 44 | 45 | 46 | class Disasm: 47 | """Abstract class for different disassembler interfaces""" 48 | 49 | def __init__(self, disasm): 50 | self.disasm = disasm 51 | 52 | @abstractmethod 53 | def disassemble_instruction(self, code, pc) -> Instruction: 54 | """Get next instruction based on the disassembler in use 55 | 56 | :param str code: binary blob to be disassembled 57 | :param long pc: program counter 58 | """ 59 | 60 | 61 | class CapstoneDisasm(Disasm): 62 | def __init__(self, arch, mode): 63 | try: 64 | cap = cs.Cs(arch, mode) 65 | except Exception as e: 66 | raise e 67 | cap.detail = True 68 | cap.syntax = 0 69 | super().__init__(cap) 70 | 71 | def disassemble_instruction(self, code: bytes, pc: int) -> Instruction: 72 | """Get next instruction using the Capstone disassembler 73 | 74 | :param str code: binary blob to be disassembled 75 | :param long pc: program counter 76 | """ 77 | return next(self.disasm.disasm(code, pc)) 78 | 79 | 80 | def init_disassembler(disassembler, arch, mode, view=None): 81 | if disassembler == "capstone": 82 | return CapstoneDisasm(arch, mode) 83 | else: 84 | raise NotImplementedError("Disassembler not implemented") 85 | -------------------------------------------------------------------------------- /manticore/native/cpu/register.py: -------------------------------------------------------------------------------- 1 | from copy import copy 2 | 3 | from ...core.smtlib import Operators, BitVec, Bool 4 | 5 | 6 | class Register: 7 | """ 8 | Generic variable width register. For 1 bit registers, allows writes of types 9 | bool and int, but always reads back bools. 10 | """ 11 | 12 | def __init__(self, width): 13 | self.width = width 14 | self.value = 0 15 | 16 | def is_flag(self): 17 | return self.width == 1 18 | 19 | def read(self): 20 | return self.value 21 | 22 | def write(self, val): 23 | if isinstance(val, (Bool, bool)): 24 | self.value = val 25 | elif isinstance(val, BitVec): 26 | self.value = val.Bool() if self.is_flag() else val 27 | elif isinstance(val, int): 28 | self.value = Operators.EXTRACT(val, 0, self.width) 29 | if self.is_flag(): 30 | self.value = bool(self.value) 31 | else: 32 | raise TypeError(f"Cannot store {val.__class__.__name__} in Register") 33 | -------------------------------------------------------------------------------- /manticore/platforms/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/manticore/platforms/__init__.py -------------------------------------------------------------------------------- /manticore/platforms/platform.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from functools import wraps 4 | from typing import Any, Callable, TypeVar 5 | 6 | from ..utils.event import Eventful 7 | 8 | 9 | logger = logging.getLogger(__name__) 10 | 11 | 12 | class OSException(Exception): 13 | pass 14 | 15 | 16 | T = TypeVar("T") 17 | 18 | 19 | def unimplemented(wrapped: Callable[..., T]) -> Callable[..., T]: 20 | @wraps(wrapped) 21 | def new_wrapped(self: Any, *args, **kwargs) -> T: 22 | cpu = getattr(getattr(self, "parent", None), "current", None) 23 | pc_str = "" if cpu is None else hex(cpu.read_register("PC")) 24 | logger.warning( 25 | f"Unimplemented system call: %s: %s(%s)", 26 | pc_str, 27 | wrapped.__name__, 28 | ", ".join(hex(a) if isinstance(a, int) else str(a) for a in args), 29 | ) 30 | return wrapped(self, *args, **kwargs) 31 | 32 | return new_wrapped 33 | 34 | 35 | class SyscallNotImplemented(OSException): 36 | """ 37 | Exception raised when you try to call an unimplemented system call. 38 | Go to linux.py and add an implementation! 39 | """ 40 | 41 | def __init__(self, idx, name): 42 | msg = f'Syscall index "{idx}" ({name}) not implemented.' 43 | super().__init__(msg) 44 | 45 | 46 | class Platform(Eventful): 47 | """ 48 | Base class for all platforms e.g. operating systems or virtual machines. 49 | """ 50 | 51 | _published_events = {"solve"} 52 | 53 | def __init__(self, path, **kwargs): 54 | super().__init__(**kwargs) 55 | 56 | def invoke_model(self, model, prefix_args=None): 57 | self._function_abi.invoke(model, prefix_args) 58 | 59 | def __setstate__(self, state): 60 | super().__setstate__(state) 61 | 62 | def __getstate__(self): 63 | state = super().__getstate__() 64 | return state 65 | 66 | def generate_workspace_files(self): 67 | return {} 68 | -------------------------------------------------------------------------------- /manticore/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/manticore/utils/__init__.py -------------------------------------------------------------------------------- /manticore/utils/command_line.py: -------------------------------------------------------------------------------- 1 | """ 2 | NOTE: Most of the code here is compatible/taken from Slither project ( https://github.com/trailofbits/slither ). 3 | to be compatible with it. 4 | """ 5 | from prettytable import PrettyTable 6 | 7 | from .enums import DetectorClassification 8 | 9 | classification_txt = { 10 | DetectorClassification.INFORMATIONAL: "Informational", 11 | DetectorClassification.LOW: "Low", 12 | DetectorClassification.MEDIUM: "Medium", 13 | DetectorClassification.HIGH: "High", 14 | } 15 | 16 | 17 | def output_detectors(detector_classes): 18 | """ 19 | Copied from 20 | https://github.com/trailofbits/slither/blob/563d5118298e4cae7f0ea5f2a531f0dcdcebd64d/slither/utils/command_line.py 21 | """ 22 | detectors_list = [] 23 | 24 | for detector in detector_classes: 25 | argument = detector.ARGUMENT 26 | help_info = detector.HELP 27 | impact = detector.IMPACT 28 | confidence = classification_txt[detector.CONFIDENCE] 29 | detectors_list.append((argument, help_info, impact, confidence)) 30 | 31 | table = PrettyTable(["Num", "Check", "What it Detects", "Impact", "Confidence"]) 32 | 33 | # Sort by impact, confidence, and name 34 | detectors_list = sorted( 35 | detectors_list, key=lambda element: (element[2], element[3], element[0]) 36 | ) 37 | idx = 1 38 | for (argument, help_info, impact, confidence) in detectors_list: 39 | table.add_row([idx, argument, help_info, classification_txt[impact], confidence]) 40 | idx = idx + 1 41 | 42 | print(table) 43 | -------------------------------------------------------------------------------- /manticore/utils/deprecated.py: -------------------------------------------------------------------------------- 1 | from functools import wraps 2 | import inspect 3 | import warnings 4 | 5 | # DeprecationWarning is ignored by default, so we define a subcategory that we can give a different default. 6 | 7 | 8 | class ManticoreDeprecationWarning(DeprecationWarning): 9 | """The deprecation warning class used by Manticore.""" 10 | 11 | pass 12 | 13 | 14 | warnings.simplefilter("default", category=ManticoreDeprecationWarning) 15 | 16 | 17 | def deprecated(message: str): 18 | """A decorator for marking functions as deprecated.""" 19 | assert isinstance(message, str), "The deprecated decorator requires a message string argument." 20 | 21 | def decorator(func): 22 | @wraps(func) 23 | def wrapper(*args, **kwargs): 24 | warnings.warn( 25 | f"`{func.__qualname__}` is deprecated. {message}", 26 | category=ManticoreDeprecationWarning, 27 | stacklevel=2, 28 | ) 29 | return func(*args, **kwargs) 30 | 31 | return wrapper 32 | 33 | return decorator 34 | -------------------------------------------------------------------------------- /manticore/utils/enums.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | class StateLists(Enum): 5 | """ 6 | The set of StateLists tracked in ManticoreBase 7 | """ 8 | 9 | ready = "READY" 10 | busy = "BUSY" 11 | terminated = "TERMINATED" 12 | killed = "KILLED" 13 | 14 | 15 | class StateStatus(Enum): 16 | """ 17 | Statuses that a StateDescriptor can have 18 | """ 19 | 20 | waiting_for_worker = "waiting_for_worker" 21 | waiting_for_solver = "waiting_for_solver" 22 | running = "running" 23 | #: Killed OR Terminated 24 | stopped = "stopped" 25 | #: Removed 26 | destroyed = "destroyed" 27 | 28 | 29 | class MProcessingType(Enum): 30 | """Used as configuration constant for choosing multiprocessing flavor""" 31 | 32 | multiprocessing = "multiprocessing" 33 | single = "single" 34 | threading = "threading" 35 | 36 | def title(self): 37 | return self._name_.title() 38 | 39 | @classmethod 40 | def from_string(cls, name): 41 | return cls.__members__[name] 42 | 43 | def to_class(self): 44 | return globals()[f"Manticore{self.title()}"] 45 | 46 | 47 | class Sha3Type(Enum): 48 | """Used as configuration constant for choosing sha3 flavor""" 49 | 50 | concretize = "concretize" 51 | symbolicate = "symbolicate" 52 | fake = "fake" 53 | 54 | def title(self): 55 | return self._name_.title() 56 | 57 | @classmethod 58 | def from_string(cls, name): 59 | return cls.__members__[name] 60 | 61 | 62 | class DetectorClassification(Enum): 63 | """ 64 | Shall be consistent with 65 | https://github.com/trailofbits/slither/blob/563d5118298e4cae7f0ea5f2a531f0dcdcebd64d/slither/detectors/abstract_detector.py#L11-L15 66 | """ 67 | 68 | HIGH = 0 69 | MEDIUM = 1 70 | LOW = 2 71 | INFORMATIONAL = 3 72 | -------------------------------------------------------------------------------- /manticore/utils/install_helper.py: -------------------------------------------------------------------------------- 1 | REQUIREMENTS_TO_IMPORTS = { 2 | "native": {"capstone": "capstone", "pyelftools": "elftools", "unicorn": "unicorn"} 3 | } 4 | 5 | 6 | def ensure_native_deps(): 7 | if not has_native: 8 | raise ImportError( 9 | "Missing some packages for native binary analysis. Please install them with pip3 install manticore[native]." 10 | ) 11 | 12 | 13 | def _has_deps(deps): 14 | for pkg, import_name in REQUIREMENTS_TO_IMPORTS[deps].items(): 15 | try: 16 | __import__(import_name) 17 | except ImportError: 18 | return False 19 | 20 | return True 21 | 22 | 23 | has_native = _has_deps("native") 24 | 25 | __all__ = ["ensure_native_deps", "has_native"] 26 | -------------------------------------------------------------------------------- /manticore/utils/nointerrupt.py: -------------------------------------------------------------------------------- 1 | import signal 2 | import logging 3 | 4 | 5 | class WithKeyboardInterruptAs: 6 | def __init__(self, callback): 7 | if callback is None: 8 | callback = lambda *args, **kwargs: None 9 | self.callback = callback 10 | 11 | def __enter__(self): 12 | self.signal_received = 0 13 | self.old_handler = signal.getsignal(signal.SIGINT) 14 | try: 15 | signal.signal(signal.SIGINT, self.handler) 16 | except ValueError as e: 17 | logging.debug(e) 18 | 19 | def handler(self, sig, frame): 20 | self.signal_received += 1 21 | if self.signal_received > 3: 22 | self.old_handler(sig, frame) 23 | else: 24 | self.callback() 25 | logging.debug("SIGINT received. Supressing KeyboardInterrupt.") 26 | 27 | def __exit__(self, type, value, traceback): 28 | try: 29 | signal.signal(signal.SIGINT, self.old_handler) 30 | except ValueError as e: 31 | logging.debug(e) 32 | -------------------------------------------------------------------------------- /manticore/wasm/__init__.py: -------------------------------------------------------------------------------- 1 | from .manticore import ManticoreWASM 2 | -------------------------------------------------------------------------------- /manticore/wasm/cli.py: -------------------------------------------------------------------------------- 1 | from .manticore import ManticoreWASM 2 | 3 | from ..core.plugin import Profiler 4 | from ..utils import config 5 | 6 | consts = config.get_group("cli") 7 | consts.add("profile", default=False, description="Enable worker profiling mode") 8 | consts.add("target_func", default="main", description="WASM Function to execute") 9 | 10 | 11 | def wasm_main(args, _logger): 12 | 13 | m = ManticoreWASM( 14 | args.argv[0], 15 | argv=args.argv[1:], 16 | env={}, 17 | exec_start=True, 18 | workspace_url=args.workspace, 19 | policy=args.policy, 20 | ) 21 | 22 | if consts.profile: 23 | profiler = Profiler() 24 | m.register_plugin(profiler) 25 | 26 | m.default_invoke(func_name=consts.target_func) 27 | 28 | with m.kill_timeout(): 29 | m.run() 30 | 31 | m.finalize() 32 | 33 | return m 34 | -------------------------------------------------------------------------------- /manticore/wasm/state.py: -------------------------------------------------------------------------------- 1 | from ..core.state import StateBase 2 | 3 | 4 | class State(StateBase): 5 | @property 6 | def stack(self): 7 | """ 8 | Current execution Stack 9 | """ 10 | return self._platform.stack 11 | 12 | @property 13 | def store(self): 14 | """ 15 | Current execution Store 16 | """ 17 | return self._platform.store 18 | 19 | @property 20 | def mem(self): 21 | """ 22 | The first memory in the current execution Store 23 | """ 24 | return self.store.mems[0] 25 | 26 | @property 27 | def globals(self): 28 | """ 29 | The set of globals in the current execution Store 30 | """ 31 | return self.store.globals 32 | 33 | @property 34 | def locals(self): 35 | """ 36 | The set of locals in the current execution frame. 37 | 38 | There may not be a frame on the stack if this is called at the wrong time. 39 | """ 40 | frame = self.stack.get_frame() 41 | frame = getattr(frame, "frame", frame) 42 | return frame.locals 43 | 44 | def execute(self): 45 | super().execute() 46 | return self._platform.execute(self) 47 | -------------------------------------------------------------------------------- /mypy.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | python_version = 3.7 3 | files = manticore, tests 4 | ignore_missing_imports = True 5 | 6 | # Generated file 7 | [mypy-manticore.ethereum.parsetab] 8 | ignore_errors = True 9 | 10 | [mypy-manticore.core.state_pb2] 11 | ignore_errors = True 12 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.black] 2 | target-version = ['py36'] 3 | line-length = 100 4 | extend-exclude = ''' 5 | ( 6 | venv 7 | | server # Has its own formatting 8 | ) 9 | ''' 10 | -------------------------------------------------------------------------------- /readthedocs.yml: -------------------------------------------------------------------------------- 1 | build: 2 | image: latest 3 | 4 | python: 5 | version: 3.7 6 | -------------------------------------------------------------------------------- /scripts/binaryninja/README.md: -------------------------------------------------------------------------------- 1 | ## Installation 2 | 3 | - Symlink the desired plugin into the [plugin directory](https://github.com/Vector35/binaryninja-api/tree/dev/python/examples#loading-plugins) 4 | 5 | Example: 6 | 7 | ``` 8 | ## Installation: 9 | Copy and paste the `manticore_viz` directory to the binary ninja [plugin folder](https://github.com/Vector35/binaryninja-api/tree/dev/python/examples#loading-plugins). 10 | 11 | 12 | Alternatively, you can create a symbolic link to the respective directories. 13 | E.g., in Mac OS X 14 | ``` 15 | cd ~/Library/Application\ Support/Binary\ Ninja 16 | ln -s /scripts/binaryninja/manticore_viz . 17 | ``` 18 | 19 | ## Usage 20 | 21 | - Run Manticore on a binary 22 | - Open the same binary in Binary Ninja 23 | - Select "Highlight Trace" 24 | -------------------------------------------------------------------------------- /scripts/binaryninja/manticore_viz/plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugin": { 3 | "name": "ManticoreTrace", 4 | "type": ["ui"], 5 | "api": "python2", 6 | "description": "Manticore Trace Visualization.", 7 | "longdescription": "This plugin visualizes Manticore execution traces.\n", 8 | "license": { 9 | "name": "", 10 | "text": "" 11 | }, 12 | "version": "0.0", 13 | "author": "" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /scripts/compare_traces.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | import os 4 | 5 | 6 | def compare_traces(dir1: str, dir2: str): 7 | """ 8 | Compare state traces from two mcore_* directories. 9 | 10 | For now assumes to use `test_xxxxxxx.trace` only. 11 | """ 12 | get_traces = lambda dir: [ 13 | f for f in os.listdir(dir) if f.startswith("test_") and f.endswith(".trace") 14 | ] 15 | 16 | traces1 = get_traces(dir1) 17 | traces2 = get_traces(dir2) 18 | 19 | traces1.sort() 20 | traces2.sort() 21 | 22 | print("### Comparing traces: ") 23 | print(f"dir1 - {dir1} :") 24 | print(", ".join(traces1)) 25 | print() 26 | print(f"dir2 - {dir2} :") 27 | print(", ".join(traces2)) 28 | 29 | for t1, t2 in zip(traces1, traces2): 30 | path1 = os.path.join(dir1, t1) 31 | path2 = os.path.join(dir2, t2) 32 | 33 | with open(path1) as fp1, open(path2) as fp2: 34 | if fp1.read() != fp2.read(): 35 | print(f"Files {t1} and {t2} differs.") 36 | else: 37 | print(f"Files {t1} and {t2} matches.") 38 | 39 | 40 | if __name__ == "__main__": 41 | if len(sys.argv) != 3: 42 | print(f"Usage: {sys.argv[0]} MCORE_DIR_1 MCORE_DIR_2") 43 | sys.exit() 44 | 45 | dir1, dir2 = sys.argv[1:] 46 | 47 | not_dir = lambda d: not os.path.isdir(d) 48 | 49 | if not_dir(dir1) or not_dir(dir2): 50 | print("One of passed args is not a directory!") 51 | sys.exit(-1) 52 | 53 | compare_traces(dir1, dir2) 54 | -------------------------------------------------------------------------------- /scripts/prof.py: -------------------------------------------------------------------------------- 1 | """ 2 | Script used to profile Manticore runs. 3 | """ 4 | 5 | from __future__ import print_function 6 | 7 | from sys import argv, exit 8 | 9 | from manticore.native import Manticore 10 | from manticore.core.plugin import Profiler 11 | 12 | 13 | def profile(program, sort="cumulative"): 14 | print(f'[*] Profiling program "{program}"') 15 | 16 | m = Manticore(program) 17 | profiler = Profiler() 18 | m.register_plugin(profiler) 19 | m.run() 20 | m.finalize() 21 | 22 | stats = profiler.get_profiling_data() 23 | print(f"[*] Loaded profiling data.") 24 | 25 | if stats is None: 26 | print(f"[*] Failed to collect stats for program {program}") 27 | return 28 | 29 | stats.sort_stats(sort) 30 | 31 | stats.print_stats() 32 | 33 | 34 | if __name__ == "__main__": 35 | if len(argv) != 2: 36 | print(f"usage: python {argv[0]} PROGRAM [SORT_METHOD]") 37 | print("The default SORT_METHOD is cumulative") 38 | print( 39 | "SORT_METHODs can be seen on https://docs.python.org/3/library/profile.html#pstats.Stats.sort_stats" 40 | ) 41 | exit() 42 | 43 | profile(argv[1]) 44 | -------------------------------------------------------------------------------- /scripts/pyfile_exists.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import sys 5 | 6 | # Checks whether files listed via stdin actually exist 7 | for f in sys.stdin.readlines(): 8 | line = f.strip() 9 | if line.endswith(".py") and os.path.exists(line): 10 | print(line) 11 | -------------------------------------------------------------------------------- /scripts/sandshrew/README.md: -------------------------------------------------------------------------------- 1 | # sandshrew 2 | 3 | sandshrew is a prototype concolic unit testing tool for cryptographic verification. It harnesses the [Manticore](https://github.com/trailofbits/manticore) API in order to perform unconstrained concolic execution on C cryptographic primitives. 4 | 5 | > Read more: https://blog.trailofbits.com/2019/04/01/performing-concolic-execution-on-cryptographic-primitives/ 6 | 7 | ## Usage 8 | 9 | ``` 10 | $ python sandshrew.py -h 11 | usage: sandshrew [-h] -t TEST [-c CONSTRAINT] [--debug] [--trace] 12 | [--no-concolic] [--cmpsym CMP_SYM] 13 | 14 | optional arguments: 15 | -h, --help show this help message and exit 16 | -c CONSTRAINT, --constraint CONSTRAINT 17 | Constraint to apply to symbolic input. Includes ascii, 18 | alpha, num, or alphanum 19 | --debug If set, turns on debugging output for sandshrew 20 | --trace If set, trace instruction recording will be outputted 21 | to logger 22 | --cmpsym CMP_SYM Overrides comparison function used to test for 23 | equivalence (default is strcmp) 24 | 25 | required arguments: 26 | -t TEST, --test TEST Target binary for sandshrew analysis 27 | ``` 28 | 29 | ## Example 30 | 31 | To run the sandshrew script against a sample cryptographic hash collision test case: 32 | 33 | ``` 34 | cd examples/ 35 | make & cd .. 36 | python sandshrew.py --test examples/test_openssl_md5 --debug 37 | ``` 38 | 39 | ![sandshrewgif](https://trailofbits.files.wordpress.com/2019/04/237667.cast_.gif) 40 | 41 | -------------------------------------------------------------------------------- /scripts/sandshrew/TUTORIAL.md: -------------------------------------------------------------------------------- 1 | # Tutorial 2 | 3 | Let's test sandshrew on a simple toy program, where we pit the SMT solver against a hash function, to see if we can solve for a collision. Concolic execution allows analysis to complete, due to the effective concretization of the nondeterministic hash function. 4 | 5 | Let's take a look at `examples/test_openssl_md5.c`: 6 | 7 | ```c 8 | void 9 | SANDSHREW_MD5(unsigned char * output, char * input) 10 | { 11 | MD5(input, 32, output); 12 | } 13 | 14 | 15 | int 16 | main(int argc, char *argv[]) 17 | { 18 | unsigned char in[32]; 19 | 20 | unsigned char orig_result[16]; 21 | unsigned char user_result[16]; 22 | 23 | SANDSHREW_MD5(orig_result, "s0m3_1nput_123"); 24 | SANDSHREW_MD5(user_result, argv[1]); 25 | 26 | /* if equal, we generated a hash collision! */ 27 | if (__strcmp_ssse3(orig_result, user_result) == 0) 28 | abort(); 29 | return 0; 30 | } 31 | ``` 32 | 33 | This builds the test case binary and executes sandshrew to analyze it while outputting debug information: 34 | 35 | ``` 36 | $ cd tests/ && make test_openssl_md5 37 | $ sandshrew -t test_openssl_md5 --debug 38 | ``` 39 | -------------------------------------------------------------------------------- /scripts/sandshrew/WRITING_TEST_CASES.md: -------------------------------------------------------------------------------- 1 | # Writing Test Cases 2 | 3 | Writing a test case is fairly flexible (no APIs), but should adhere to the follow C-pseudocode format seen below. Read the annotated comments to better understand the design choice. 4 | 5 | ```c 6 | #include 7 | #include 8 | 9 | /* sandshrew will parse out wrapper functions prepended with SANDSHREW_*, 10 | * and concretely execute them during SE runtime. Wrapper functions must also: 11 | * 12 | * 1. Pass output and input through arg1 and arg2 respectively 13 | * 2. Return `void`. 14 | */ 15 | 16 | void SANDSHREW_benchmark_encrypt(out, in, len, ...) { 17 | benchmark_encrypt(in, len, out); 18 | } 19 | 20 | /* Differing libraries will use calling conventions for their primitives, based on design choices made by 21 | * devs. As long as a wrapper function exists for a primitive being tested, sandshrew will be able to reason 22 | * parameters through a uniform convention (`out`, `in`, and other args). 23 | */ 24 | 25 | void SANDSHREW_my_encrypt(out, in, len) { 26 | my_encrypt(out, len); 27 | } 28 | 29 | 30 | int main(int argc, char *argv[]) 31 | { 32 | /* sandshrew passes in symbolic input in argv[1] */ 33 | symbolic_input = argv[1]; 34 | 35 | /* get result from a benchmark primitive (ideally should be verified) */ 36 | SANDSHREW_benchmark_encrypt(out1, symbolic_input, 32, /* other args */); 37 | 38 | /* get result from the primitive being tested */ 39 | SANDSHREW_my_encrypt(out2, symbolic_input, 32, /* other args */); 40 | 41 | /* test for equivalence using strcmp 42 | * NOTE: implementation must use *_cmp and abort for 43 | * proper Manticore hooking and instrumentation 44 | */ 45 | if (strcmp(out1, out2) != 0) 46 | abort(); 47 | } 48 | ``` 49 | 50 | ### Compiling 51 | 52 | Once complete, compile the C file into a binary normally, passing in the appropriate header directories and linker flags. 53 | 54 | ``` 55 | $ gcc -g -m64 -Iinclude -o test1 test.c -llib1 -llib2 56 | $ sandshrew --test test1 --debug 57 | ``` 58 | -------------------------------------------------------------------------------- /scripts/sandshrew/examples/Makefile: -------------------------------------------------------------------------------- 1 | ###################################################### 2 | CC = gcc 3 | 4 | IFLAGS = -Iinclude 5 | 6 | CFLAGS = -g -Wall 7 | LFLAGS = -shared -fPIC 8 | 9 | OPENSSL_LFLAGS = -lcrypto -lssl 10 | ###################################################### 11 | 12 | all: test_openssl_md5 test_openssl_bnsqr test_tweetnacl_scalarmult test_monocypher_eddsa 13 | 14 | init: 15 | mkdir include/ 16 | 17 | test_openssl_md5: test_openssl_md5.c 18 | $(CC) $(CFLAGS) -static -o $@ $< $(OPENSSL_LFLAGS) 19 | 20 | 21 | test_openssl_bnsqr: test_openssl_bnsqr.c 22 | $(CC) $(CFLAGS) -o $@ $< $(OPENSSL_LFLAGS) 23 | 24 | 25 | test_tweetnacl_scalarmult: test_tweetnacl_scalarmult.c 26 | $(CC) $(CFLAGS) -static -o $@ $< 27 | 28 | clean: 29 | rm -rf ../mcore_*/ 30 | rm test_openssl_md5 test_openssl_bnsqr test_tweetnacl_scalarmult 31 | -------------------------------------------------------------------------------- /scripts/sandshrew/examples/test_openssl_bnsqr.c: -------------------------------------------------------------------------------- 1 | /* test_openssl_bnsqr.c 2 | * 3 | * Tests: 4 | * OpenSSL Bignum Squaring 5 | * 6 | * Description: 7 | * Tests invariance between sqr and self-multiplication 8 | * in OpenSSL BN_sqr() implementation. 9 | * 10 | * NOTE: OpenSSL is a hard library for sandshrew tests to 11 | * scale to. SMT timeouts will most likely incur. 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | void SANDSHREW_BN_sqr(BIGNUM *result, BIGNUM *input, BN_CTX *ctx) 19 | { 20 | BN_sqr(result, input, ctx); 21 | } 22 | 23 | 24 | void SANDSHREW_BN_mul(BIGNUM *result, BIGNUM *input, BN_CTX *ctx) 25 | { 26 | BN_mul(result, input, input, ctx); 27 | } 28 | 29 | 30 | int 31 | main(int argc, char *argv[]) 32 | { 33 | BN_CTX *ctx = BN_CTX_new(); 34 | BIGNUM *x = BN_new(); 35 | BIGNUM *r1 = BN_new(); 36 | BIGNUM *r2 = BN_new(); 37 | 38 | BN_bin2bn(argv[1], 32, x); 39 | 40 | /* test for invariance between mult and sqr */ 41 | SANDSHREW_BN_sqr(r1, x, ctx); 42 | SANDSHREW_BN_mul(r2, x, ctx); 43 | 44 | if (BN_cmp(r1, r2) != 0) 45 | abort(); 46 | 47 | /* unsafe: no frees */ 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /scripts/sandshrew/examples/test_openssl_md5.c: -------------------------------------------------------------------------------- 1 | /* test_openssl_md5.c 2 | * 3 | * Tests: 4 | * OpenSSL MD5 5 | * 6 | * Description: 7 | * This is a test case that utilizes concolic execution 8 | * to determine an input that produces the same hash as a fixed 9 | * concrete input (aka a 'Birthday Attack'), resulting in a hash 10 | * collision. 11 | * 12 | * Results: 13 | * Getting a viable solution (a working concrete input OR the original plaintext) 14 | * is probabilistic. Complex SMT queries during runtime remain problematic. 15 | * 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | 24 | /* create a SANDSHREW_* wrapper over OpenSSL's MD5 for concretization */ 25 | void 26 | SANDSHREW_MD5(unsigned char * output, char * input) 27 | { 28 | MD5(input, 32, output); 29 | } 30 | 31 | 32 | int 33 | main(int argc, char *argv[]) 34 | { 35 | unsigned char in[32]; 36 | 37 | unsigned char orig_result[16]; 38 | unsigned char user_result[16]; 39 | 40 | SANDSHREW_MD5(orig_result, "s0m3_1nput_123"); 41 | SANDSHREW_MD5(user_result, argv[1]); 42 | 43 | /* if equal, we generated a hash collision! */ 44 | if (__strcmp_ssse3(orig_result, user_result) == 0) 45 | abort(); 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /server/.gitignore: -------------------------------------------------------------------------------- 1 | manticore_server.egg-info/** 2 | **/__pycache__ 3 | dist/** 4 | .mypy_cache/** 5 | -------------------------------------------------------------------------------- /server/README.md: -------------------------------------------------------------------------------- 1 | # Manticore Server 2 | Manticore Server is a gRPC service that acts as a wrapper around [Manticore](https://github.com/trailofbits/manticore), to support projects like the [Manticore User Interface (MUI)](https://github.com/trailofbits/ManticoreUI). Manticore Server is designed to allow developers to more easily create tools around Manticore that aren't in Python or to allow for Manticore to be run and managed in the cloud/remotely. 3 | 4 | ❗NOTE❗: The server is not published or packaged anywhere and is intended to be installed from source in a clean Python virtual environment. The server is only tested for compatibility with the version of Manticore living in the parent directory; this version of Manticore is installed when installing the server. 5 | 6 | # Usage 7 | Create a new Python virtual environment: 8 | 9 | ```bash 10 | python3 -m venv venv 11 | source venv/bin/activate 12 | ``` 13 | 14 | Install the server with `pip install .`. This will install Manticore from the parent directory. 15 | 16 | The Manticore Server can be run via `manticore_server`, and it will run on port `50010`. 17 | 18 | Your Manticore Server client will require the relevant gRPC client code. You can find out how to generate gRPC client code in your desired language from [the gRPC website](https://grpc.io/docs/languages/). 19 | 20 | You may refer to the [Protobuf Specification](manticore_server/ManticoreServer.proto) for information about the RPC services provided and the message types. 21 | -------------------------------------------------------------------------------- /server/justfile: -------------------------------------------------------------------------------- 1 | init: 2 | test -d venv || python3 -m venv venv 3 | . venv/bin/activate; pip install -U setuptools pip wheel; pip install -e .[dev] 4 | 5 | format: 6 | black . 7 | isort . 8 | 9 | lint: 10 | black --check . 11 | isort --check . 12 | mypy 13 | 14 | generate: 15 | python3 setup.py generate 16 | 17 | build: generate 18 | #!/usr/bin/env bash 19 | set -euo 20 | mkdir -p dist 21 | py_ver=$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")') 22 | python3 -m shiv -c manticore_server -o dist/manticore_server --reproducible --no-modify --python "/usr/bin/env python${py_ver}" --compressed . 23 | 24 | test: 25 | python3 -m unittest tests/test_*.py 26 | -------------------------------------------------------------------------------- /server/manticore_server/__init__.py: -------------------------------------------------------------------------------- 1 | from . import manticore_server 2 | -------------------------------------------------------------------------------- /server/manticore_server/introspect_plugin.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from datetime import datetime 3 | 4 | from manticore.core.plugin import IntrospectionAPIPlugin, StateDescriptor 5 | from manticore.core.state import StateBase 6 | from manticore.utils.enums import StateLists 7 | 8 | logger = logging.getLogger(__name__) 9 | 10 | 11 | class ManticoreServerIntrospectionPlugin(IntrospectionAPIPlugin): 12 | NAME = "ManticoreServerIntrospectionPlugin" 13 | 14 | @property 15 | def name(self) -> str: 16 | return "ManticoreServerIntrospectionPlugin" 17 | 18 | def create_state(self, state_id: int): 19 | """Override create_state to force a state update right after creation. 20 | This is helpful when retrieving info from a state yet to execute.""" 21 | super().create_state(state_id) 22 | state = self.manticore._load(state_id) 23 | self._force_update_state_descriptor(state) 24 | 25 | def will_fork_state_callback(self, state: StateBase, expression, solutions, policy): 26 | self._force_update_state_descriptor(state) 27 | 28 | def will_transition_state_callback( 29 | self, state_id: int, from_list: StateLists, to_list: StateLists 30 | ): 31 | state = self.manticore._load(state_id) 32 | self._force_update_state_descriptor(state) 33 | 34 | def _force_update_state_descriptor(self, state: StateBase): 35 | """Force a given state to update its information, which can include the current PC, etc. 36 | Calling _update_state_descriptor directly may become an issue if specific state implementations 37 | start to require additional arguments for this method.""" 38 | with self.locked_context("manticore_state", dict) as context: 39 | state._update_state_descriptor( 40 | context.setdefault(state.id, StateDescriptor(state_id=state.id)), 41 | ) 42 | context[state.id].last_intermittent_update = datetime.now() 43 | 44 | def did_terminate_worker_callback(self, worker_id: int): 45 | logger.debug(f"worker exits (id: {worker_id})") 46 | -------------------------------------------------------------------------------- /server/manticore_server/native_plugin.py: -------------------------------------------------------------------------------- 1 | from manticore.core.plugin import Plugin 2 | 3 | 4 | class UnicornEmulatePlugin(Plugin): 5 | """Manticore plugin to speed up emulation using unicorn until `start`""" 6 | 7 | def __init__(self, start: int): 8 | super().__init__() 9 | self.start = start 10 | 11 | def will_run_callback(self, ready_states): 12 | for state in ready_states: 13 | state.cpu.emulate_until(self.start) 14 | -------------------------------------------------------------------------------- /server/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | # Minimum requirements for the build system to execute. 3 | requires = ["setuptools>=49.0.0", "wheel"] # PEP 518 specifications. 4 | 5 | [tool.mypy] 6 | files = ["manticore_server", "tests"] 7 | ignore_missing_imports = true 8 | warn_redundant_casts = true 9 | warn_unused_ignores = true 10 | warn_unreachable = true 11 | 12 | [tool.isort] 13 | profile = "black" 14 | skip = ["venv", "build", "manticore_server/ManticoreServer_pb2.py", "manticore_server/ManticoreServer_pb2_grpc.py"] 15 | 16 | [tool.black] 17 | line-length = 88 18 | extend-exclude = ''' 19 | ManticoreServer_pb2_grpc\.py 20 | | ManticoreServer_pb2\.py 21 | | ManticoreServer_pb2\.pyi 22 | | venv 23 | ''' 24 | -------------------------------------------------------------------------------- /server/setup.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | from setuptools import Command, find_packages, setup 4 | 5 | 6 | class GenerateCommand(Command): 7 | description = "generates manticore_server server protobuf + grpc code from protobuf specification file" 8 | user_options = [] 9 | 10 | def initialize_options(self): 11 | pass 12 | 13 | def finalize_options(self): 14 | pass 15 | 16 | def run(self): 17 | from grpc.tools import protoc 18 | 19 | protoc.main( 20 | [ 21 | "grpc_tools.protoc", 22 | "-I.", 23 | "--python_out=.", 24 | "--grpc_python_out=.", 25 | "--mypy_out=.", 26 | "./manticore_server/ManticoreServer.proto", 27 | ] 28 | ) 29 | 30 | 31 | PB_VER = 3.20 32 | 33 | setup( 34 | name="manticore_server", 35 | version="0.0.1", 36 | packages=find_packages(exclude=["tests", "tests.*"]), 37 | python_requires=">=3.7", 38 | install_requires=[ 39 | f"manticore[native] @ file://{Path(__file__).parent.resolve()}/..", 40 | f"protobuf~={PB_VER}", 41 | "grpcio~=1.46", 42 | "crytic-compile>=0.2.2", 43 | ], 44 | extras_require={ 45 | "dev": [ 46 | "grpcio-tools", 47 | "mypy-protobuf", 48 | f"types-protobuf~={PB_VER}", 49 | "shiv~=1.0.1", 50 | "types-setuptools", 51 | "black~=22.0", 52 | "isort==5.10.1", 53 | "mypy==0.942", 54 | ] 55 | }, 56 | entry_points={ 57 | "console_scripts": [ 58 | "manticore_server=manticore_server.manticore_server:main", 59 | ], 60 | "distutils.commands": ["generate = GenerateCommand"], 61 | }, 62 | cmdclass={ 63 | "generate": GenerateCommand, 64 | }, 65 | ) 66 | -------------------------------------------------------------------------------- /server/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/server/tests/__init__.py -------------------------------------------------------------------------------- /server/tests/contracts/adder.sol: -------------------------------------------------------------------------------- 1 | contract Adder { 2 | function incremented(uint value) public returns (uint){ 3 | if (value == 1) 4 | revert(); 5 | return value + 1; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /server/tests/mock_classes.py: -------------------------------------------------------------------------------- 1 | import grpc 2 | from grpc._server import _Context 3 | 4 | 5 | class MockContext(_Context): 6 | def __init__(self) -> None: 7 | self.code: grpc.StatusCode = grpc.StatusCode.OK 8 | self.details: str = "" 9 | 10 | def set_details(self, details: str) -> None: 11 | self.details = details 12 | 13 | def set_code(self, code: grpc.StatusCode) -> None: 14 | self.code = code 15 | 16 | def reset(self): 17 | self.code: grpc.StatusCode = grpc.StatusCode.OK 18 | self.details: str = "" 19 | -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | ## Tests 2 | 3 | Please DO NOT create directories in tests/ as we run separate directories in separate test jobs **and this is done explicitly in .github/workflows/ci.yml** (unless you change that file too). 4 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | This file is requires so that unittest will be able to discover tests in children directories. 3 | """ 4 | -------------------------------------------------------------------------------- /tests/auto_generators/Readme.md: -------------------------------------------------------------------------------- 1 | Auto unittest generation 2 | ------------------------ 3 | 4 | 1) You need a Linux program that exercises a set of interesting instructions. 5 | For instance try `make` in examples/linux. 6 | 7 | 2) Run the tracer on your program. It is a gdb wrapper that will execute the program step by step 8 | printing pre/pos information on each instruction: 9 | 10 | ``` 11 | python make_dump.py ../../examples/linux/nostdlib32 > mytest.dump 12 | ``` 13 | (Several dumps can be concatenated together) 14 | 15 | 3) Generate the actual python unittest based on the dump. 16 | ``` 17 | python make_tests.py mytest.dump > SymbolicExecutor/tests/test_example.py 18 | ``` 19 | This will get up to 1000 testcases for the same mnemonic in the dump. 20 | 21 | 4) Run the test: 22 | ``` 23 | python -m unittest -c test_example 24 | ``` 25 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from manticore.utils import log 4 | 5 | 6 | @pytest.fixture(scope="session", autouse=True) 7 | def initialize_manticore_logging(request): 8 | """Initialize Manticore's logger for all tests""" 9 | log.init_logging() 10 | -------------------------------------------------------------------------------- /tests/ethereum/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | This file is requires so that unittest will be able to discover tests in children directories. 3 | """ 4 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/1102.sol: -------------------------------------------------------------------------------- 1 | //Single transaction overflow 2 | //Post-transaction effect: overflow escapes to publicly-readable storage 3 | 4 | pragma solidity ^0.4.19; 5 | 6 | contract IntegerOverflowMinimal { 7 | uint public count = 1; 8 | 9 | function run(uint256 input) public { 10 | count -= input; 11 | } 12 | } -------------------------------------------------------------------------------- /tests/ethereum/contracts/676.sol: -------------------------------------------------------------------------------- 1 | contract C { 2 | uint public n=0; 3 | function f() public{ 4 | n = block.number; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/678.sol: -------------------------------------------------------------------------------- 1 | contract C { 2 | function f() public returns(bytes32){ 3 | return "abc"; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/701.sol: -------------------------------------------------------------------------------- 1 | contract C { 2 | 3 | function reveal(uint x, bytes32 hash) returns (bool) { 4 | if (sha3(x) == hash) { 5 | return true; 6 | } 7 | 8 | return false; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/705.sol: -------------------------------------------------------------------------------- 1 | import "imp.sol"; 2 | 3 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/714.sol: -------------------------------------------------------------------------------- 1 | contract C { 2 | function() { 3 | if (msg.data[0] == 1) { 4 | return; 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/735.sol: -------------------------------------------------------------------------------- 1 | contract SS { 2 | address recvr; 3 | function setme() { 4 | recvr = msg.sender; 5 | } 6 | function sui() { 7 | suicide(recvr); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/760.sol: -------------------------------------------------------------------------------- 1 | contract TEST { 2 | function Test_SignedInteger_AdditionOverflow(int x) public { 3 | int y = x + x; 4 | assert(y > 0); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/780.sol: -------------------------------------------------------------------------------- 1 | contract C { 2 | function C(bool x) { 3 | return; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/795.sol: -------------------------------------------------------------------------------- 1 | contract Simple { 2 | function f(uint a) payable public { 3 | if (a == 65) { 4 | revert(); 5 | } 6 | } 7 | } -------------------------------------------------------------------------------- /tests/ethereum/contracts/799.sol: -------------------------------------------------------------------------------- 1 | contract X { function X(address x) {} } 2 | contract C { function C(address x) { new X(x); } } 3 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/807.sol: -------------------------------------------------------------------------------- 1 | contract X { 2 | mapping(address => uint) private balance; 3 | function f(address z) returns (uint) { return balance[z]; } 4 | } 5 | contract C { 6 | X y; 7 | function C() { 8 | y = new X(); 9 | uint z = y.f(0); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/808.sol: -------------------------------------------------------------------------------- 1 | library X { 2 | function f(uint z) returns (uint) { return 2*z; } 3 | } 4 | contract C { 5 | function C() { 6 | uint z = X.f(0); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/absurdrepetition.sol: -------------------------------------------------------------------------------- 1 | contract AR { 2 | event Log(string); 3 | uint public a; 4 | uint public b; 5 | uint public c; 6 | 7 | function writea(uint wad) public { 8 | a=wad; 9 | } 10 | function writeb(uint wad) public { 11 | if (a==10){ 12 | b=wad; 13 | } 14 | } 15 | function writec(uint wad) public { 16 | if (b==10){ 17 | c=wad; 18 | } 19 | } 20 | function done() public { 21 | if (c==10){ 22 | emit Log("Done!"); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/detectors/balance_not_ok.sol: -------------------------------------------------------------------------------- 1 | contract DetectThis { 2 | event Log(string); 3 | function foo() payable public{ 4 | uint256 eth2; 5 | uint256 eth = msg.value; 6 | eth2 = address(msg.sender).balance; 7 | if(eth2 == eth){ 8 | emit Log("Found a bug"); 9 | } 10 | } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/detectors/balance_ok.sol: -------------------------------------------------------------------------------- 1 | contract DetectThis { 2 | event Log(string); 3 | function foo() payable public{ 4 | uint256 eth2; 5 | uint256 eth = msg.value; 6 | eth2 = address(msg.sender).balance; 7 | if(eth2 >= eth){ 8 | emit Log("Found a bug"); 9 | } 10 | } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/detectors/delegatecall_not_ok.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | /* 3 | There is a dangerous use of lowlevel instruction delegatecall in the fallback function. 4 | The address to which the delegatecall tx is sent is controlled by any user of this contract. 5 | The storage variable `addr` is initialized to `this` and it CAN be modified. 6 | The function selector of the delegate call is fully controlled by the user 7 | */ 8 | 9 | contract DetectThis { 10 | address addr; 11 | constructor(){ 12 | addr = address(this); 13 | } 14 | function setaddr(address a){ 15 | addr = a; 16 | } 17 | 18 | function default_call(bytes data) public { 19 | require(msg.sender == address(this)); 20 | //do legal stuff on bytes 21 | } 22 | 23 | function () public { 24 | require(addr.delegatecall(msg.data)); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/detectors/delegatecall_not_ok1.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | /* 3 | There is a dangerous use of lowlevel instruction delegatecall in the fallback function. 4 | The target address of the delegatecall hardcoded function selector of the delegate 5 | call is fully controlled by the user. 6 | */ 7 | 8 | contract DetectThis { 9 | address addr; 10 | constructor(){ 11 | addr = address(this); 12 | } 13 | function setaddr(address a){ 14 | addr = a; 15 | } 16 | 17 | function default_call(bytes data) public { 18 | require(msg.sender == address(this)); 19 | //do legal stuff on bytes 20 | } 21 | 22 | function f() public { 23 | require(msg.data.length >=4); 24 | uint i; 25 | bytes memory new_calldata = new bytes(msg.data.length-4); 26 | 27 | for (i=0; i < msg.data.length-4; i++) { 28 | new_calldata[i] = msg.data[i+4]; 29 | } 30 | 31 | require(address(0x41414141).delegatecall(new_calldata)); 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/detectors/delegatecall_ok.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | /* 3 | A fair use of delegatecall instruction is inserted by the solidity compiler for 4 | implementing libraries. This is an ok use of delegatecall. 5 | */ 6 | pragma solidity ^0.4.24; 7 | 8 | library Lib { 9 | 10 | struct Data {uint val;} 11 | 12 | function set(Data storage self, uint new_val) public{ 13 | self.val = new_val; 14 | } 15 | } 16 | 17 | contract DetectThis { 18 | Lib.Data public myVal; 19 | 20 | function () public payable{ 21 | Lib.set(myVal, msg.value); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/detectors/delegatecall_ok1.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | /* 3 | There is a fair use of lowlevel instruction delegatecall in the fallback function. 4 | It is effectively a CALL to `default_call` with the full calldata that was given to the fallback function 5 | */ 6 | contract DetectThis { 7 | 8 | function default_call(bytes data) public { 9 | require(msg.sender == address(this)); 10 | //do legal stuff on bytes 11 | } 12 | 13 | function () public { 14 | bool retval = address(this).delegatecall(bytes4(keccak256("default_call(bytes)")), msg.data); 15 | require(retval); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/detectors/delegatecall_ok2.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | /* 3 | There is a fair use of lowlevel instruction delegatecall in the fallback function. 4 | It is effectively a CALL to `this.default_call` with a concrete data. 5 | The storage variable `addr` is initialized to `this` and can not be modified. 6 | */ 7 | 8 | contract DetectThis { 9 | address addr; 10 | constructor(){ 11 | addr = address(this); 12 | } 13 | 14 | function default_call(bytes data) public { 15 | require(msg.sender == address(this)); 16 | //do legal stuff on bytes 17 | } 18 | 19 | function () public { 20 | bool retval = addr.delegatecall(bytes4(keccak256("default_call(bytes)")), "Concrete values!"); 21 | require(retval); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/detectors/delegatecall_ok3.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | /* 3 | There is a dangerous use of lowlevel instruction delegatecall in the fallback function. 4 | The address to which the delegatecall tx is sent is controlled by any user of this contract. 5 | The storage variable `addr` is initialized to `this` and it CAN be modified. 6 | The function selector of the delegate call is fully controlled by the user 7 | */ 8 | 9 | contract DetectThis { 10 | address addr; 11 | constructor() public{ 12 | addr = address(this); 13 | } 14 | 15 | function default_call(bytes data) public { 16 | require(msg.sender == address(this)); 17 | //do legal stuff on bytes 18 | } 19 | 20 | function () public { 21 | require(msg.data.length > 4); 22 | uint i; 23 | bytes memory new_calldata = new bytes(msg.data.length); 24 | bytes4 func_id = bytes4(keccak256("default_call(bytes)")); 25 | for (i=0; i < 4; i++) { 26 | new_calldata[i] = func_id[i]; 27 | } 28 | 29 | for (; i < msg.data.length; i++) { 30 | new_calldata[i] = msg.data[i]; 31 | } 32 | 33 | require(address(this).delegatecall(new_calldata)); 34 | 35 | } 36 | } 37 | 38 | 39 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/detectors/etherleak_true_neg.sol: -------------------------------------------------------------------------------- 1 | /* 2 | Example contract - True Negative 3 | The ether leak is not reachable by non-creator and there is no way to set 4 | yourself as the owner. 5 | 6 | This should NOT report a finding. 7 | */ 8 | 9 | pragma solidity ^0.4.24; 10 | 11 | contract DetectThis { 12 | 13 | address private owner; 14 | 15 | modifier onlyOwner() { 16 | require(msg.sender == owner); 17 | _; 18 | } 19 | 20 | constructor () { 21 | owner = msg.sender; 22 | } 23 | 24 | function () payable { // makes it possible for contract to have balance > 0 25 | } 26 | 27 | function withdrawfunds() onlyOwner { 28 | msg.sender.transfer(this.balance); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/detectors/etherleak_true_neg1.sol: -------------------------------------------------------------------------------- 1 | /* 2 | Example contract - True Negative, Potential false positive 3 | The ether leak is not reachable by non-creator and there is no way to set 4 | yourself as the owner. 5 | 6 | This should NOT report a finding. 7 | */ 8 | 9 | pragma solidity ^0.4.24; 10 | 11 | contract DetectThis { 12 | 13 | address private owner; 14 | 15 | modifier onlyOwner() { 16 | require(msg.sender == owner); 17 | _; 18 | } 19 | 20 | function fakeconstructor () { // writes to owner storage, but not exploitably 21 | owner = 2; 22 | } 23 | 24 | function () payable { // makes it possible for contract to have balance > 0 25 | } 26 | 27 | function withdrawfunds() onlyOwner { 28 | msg.sender.transfer(this.balance); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/detectors/etherleak_true_neg2.sol: -------------------------------------------------------------------------------- 1 | /* 2 | Example contract - True Negative 3 | The ether leak is reachable by non-creator if you set yourself as the owner, BUT the balance 4 | can never be > 0. 5 | 6 | This should NOT report a finding. 7 | */ 8 | 9 | pragma solidity ^0.4.24; 10 | 11 | contract DetectThis { 12 | 13 | address private owner; 14 | 15 | modifier onlyOwner() { 16 | require(msg.sender == owner); 17 | _; 18 | } 19 | 20 | function fakeconstructor() { 21 | owner = msg.sender; 22 | } 23 | 24 | function withdrawfunds() onlyOwner { 25 | msg.sender.transfer(this.balance); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/detectors/etherleak_true_neg3.sol: -------------------------------------------------------------------------------- 1 | /* 2 | Example contract - True Negative, Potential false positive 3 | The ether leak is reachable by non-creator if you set yourself as the owner, and the 4 | balance can be > 0, but only 0 can ever be sent. 5 | 6 | This should NOT report a finding. 7 | */ 8 | 9 | pragma solidity ^0.4.24; 10 | 11 | contract DetectThis { 12 | 13 | address private owner; 14 | 15 | modifier onlyOwner() { 16 | require(msg.sender == owner); 17 | _; 18 | } 19 | 20 | function fakeconstructor() payable { 21 | owner = msg.sender; 22 | } 23 | 24 | function withdrawfunds() onlyOwner { 25 | if (this.balance == 0) { 26 | msg.sender.transfer(this.balance); 27 | } 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/detectors/etherleak_true_pos_argument.sol: -------------------------------------------------------------------------------- 1 | /* 2 | Example contract - True Positive 3 | The argument ether leak is reachable by non-creator if you set yourself as the owner. 4 | 5 | This should report a finding. 6 | */ 7 | 8 | pragma solidity ^0.4.24; 9 | 10 | contract DetectThis { 11 | 12 | address private owner; 13 | 14 | modifier onlyOwner() { 15 | require(msg.sender == owner); 16 | _; 17 | } 18 | 19 | function fakeconstructor() payable { // makes it possible for contract to have balance > 0 20 | owner = msg.sender; 21 | } 22 | 23 | function withdrawfunds(address attacker) onlyOwner { 24 | attacker.transfer(this.balance); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/detectors/etherleak_true_pos_argument1.sol: -------------------------------------------------------------------------------- 1 | /* 2 | Example contract - True Positive, Potential false negative 3 | The ether leak is reachable by non-creator if you set yourself as the owner by exploiting 4 | the set() function. 5 | 6 | NOTE: this currently requires the LoopDepthLimiter plugin to find quickly. This is due to the 7 | assignment to map.length. 8 | 9 | This should report a finding. 10 | */ 11 | 12 | pragma solidity ^0.4.24; 13 | 14 | contract DetectThis { 15 | 16 | address private owner; 17 | uint256[] map; 18 | 19 | modifier onlyOwner() { 20 | require(msg.sender == owner); 21 | _; 22 | } 23 | 24 | function set(uint256 key, uint256 value) public payable { // you can use this to overwrite owner // makes it possible for contract to have balance > 0 25 | // Expand dynamic array as needed 26 | if (map.length <= key) { 27 | map.length = key + 1; 28 | } 29 | 30 | map[key] = value; 31 | } 32 | 33 | function withdrawfunds(address attacker) onlyOwner { 34 | attacker.transfer(this.balance); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/detectors/etherleak_true_pos_argument2.sol: -------------------------------------------------------------------------------- 1 | /* 2 | Example contract - True Positive 3 | The argument ether leak is reachable by non-creator if you set yourself as the owner. 4 | 5 | This should report a finding. 6 | */ 7 | 8 | pragma solidity ^0.4.24; 9 | 10 | contract DetectThis { 11 | 12 | address private owner; 13 | 14 | modifier onlyOwner() { 15 | require(msg.sender == owner); 16 | _; 17 | } 18 | 19 | function fakeconstructor() payable { // makes it possible for contract to have balance > 0 20 | owner = msg.sender; 21 | } 22 | 23 | function withdrawfunds(address attacker) onlyOwner { 24 | if (attacker != msg.sender) { 25 | attacker.transfer(this.balance); 26 | } 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/detectors/etherleak_true_pos_msgsender.sol: -------------------------------------------------------------------------------- 1 | /* 2 | Example contract - True Positive 3 | The ether leak is reachable by non-creator if you set yourself as the owner. 4 | 5 | This should report a finding. 6 | */ 7 | 8 | pragma solidity ^0.4.24; 9 | 10 | contract DetectThis { 11 | 12 | address private owner; 13 | 14 | modifier onlyOwner() { 15 | require(msg.sender == owner); 16 | _; 17 | } 18 | 19 | function fakeconstructor() payable { // makes it possible for contract to have balance > 0 20 | owner = msg.sender; 21 | } 22 | 23 | function withdrawfunds() onlyOwner { 24 | msg.sender.transfer(this.balance); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/detectors/etherleak_true_pos_msgsender1.sol: -------------------------------------------------------------------------------- 1 | /* 2 | Example contract - True Positive, Potential false negative 3 | The ether leak is reachable by non-creator if you set yourself as the owner by exploiting 4 | the set() function. 5 | 6 | NOTE: this currently requires the LoopDepthLimiter plugin to find quickly. This is due to the 7 | assignment to map.length. 8 | 9 | This should report a finding. 10 | */ 11 | 12 | pragma solidity ^0.4.24; 13 | 14 | contract DetectThis { 15 | 16 | address private owner; 17 | uint256[] map; 18 | 19 | modifier onlyOwner() { 20 | require(msg.sender == owner); 21 | _; 22 | } 23 | 24 | function set(uint256 key, uint256 value) public payable { // you can use this to overwrite owner // makes it possible for contract to have balance > 0 25 | // Expand dynamic array as needed 26 | if (map.length <= key) { 27 | map.length = key + 1; 28 | } 29 | 30 | map[key] = value; 31 | } 32 | 33 | function withdrawfunds() onlyOwner { 34 | msg.sender.transfer(this.balance); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/detectors/predictable_not_ok.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | /* 3 | Example contract - True Negative 4 | The return value of a low level call IS checked via solidity injected code. 5 | This should NOT report a finding. 6 | */ 7 | contract DetectThis { 8 | uint secret = 0; 9 | 10 | function callchecked() public returns (uint256){ 11 | uint old_secret = secret; 12 | uint current_block_timestamp = now; 13 | uint current_block_coinbase = uint(block.coinbase); 14 | uint current_block_difficulty = block.difficulty; 15 | uint current_block_number = block.number; 16 | uint current_block_blockhash = uint(blockhash(block.number-1)); 17 | uint tx_origin = uint(tx.origin); 18 | uint tx_gasprice = tx.gasprice; 19 | uint current_block_gaslimit = block.gaslimit; 20 | secret = current_block_timestamp ^ current_block_coinbase ^ current_block_difficulty ^ current_block_number ^ current_block_blockhash ^ tx_origin ^ tx_gasprice ^ current_block_gaslimit; 21 | return old_secret; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/detectors/race_condition.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.19; 2 | /* 3 | Example contract - True Positive 4 | There can be a race condition between storing an address with `setStoredAddress` 5 | and using it in `callStoredAddress`. 6 | 7 | An attacker seeing a `setStoredAddress` that is supposed to "change something important" 8 | might send a tx with more gas and execute `callStoredAddress` before one changes the state.sss 9 | 10 | This should report a finding. 11 | */ 12 | 13 | contract DetectThis { 14 | address public stored_address; 15 | 16 | function callStoredAddress() { 17 | stored_address.call(); 18 | } 19 | 20 | function setStoredAddress(address addr) { 21 | stored_address = addr; 22 | } 23 | } -------------------------------------------------------------------------------- /tests/ethereum/contracts/detectors/race_condition2.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.19; 2 | /* 3 | Example contract - True Positive 4 | 5 | Taken from https://consensys.github.io/smart-contract-best-practices/known_attacks/#cross-function-race-conditions 6 | 7 | In this case, the attacker calls transfer() when their code is executed on the external call in withdrawBalance. 8 | Since their balance has not yet been set to 0, they are able to transfer the tokens even though they already 9 | received the withdrawal. This vulnerability was also used in the DAO attack. 10 | 11 | This should report a finding. 12 | */ 13 | 14 | contract DetectThis { 15 | mapping (address => uint) private userBalances; 16 | 17 | function transfer(address to, uint amount) { 18 | if (userBalances[msg.sender] >= amount) { 19 | userBalances[to] += amount; 20 | userBalances[msg.sender] -= amount; 21 | } 22 | } 23 | 24 | function withdrawBalance() public { 25 | uint amountToWithdraw = userBalances[msg.sender]; 26 | // At this point, the caller's code is executed, and can call transfer() 27 | require(msg.sender.call.value(amountToWithdraw)()); 28 | userBalances[msg.sender] = 0; 29 | } 30 | } -------------------------------------------------------------------------------- /tests/ethereum/contracts/detectors/retval_crazy.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | /* 3 | Example contract - Potential False Positive 4 | The return value of a low level call IS checked after some manipulation. 5 | This should NOT report a finding. 6 | */ 7 | 8 | contract DetectThis { 9 | 10 | function call() public pure{ 11 | assert(false); 12 | } 13 | 14 | function callchecked() public { 15 | bool retval; 16 | bool retval2; 17 | retval = address(this).call.value(0)(bytes4(keccak256("call()"))); 18 | retval2 = retval; 19 | if (retval2 == false) 20 | assert(false); 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/detectors/retval_insane.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | /* 3 | Example contract - Potential False Positive 4 | The return value of a low level call IS checked after some manipulation. 5 | This should NOT report a finding. 6 | */ 7 | 8 | contract DetectThis{ 9 | 10 | function call() public pure{ 11 | assert(false); 12 | } 13 | 14 | function callchecked() public { 15 | bool retval; 16 | retval = address(this).call.value(0)(bytes4(keccak256("call()"))); 17 | require(retval == true); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/detectors/retval_lunatic.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | /* 3 | Example contract - Potential False Positive 4 | The return value of a low level call IS checked after some manipulation. 5 | This should not report a finding. 6 | */ 7 | 8 | contract DetectThis{ 9 | 10 | function call() public pure{ 11 | assert(false); 12 | } 13 | 14 | function callchecked() public { 15 | bool retval; 16 | retval = address(this).call.value(0)(bytes4(keccak256("call()"))); 17 | if (retval && retval) 18 | require (true); 19 | else 20 | require(false); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/detectors/retval_not_ok.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | /* 3 | Example contract - True Positive 4 | The return value of a low level call is simply ignored. 5 | We assume developer always want to check/bubble up exceptions. 6 | This should report a finding. 7 | */ 8 | contract DetectThis { 9 | 10 | function call() public pure{ 11 | assert(false); 12 | } 13 | 14 | function callchecked() public { 15 | address(this).call.value(0)(bytes4(keccak256("call()"))); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/detectors/retval_ok.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | /* 3 | Example contract - True Negative 4 | The return value of a low level call IS checked via solidity injected code. 5 | This should NOT report a finding. 6 | */ 7 | contract DetectThis { 8 | 9 | function call() public pure{ 10 | assert(false); 11 | } 12 | 13 | function callchecked() public { 14 | this.call(); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/detectors/selfdestruct_true_neg.sol: -------------------------------------------------------------------------------- 1 | /* 2 | Example contract - True Negative 3 | The selfdestruct is not reachable by non-creator and there is no way to set 4 | yourself as the owner. 5 | 6 | This should NOT report a finding. 7 | */ 8 | 9 | pragma solidity ^0.4.24; 10 | 11 | contract DetectThis { 12 | mapping (address => uint) balances; 13 | address owner; 14 | 15 | modifier onlyOwner { 16 | assert(msg.sender == owner); 17 | _; 18 | } 19 | 20 | constructor () public { 21 | owner = msg.sender; 22 | } 23 | 24 | function kill() public onlyOwner { 25 | selfdestruct(msg.sender); 26 | } 27 | } -------------------------------------------------------------------------------- /tests/ethereum/contracts/detectors/selfdestruct_true_neg1.sol: -------------------------------------------------------------------------------- 1 | /* 2 | Example contract - True Negative, Potential False Positive 3 | The selfdestruct is not reachable by non-creator and there is no way to set 4 | yourself as the owner. 5 | 6 | This should NOT report a finding. 7 | */ 8 | 9 | pragma solidity ^0.4.24; 10 | 11 | contract DetectThis { 12 | mapping (address => uint) balances; 13 | address owner; 14 | 15 | modifier onlyOwner { 16 | assert(msg.sender == owner); 17 | _; 18 | } 19 | function fakeSetOwner() { // writes to owner storage, but not exploitably 20 | owner = 2; 21 | } 22 | 23 | function kill() public onlyOwner { 24 | selfdestruct(msg.sender); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/detectors/selfdestruct_true_pos.sol: -------------------------------------------------------------------------------- 1 | /* 2 | Example contract - True Positive 3 | The selfdestruct is reachable by non-creator if you set yourself as the owner. 4 | 5 | This should report a finding. 6 | */ 7 | 8 | pragma solidity ^0.4.24; 9 | 10 | contract DetectThis { 11 | mapping (address => uint) balances; 12 | address owner; 13 | 14 | modifier onlyOwner { 15 | assert(msg.sender == owner); 16 | _; 17 | } 18 | 19 | function setOwner() public { // vulnerability here, anyone can be the owner 20 | owner = msg.sender; 21 | } 22 | 23 | function kill() public onlyOwner { 24 | selfdestruct(msg.sender); 25 | } 26 | } -------------------------------------------------------------------------------- /tests/ethereum/contracts/detectors/selfdestruct_true_pos1.sol: -------------------------------------------------------------------------------- 1 | /* 2 | Example contract - True Positive, Potential False Negative 3 | The selfdestruct is reachable by non-creator if you set yourself as the owner by exploiting 4 | the set() function. 5 | 6 | NOTE: this currently requires the LoopDepthLimiter plugin to find quickly. This is due to the 7 | assignment to map.length. 8 | 9 | This should report a finding. 10 | */ 11 | 12 | pragma solidity ^0.4.24; 13 | 14 | contract DetectThis { 15 | address owner; 16 | uint256[] map; 17 | 18 | modifier onlyOwner { 19 | assert(msg.sender == owner); 20 | _; 21 | } 22 | 23 | function set(uint256 key, uint256 value) public { // you can use this to overwrite owner 24 | // Expand dynamic array as needed 25 | if (map.length <= key) { 26 | map.length = key + 1; 27 | } 28 | 29 | map[key] = value; 30 | } 31 | 32 | function kill() public onlyOwner { 33 | selfdestruct(msg.sender); 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/imp.sol: -------------------------------------------------------------------------------- 1 | contract C { 2 | } 3 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/imports_issue/main/main.sol: -------------------------------------------------------------------------------- 1 | import '../utils/DirImported.sol'; 2 | import 'utils/DirImported2.sol'; 3 | 4 | contract C {} 5 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/imports_issue/utils/DirImported.sol: -------------------------------------------------------------------------------- 1 | contract Imported {} -------------------------------------------------------------------------------- /tests/ethereum/contracts/imports_issue/utils/DirImported2.sol: -------------------------------------------------------------------------------- 1 | contract Imported2 {} -------------------------------------------------------------------------------- /tests/ethereum/contracts/int_overflow.sol: -------------------------------------------------------------------------------- 1 | contract IntOverflowUnderflow { 2 | uint global; 3 | 4 | function intoverflow_add(uint input) { 5 | uint local = input + 1; 6 | } 7 | 8 | function intoverflow_mul(uint input) { 9 | uint local = input * 2; 10 | } 11 | 12 | function intunderflow(uint input) { 13 | uint local = input - 1; 14 | } 15 | 16 | function gintoverflow_add(uint input) { 17 | global = input + 1; 18 | } 19 | 20 | function gintoverflow_mul(uint input) { 21 | global = input * 2; 22 | } 23 | 24 | function gintunderflow(uint input) { 25 | global = input - 1; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/prop_verifier.sol: -------------------------------------------------------------------------------- 1 | contract Ownership{ 2 | address owner = msg.sender; 3 | function Owner() public{ 4 | owner = msg.sender; 5 | } 6 | modifier isOwner(){ 7 | require(owner == msg.sender); 8 | _; 9 | } 10 | } 11 | contract Pausable is Ownership{ 12 | bool is_paused; 13 | modifier ifNotPaused(){ 14 | require(!is_paused); 15 | _; 16 | } 17 | function paused() isOwner public{ 18 | is_paused = true; 19 | } 20 | function resume() isOwner public{ 21 | is_paused = false; 22 | } 23 | } 24 | contract Token is Pausable{ 25 | mapping(address => uint) public balances; 26 | function transfer(address to, uint value) ifNotPaused public{ 27 | balances[msg.sender] -= value; 28 | balances[to] += value; 29 | } 30 | } 31 | 32 | contract TestToken is Token { 33 | constructor() public{ 34 | balances[msg.sender] = 10000; 35 | } 36 | // the properties 37 | function crytic_test_balance() view public returns(bool){ 38 | return balances[msg.sender] <= 10000; 39 | } 40 | function crytic_test_must_revert() view public returns(bool){ 41 | require(false); 42 | } 43 | function crytic_failing_test_must_revert() view public returns(bool){ 44 | require(true); 45 | } 46 | 47 | 48 | } 49 | -------------------------------------------------------------------------------- /tests/ethereum/contracts/simple_int_overflow.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.15; 2 | 3 | contract Overflow { 4 | uint private sellerBalance=0; 5 | 6 | function add(uint value) public { 7 | sellerBalance += value; // complicated math with possible overflow 8 | 9 | // possible auditor assert 10 | assert(sellerBalance >= value); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/ethereum_bench/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | This file is requires so that unittest will be able to discover tests in children directories. 3 | """ 4 | -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/assert_constructor.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.19; 2 | 3 | contract Benchmark { 4 | function Benchmark() public { 5 | assert(false); 6 | } 7 | } -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/assert_minimal.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.19; 2 | 3 | contract Benchmark { 4 | function run() public { 5 | assert(false); 6 | } 7 | } -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/assert_multitx_1.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.19; 2 | 3 | contract Benchmark { 4 | uint256 private param; 5 | 6 | function Benchmark(uint256 _param) public { 7 | require(_param > 0); 8 | param = _param; 9 | } 10 | 11 | function run() { 12 | assert(param > 0); 13 | } 14 | 15 | } -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/assert_multitx_2.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.19; 2 | 3 | contract Benchmark { 4 | uint256 private param; 5 | 6 | function Benchmark(uint256 _param) public { 7 | require(_param > 0); 8 | param = _param; 9 | } 10 | 11 | function run() { 12 | assert(param > 0); 13 | } 14 | 15 | function set(uint256 _param) { 16 | param = _param; 17 | } 18 | 19 | 20 | } -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/assert_require.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.19; 2 | 3 | contract Benchmark { 4 | function run(uint256 _param) public { 5 | require(_param > 0); 6 | assert(_param > 0); 7 | } 8 | } -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/assert_sym.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.19; 2 | 3 | contract Benchmark { 4 | function run(uint256 param) public { 5 | assert(param > 0); 6 | } 7 | } -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/attribute_store.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.8; 2 | 3 | library AttributeStore { 4 | struct Data { 5 | mapping(bytes32 => uint) store; 6 | } 7 | 8 | function getAttribute(Data storage self, bytes32 _UUID, string _attrName) public view returns (uint) { 9 | bytes32 key = keccak256(_UUID, _attrName); 10 | return self.store[key]; 11 | } 12 | 13 | function attachAttribute(Data storage self, bytes32 _UUID, string _attrName, uint _attrVal) public { 14 | bytes32 key = keccak256(_UUID, _attrName); 15 | self.store[key] = _attrVal; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/eth_tx_order_dependence_multitx_1.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.16; 2 | 3 | contract Benchmark { 4 | address public owner; 5 | bool public claimed; 6 | uint256 public reward; 7 | bool public freezeReward; 8 | 9 | function Benchmark() public { 10 | owner = msg.sender; 11 | } 12 | 13 | function setReward() public payable { 14 | require (!claimed); 15 | require (!freezeReward); 16 | require(msg.sender == owner); 17 | 18 | owner.transfer(reward); 19 | reward = msg.value; 20 | } 21 | 22 | function freezeReward() public { 23 | freezeReward = true; 24 | } 25 | 26 | function claimReward(uint256 submission) { 27 | require (freezeReward); 28 | require (!claimed); 29 | require(submission < 10); 30 | 31 | msg.sender.transfer(reward); 32 | claimed = true; 33 | } 34 | } -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/integer_overflow_add.sol: -------------------------------------------------------------------------------- 1 | //Single transaction overflow 2 | //Post-transaction effect: overflow escapes to publicly-readable storage 3 | 4 | pragma solidity ^0.4.19; 5 | 6 | contract Benchmark { 7 | uint public count = 1; 8 | 9 | function run(uint256 input) public { 10 | count += input; 11 | } 12 | } -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/integer_overflow_benign_1.sol: -------------------------------------------------------------------------------- 1 | //Single transaction overflow 2 | //Post-transaction effect: overflow never escapes function 3 | 4 | pragma solidity ^0.4.19; 5 | 6 | contract Benchmark { 7 | uint public count = 1; 8 | 9 | function run(uint256 input) public { 10 | uint res = count - input; 11 | } 12 | } -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/integer_overflow_benign_2.sol: -------------------------------------------------------------------------------- 1 | //Single transaction overflow 2 | //Post-transaction effect: overflow never escapes to publicly-readable storage 3 | 4 | pragma solidity ^0.4.19; 5 | 6 | contract Benchmark { 7 | uint public count; 8 | 9 | function run(uint256 input) public { 10 | bool err; 11 | uint256 res = 1; 12 | 13 | (err, res) = minus(res, input); 14 | 15 | require(!err); 16 | count = res; 17 | } 18 | 19 | //from BasicMathLib 20 | function minus(uint256 a, uint256 b) private pure returns (bool err,uint256 res) { 21 | assembly { 22 | res := sub(a,b) 23 | switch eq(and(eq(add(res,b), a), or(lt(res,a), eq(res,a))), 1) 24 | case 0 { 25 | err := 1 26 | res := 0 27 | } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/integer_overflow_bytes_param.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.8; 2 | 3 | contract Benchmark { 4 | function get(bytes key) public pure returns (bytes32) { 5 | return keccak256(key); 6 | } 7 | } -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/integer_overflow_dynarray.sol: -------------------------------------------------------------------------------- 1 | //Dynamic storage array with packing 2 | // 3 | pragma solidity ^0.4.11; 4 | 5 | contract Benchmark { 6 | 7 | uint128[] private s; 8 | 9 | function init() public { 10 | s.length = 4; 11 | s[0] = 0xAA; 12 | s[1] = 0xBB; 13 | s[2] = 0xCC; 14 | s[3] = 0xDD; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/integer_overflow_mapping_mapping.sol: -------------------------------------------------------------------------------- 1 | //storage key for tuples[k].a calculated as 2 | // keccak(bytes32(k) + bytes32(position['tuples']))+offset['a'] 3 | pragma solidity ^0.4.11; 4 | 5 | contract Benchmark { 6 | mapping(uint256 => mapping (uint256 => Tuple)) maps; 7 | 8 | struct Tuple { 9 | uint256 a; 10 | uint256 b; 11 | } 12 | 13 | function init(uint256 k) { 14 | maps[k][k].b = 0x1A; 15 | } 16 | } -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/integer_overflow_mapping_staticarray.sol: -------------------------------------------------------------------------------- 1 | //storage key for tuples[k].a calculated as 2 | // keccak(bytes32(k) + bytes32(position['map']))+offset['a'] 3 | pragma solidity ^0.4.11; 4 | 5 | contract Benchmark { 6 | mapping(uint256 => bytes2) map; 7 | 8 | function init(uint256 k) public { 9 | map[k] = 0x1A; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/integer_overflow_mapping_strkey.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.8; 2 | 3 | contract Benchmark { 4 | mapping(string => uint256) map; 5 | 6 | function get(string key) public view returns (uint256) { 7 | return map[key]; 8 | } 9 | } -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/integer_overflow_mapping_struct.sol: -------------------------------------------------------------------------------- 1 | //storage key for tuples[k].a calculated as 2 | // keccak(bytes32(k) + bytes32(position['tuples']))+offset['a'] 3 | pragma solidity ^0.4.11; 4 | 5 | contract Benchmark { 6 | mapping(uint256 => Tuple) tuples; 7 | 8 | struct Tuple { 9 | uint256 a; 10 | uint256 b; 11 | } 12 | 13 | function init(uint256 k) { 14 | tuples[k].b = 0x1A; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/integer_overflow_mapping_sym_1.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | contract Benchmark { 4 | mapping(uint256 => uint256) map; 5 | 6 | function init(uint256 k, uint256 v) public { 7 | map[k] -= v; 8 | } 9 | } -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/integer_overflow_mapping_sym_2.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | contract Benchmark { 4 | mapping(uint256 => uint256) map; 5 | 6 | function init(uint256 k, uint256 v) public { 7 | require(v < 10); 8 | map[k] = 10; 9 | map[k] -= v; 10 | } 11 | } -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/integer_overflow_mapping_word.sol: -------------------------------------------------------------------------------- 1 | //storage key for tuples[i].a calculated as 2 | // keccak(bytes32(i) + bytes32(position['tuples']))+offset[a] 3 | pragma solidity ^0.4.11; 4 | 5 | contract Benchmark { 6 | mapping(uint256 => uint256) tuples; 7 | 8 | //tuple variable offset added to keccak(bytes32(key) + bytes32(position)) 9 | function init(uint256 key) public { 10 | tuples[key] = 0x1A; 11 | //tuples[key].b = 0x1B; 12 | //tuples[key].c = 0x1C; 13 | } 14 | } -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/integer_overflow_minimal.sol: -------------------------------------------------------------------------------- 1 | //Single transaction overflow 2 | //Post-transaction effect: overflow escapes to publicly-readable storage 3 | 4 | pragma solidity ^0.4.19; 5 | 6 | contract Benchmark { 7 | uint public count = 1; 8 | 9 | function run(uint256 input) public { 10 | count -= input; 11 | } 12 | } -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/integer_overflow_mul.sol: -------------------------------------------------------------------------------- 1 | //Single transaction overflow 2 | //Post-transaction effect: overflow escapes to publicly-readable storage 3 | 4 | pragma solidity ^0.4.19; 5 | 6 | contract Benchmark { 7 | uint public count = 2; 8 | 9 | function run(uint256 input) public { 10 | count *= input; 11 | } 12 | } -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/integer_overflow_multitx_multifunc_feasible.sol: -------------------------------------------------------------------------------- 1 | //Multi-transactional, multi-function 2 | //Arithmetic instruction reachable 3 | 4 | pragma solidity ^0.4.19; 5 | 6 | contract Benchmark { 7 | uint256 private initialized = 0; 8 | uint256 public count = 1; 9 | 10 | function init() public { 11 | initialized = 1; 12 | } 13 | 14 | function run(uint256 input) { 15 | if (initialized == 0) { 16 | return; 17 | } 18 | 19 | count -= input; 20 | } 21 | } -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/integer_overflow_multitx_onefunc_feasible.sol: -------------------------------------------------------------------------------- 1 | //Multi-transactional, single function 2 | //Arithmetic instruction reachable 3 | 4 | pragma solidity ^0.4.19; 5 | 6 | contract Benchmark { 7 | uint256 private initialized = 0; 8 | uint256 public count = 1; 9 | 10 | function run(uint256 input) public { 11 | if (initialized == 0) { 12 | initialized = 1; 13 | return; 14 | } 15 | 16 | count -= input; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/integer_overflow_multitx_onefunc_infeasible.sol: -------------------------------------------------------------------------------- 1 | //Multi-transactional, single function 2 | //Overflow infeasible because arithmetic instruction not reachable 3 | 4 | pragma solidity ^0.4.19; 5 | 6 | contract Benchmark { 7 | uint256 private initialized = 0; 8 | uint256 public count = 1; 9 | 10 | function run(uint256 input) public { 11 | if (initialized == 0) { 12 | return; 13 | } 14 | 15 | count -= input; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/integer_overflow_path_1.sol: -------------------------------------------------------------------------------- 1 | //Single transaction overflow 2 | //Post-transaction effect: overflow never escapes to publicly-readable storage 3 | 4 | pragma solidity ^0.4.19; 5 | 6 | contract Benchmark { 7 | uint public count = 1; 8 | 9 | function run(uint256 input) public { 10 | count = sub(count, input); 11 | } 12 | 13 | //from SafeMath 14 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 15 | require(b <= a);//SafeMath uses assert here 16 | return a - b; 17 | } 18 | } -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/integer_overflow_staticarray.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | contract Benchmark { 3 | uint256[6] private numbers; 4 | 5 | function get(uint256 i) public returns(uint256) { 6 | require(i < 6); 7 | return numbers[i]; 8 | } 9 | } -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/integer_overflow_storageinvariant.sol: -------------------------------------------------------------------------------- 1 | //No underflow because of credit/balance invariant: sum (credit.values) = balance 2 | pragma solidity ^0.4.19; 3 | 4 | contract Benchmark { 5 | mapping (address => uint) credit; 6 | uint balance; 7 | 8 | function withdrawAll() public { 9 | uint oCredit = credit[msg.sender]; 10 | if (oCredit > 0) { 11 | credit[msg.sender] = 0; 12 | balance -= oCredit; 13 | msg.sender.transfer(oCredit); 14 | } 15 | } 16 | 17 | function deposit() public payable { 18 | credit[msg.sender] += msg.value; 19 | balance += msg.value; 20 | require(balance < 1000); 21 | } 22 | } -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/integer_overflow_storagepacking.sol: -------------------------------------------------------------------------------- 1 | //Storage packing optimization stores a,b in a single 32-byte storage slot. 2 | //solc generates MUL instruction that operates on compile-time constants to 3 | // extract variable a (or b) from packed storage slot. 4 | pragma solidity ^0.4.11; 5 | contract Benchmark { 6 | uint128 a; 7 | uint128 b; 8 | function C() public { 9 | a = 1; 10 | b = 2; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/reentrancy_dao.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.19; 2 | 3 | contract Benchmark { 4 | mapping (address => uint) credit; 5 | uint balance; 6 | 7 | function withdrawAll() public { 8 | uint oCredit = credit[msg.sender]; 9 | if (oCredit > 0) { 10 | balance -= oCredit; 11 | bool callResult = msg.sender.call.value(oCredit)(); 12 | require (callResult); 13 | credit[msg.sender] = 0; 14 | } 15 | } 16 | 17 | function deposit() public payable { 18 | credit[msg.sender] += msg.value; 19 | balance += msg.value; 20 | } 21 | } -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/reentrancy_dao_fixed.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.19; 2 | 3 | contract Benchmark { 4 | mapping (address => uint) credit; 5 | uint balance; 6 | 7 | function withdrawAll() public { 8 | uint oCredit = credit[msg.sender]; 9 | if (oCredit > 0) { 10 | balance -= oCredit; 11 | credit[msg.sender] = 0; 12 | bool callResult = msg.sender.call.value(oCredit)(); 13 | require (callResult); 14 | } 15 | } 16 | 17 | function deposit() public payable { 18 | credit[msg.sender] += msg.value; 19 | balance += msg.value; 20 | } 21 | } -------------------------------------------------------------------------------- /tests/ethereum_bench/consensys_benchmark/reentrancy_nostateeffect.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.19; 2 | 3 | interface Runner { 4 | function run(uint256 param) external; 5 | } 6 | 7 | contract Benchmark { 8 | 9 | function run(address base, uint256 param) public { 10 | Runner(base).run(param); 11 | } 12 | 13 | } -------------------------------------------------------------------------------- /tests/native/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | This file is requires so that unittest will be able to discover tests in children directories. 3 | """ 4 | -------------------------------------------------------------------------------- /tests/native/binaries/arguments: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/tests/native/binaries/arguments -------------------------------------------------------------------------------- /tests/native/binaries/arguments_linux_amd64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/tests/native/binaries/arguments_linux_amd64 -------------------------------------------------------------------------------- /tests/native/binaries/arguments_linux_armv7: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/tests/native/binaries/arguments_linux_armv7 -------------------------------------------------------------------------------- /tests/native/binaries/basic_linux_amd64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/tests/native/binaries/basic_linux_amd64 -------------------------------------------------------------------------------- /tests/native/binaries/basic_linux_armv7: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/tests/native/binaries/basic_linux_armv7 -------------------------------------------------------------------------------- /tests/native/binaries/basic_state_merging: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/tests/native/binaries/basic_state_merging -------------------------------------------------------------------------------- /tests/native/binaries/brk_static_amd64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/tests/native/binaries/brk_static_amd64 -------------------------------------------------------------------------------- /tests/native/binaries/cadet_decree_x86: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/tests/native/binaries/cadet_decree_x86 -------------------------------------------------------------------------------- /tests/native/binaries/epoll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/tests/native/binaries/epoll -------------------------------------------------------------------------------- /tests/native/binaries/epoll.c: -------------------------------------------------------------------------------- 1 | #define MAX_EVENTS 5 2 | #define READ_SIZE 10 3 | #include // for fprintf() 4 | #include // for close(), read() 5 | #include // for epoll_create1(), epoll_ctl(), struct epoll_event 6 | #include // for strncmp 7 | 8 | int main() 9 | { 10 | int running = 1, event_count, i; 11 | size_t bytes_read; 12 | char read_buffer[READ_SIZE + 1]; 13 | struct epoll_event event, events[MAX_EVENTS]; 14 | int epoll_fd = epoll_create1(0); 15 | 16 | if(epoll_fd == -1) 17 | { 18 | fprintf(stderr, "Failed to create epoll file descriptor\n"); 19 | return 1; 20 | } 21 | 22 | event.events = EPOLLIN; 23 | event.data.fd = 0; 24 | 25 | if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, 0, &event)) 26 | { 27 | fprintf(stderr, "Failed to add file descriptor to epoll\n"); 28 | close(epoll_fd); 29 | return 1; 30 | } 31 | 32 | while(running) 33 | { 34 | //printf("\nPolling for input...\n"); 35 | event_count = epoll_wait(epoll_fd, events, MAX_EVENTS, 30000); 36 | //printf("%d ready events\n", event_count); 37 | for(i = 0; i < event_count; i++) 38 | { 39 | //printf("Reading file descriptor '%d' -- ", events[i].data.fd); 40 | bytes_read = read(events[i].data.fd, read_buffer, READ_SIZE); 41 | //printf("%zd bytes read.\n", bytes_read); 42 | read_buffer[bytes_read] = '\0'; 43 | //printf("Read '%s'\n", read_buffer); 44 | 45 | if(read_buffer[0] == 's' && 46 | read_buffer[1] == 't' && 47 | read_buffer[2] == 'o' && 48 | read_buffer[3] == 'p') { 49 | running = 0; 50 | } 51 | } 52 | } 53 | 54 | if(close(epoll_fd)) 55 | { 56 | fprintf(stderr, "Failed to close epoll file descriptor\n"); 57 | return 1; 58 | } 59 | return 0; 60 | } -------------------------------------------------------------------------------- /tests/native/binaries/fclose_linux_amd64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/tests/native/binaries/fclose_linux_amd64 -------------------------------------------------------------------------------- /tests/native/binaries/fileio_linux_amd64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/tests/native/binaries/fileio_linux_amd64 -------------------------------------------------------------------------------- /tests/native/binaries/hello_world: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/tests/native/binaries/hello_world -------------------------------------------------------------------------------- /tests/native/binaries/ioctl_bogus_linux_amd64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/tests/native/binaries/ioctl_bogus_linux_amd64 -------------------------------------------------------------------------------- /tests/native/binaries/ioctl_socket_linux_amd64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/tests/native/binaries/ioctl_socket_linux_amd64 -------------------------------------------------------------------------------- /tests/native/binaries/rusticorn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/tests/native/binaries/rusticorn -------------------------------------------------------------------------------- /tests/native/binaries/str_model_tests/sym_strcpy_test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/tests/native/binaries/str_model_tests/sym_strcpy_test -------------------------------------------------------------------------------- /tests/native/binaries/str_model_tests/sym_strcpy_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #define LEN 5 6 | 7 | int main() { 8 | char * A = "src or dst is A"; 9 | char * NA = "src or dst is not A"; 10 | char src[LEN]; 11 | char dst[sizeof(src)]; 12 | read(0, src, sizeof(src)); 13 | 14 | strcpy(dst, src); 15 | if (dst[1] == 'A' || src[1] == 'A'){ 16 | printf(A); 17 | } 18 | if (dst[1] != 'A' && src[1] != 'A'){ 19 | printf(NA); 20 | } 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /tests/native/binaries/str_model_tests/sym_strlen_test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/tests/native/binaries/str_model_tests/sym_strlen_test -------------------------------------------------------------------------------- /tests/native/binaries/str_model_tests/sym_strlen_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #define LEN 5 5 | 6 | int main() { 7 | char str[LEN]; 8 | read(0, str, sizeof(str)); 9 | 10 | int a = strlen(str); 11 | printf("Length of string is: %d", a); 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /tests/native/binaries/str_model_tests/sym_strncpy_test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/tests/native/binaries/str_model_tests/sym_strncpy_test -------------------------------------------------------------------------------- /tests/native/binaries/str_model_tests/sym_strncpy_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #define LEN 5 6 | 7 | int main() { 8 | char src[LEN]; 9 | char dst[LEN]; 10 | read(0, src, LEN); 11 | 12 | strncpy(dst, src, LEN - 2); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /tests/native/binaries/symbolic_length_recv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/tests/native/binaries/symbolic_length_recv -------------------------------------------------------------------------------- /tests/native/binaries/symbolic_length_recv.c: -------------------------------------------------------------------------------- 1 | // Compiled on Ubuntu 18.04 Manticore Docker image with 2 | // gcc -static symbolic_read_count.c -o symbolic_read_count 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define PORT 8081 9 | #define BUFFER_SIZE 4 10 | 11 | int main() { 12 | int server_fd, new_client; 13 | struct sockaddr_in address; 14 | 15 | // create socket file descriptor, attach to 8081 16 | int opt = 1; // Reuse address 17 | server_fd = socket(AF_INET, SOCK_STREAM, 0); 18 | if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) 19 | return -1; 20 | address.sin_family = AF_INET; 21 | address.sin_addr.s_addr = INADDR_ANY; 22 | address.sin_port = htons(PORT); 23 | if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))) 24 | return -1; 25 | 26 | printf("Listening on port %i...\n", PORT); 27 | 28 | 29 | char buffer[BUFFER_SIZE]; 30 | 31 | int addrlen = sizeof(address); 32 | listen(server_fd, 10); 33 | new_client = accept(server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen); 34 | 35 | ssize_t num_rcv = recv(new_client, buffer, BUFFER_SIZE, 0); 36 | if (num_rcv < BUFFER_SIZE) { 37 | printf("Received less than BUFFER_SIZE\n"); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/native/binaries/symbolic_read_count: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/tests/native/binaries/symbolic_read_count -------------------------------------------------------------------------------- /tests/native/binaries/symbolic_read_count.c: -------------------------------------------------------------------------------- 1 | // Compiled on Ubuntu 18.04 Manticore Docker image with 2 | // gcc -static symbolic_read_count.c -o symbolic_read_count 3 | 4 | #include 5 | #include 6 | 7 | int main(int argc, char **argv) { 8 | // Need at least one argument 9 | if (argc != 2) { 10 | return -1; 11 | } 12 | 13 | // Just get the char ordinal value 14 | unsigned int count = argv[1][0]; 15 | if (count > 9) { 16 | return 0; 17 | } 18 | 19 | // Yes... this is very unsafe 20 | char *buf[10]; 21 | int sz = read(0, buf, count); 22 | if (sz > 0) { 23 | printf("WIN: Read more than zero data\n"); 24 | } 25 | return sz; 26 | } 27 | -------------------------------------------------------------------------------- /tests/native/binaries/thumb_mode_entrypoint: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/tests/native/binaries/thumb_mode_entrypoint -------------------------------------------------------------------------------- /tests/native/test_binary_package.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import os 4 | 5 | from manticore.binary import Elf, CGCElf 6 | 7 | DIRPATH = os.path.dirname(__file__) 8 | 9 | 10 | class TestBinaryPackage(unittest.TestCase): 11 | _multiprocess_can_split_ = True 12 | 13 | def test_elf(self): 14 | filename = os.path.join(DIRPATH, "binaries", "basic_linux_amd64") 15 | f = Elf(filename) 16 | self.assertTrue( 17 | [ 18 | (4194304, 823262, "r x", "tests/binaries/basic_linux_amd64", 0, 823262), 19 | (7118520, 16112, "rw ", "tests/binaries/basic_linux_amd64", 827064, 7320), 20 | ], 21 | list(f.maps()), 22 | ) 23 | self.assertTrue([("Running", {"EIP": 4196624})], list(f.threads())) 24 | self.assertIsNone(f.getInterpreter()) 25 | f.elf.stream.close() 26 | 27 | def test_decree(self): 28 | filename = os.path.join(DIRPATH, "binaries", "cadet_decree_x86") 29 | f = CGCElf(filename) 30 | self.assertTrue( 31 | [(134512640, 1478, "r x", "tests/binaries/cadet_decree_x86", 0, 1478)], list(f.maps()) 32 | ) 33 | self.assertTrue([("Running", {"EIP": 134513708})], list(f.threads())) 34 | f.elf.stream.close() 35 | -------------------------------------------------------------------------------- /tests/native/test_driver.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import os 4 | import shutil 5 | import tempfile 6 | 7 | from manticore import issymbolic 8 | from manticore.core.smtlib import BitVecVariable 9 | from manticore.native import Manticore 10 | 11 | 12 | class ManticoreDriverTest(unittest.TestCase): 13 | _multiprocess_can_split_ = True 14 | 15 | def setUp(self): 16 | # Create a temporary directory 17 | self.test_dir = tempfile.mkdtemp() 18 | 19 | def tearDown(self): 20 | # Remove the directory after the test 21 | shutil.rmtree(self.test_dir) 22 | 23 | def testCreating(self): 24 | dirname = os.path.dirname(__file__) 25 | m = Manticore(os.path.join(dirname, "binaries", "basic_linux_amd64")) 26 | m.log_file = "/dev/null" 27 | 28 | def test_issymbolic(self): 29 | v = BitVecVariable(size=32, name="sym") 30 | self.assertTrue(issymbolic(v)) 31 | 32 | def test_issymbolic_neg(self): 33 | v = 1 34 | self.assertFalse(issymbolic(v)) 35 | -------------------------------------------------------------------------------- /tests/native/test_logging.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import logging 3 | 4 | from manticore.utils.log import get_verbosity, set_verbosity, DEFAULT_LOG_LEVEL 5 | 6 | 7 | class ManticoreLogger(unittest.TestCase): 8 | """Make sure we set the logging levels correctly""" 9 | 10 | _multiprocess_can_split_ = True 11 | 12 | def test_logging(self): 13 | set_verbosity(1) 14 | self.assertEqual(get_verbosity("manticore.native.cpu.abstractcpu"), logging.WARNING) 15 | self.assertEqual(get_verbosity("manticore.ethereum.abi"), logging.INFO) 16 | 17 | set_verbosity(0) 18 | self.assertEqual(get_verbosity("manticore.native.cpu.abstractcpu"), DEFAULT_LOG_LEVEL) 19 | self.assertEqual(get_verbosity("manticore.ethereum.abi"), DEFAULT_LOG_LEVEL) 20 | -------------------------------------------------------------------------------- /tests/native/test_register.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from manticore.core.smtlib import * 4 | from manticore.native.cpu.register import Register 5 | 6 | 7 | class RegisterTest(unittest.TestCase): 8 | _multiprocess_can_split_ = True 9 | 10 | def test_rd(self): 11 | r = Register(32) 12 | self.assertEqual(r.read(), 0) 13 | 14 | def test_basic_write(self): 15 | r = Register(32) 16 | r.write(1) 17 | self.assertEqual(r.read(), 1) 18 | 19 | def test_truncate(self): 20 | r = Register(32) 21 | r.write(2**32) 22 | self.assertEqual(r.read(), 0) 23 | 24 | def test_largest_write(self): 25 | r = Register(32) 26 | r.write(0xFFFFFFFF) 27 | self.assertEqual(r.read(), 0xFFFFFFFF) 28 | 29 | def test_flag(self): 30 | r = Register(1) 31 | self.assertEqual(r.read(), False) 32 | 33 | def test_flag_write(self): 34 | r = Register(1) 35 | r.write(True) 36 | self.assertEqual(r.read(), True) 37 | 38 | def test_flag_trunc(self): 39 | r = Register(1) 40 | r.write(3) 41 | self.assertEqual(r.read(), True) 42 | 43 | def test_bool_write_nonflag(self): 44 | r = Register(32) 45 | r.write(True) 46 | self.assertEqual(r.read(), True) 47 | 48 | def test_Bool(self): 49 | r = Register(32) 50 | b = BoolVariable(name="B") 51 | r.write(b) 52 | self.assertIs(r.read(), b) 53 | 54 | def test_bitvec_flag(self): 55 | r = Register(1) 56 | b = BitVecConstant(size=32, value=0) 57 | r.write(b) 58 | # __nonzero__ (==) currently unimplemented for Bool 59 | self.assertTrue(isinstance(r.read(), Bool)) 60 | 61 | def test_bitvec(self): 62 | r = Register(32) 63 | b = BitVecConstant(size=32, value=0) 64 | r.write(b) 65 | self.assertIs(r.read(), b) 66 | 67 | def test_bad_write(self): 68 | r = Register(32) 69 | with self.assertRaises(TypeError): 70 | r.write(dict()) 71 | -------------------------------------------------------------------------------- /tests/native/test_resume.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from manticore.native import Manticore 3 | from manticore.core.state import SerializeState, TerminateState 4 | from pathlib import Path 5 | 6 | 7 | ms_file = str( 8 | Path(__file__).parent.parent.parent.joinpath("examples", "linux", "binaries", "multiple-styles") 9 | ) 10 | 11 | 12 | class TestResume(unittest.TestCase): 13 | def test_resume(self): 14 | m = Manticore(ms_file, stdin_size=17) 15 | 16 | # First instruction of `main` 17 | @m.hook(0x4009AE) 18 | def serialize(state): 19 | with m.locked_context() as context: 20 | if context.get("kill", False): 21 | raise TerminateState("Abandoning...") 22 | context["kill"] = True 23 | raise SerializeState("/tmp/ms_checkpoint.pkl") 24 | 25 | m.run() 26 | self.assertEqual(m.count_terminated_states(), 1) 27 | for state in m.terminated_states: 28 | self.assertEqual(state.cpu.PC, 0x4009AE) 29 | 30 | m = Manticore.from_saved_state("/tmp/ms_checkpoint.pkl") 31 | self.assertEqual(m.count_ready_states(), 1) 32 | for st in m.ready_states: 33 | self.assertEqual(state.cpu.PC, 0x4009AE) 34 | m.run() 35 | 36 | self.assertEqual(m.count_terminated_states(), 18) 37 | self.assertTrue( 38 | any("exit status: 0" in str(st._terminated_by) for st in m.terminated_states) 39 | ) 40 | m.finalize() 41 | for st in m.terminated_states: 42 | if "exit status: 0" in str(st._terminated_by): 43 | self.assertEqual(st.solve_one(st.input_symbols[0]), b"coldlikeminisodas") 44 | 45 | 46 | if __name__ == "__main__": 47 | unittest.main() 48 | -------------------------------------------------------------------------------- /tests/native/test_rust.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import os 4 | 5 | from manticore.native import Manticore 6 | 7 | 8 | class RustTest(unittest.TestCase): 9 | BIN_PATH = os.path.join(os.path.dirname(__file__), "binaries", "hello_world") 10 | 11 | def setUp(self): 12 | self.m = Manticore.linux(self.BIN_PATH) 13 | 14 | def test_hello_world(self): 15 | self.m.run() 16 | -------------------------------------------------------------------------------- /tests/other/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | This file is requires so that unittest will be able to discover tests in children directories. 3 | """ 4 | -------------------------------------------------------------------------------- /tests/other/test_fork.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import tempfile 3 | from manticore.native import Manticore 4 | from manticore.core.state import Concretize 5 | from pathlib import Path 6 | from glob import glob 7 | 8 | 9 | class TestFork(unittest.TestCase): 10 | def test_fork_unique_solution(self): 11 | binary = str( 12 | Path(__file__).parent.parent.parent.joinpath( 13 | "tests", "native", "binaries", "hello_world" 14 | ) 15 | ) 16 | tmp_dir = tempfile.TemporaryDirectory(prefix="mcore_test_fork_") 17 | m = Manticore(binary, stdin_size=10, workspace_url=str(tmp_dir.name)) 18 | 19 | @m.hook(0x3E50) # Entrypoint 20 | def concretize_var(state): 21 | # Concretize symbolic var that has only 1 solution 22 | var = BitVecVariable(size=32, name="bar") 23 | state.constrain(var == 5) 24 | raise Concretize(var) 25 | 26 | m.run() 27 | m.finalize() 28 | 29 | # Check that no additional state was created when forking 30 | states = f"{str(m.workspace)}/test_*.pkl" 31 | self.assertEqual(len(glob(states)), 1) 32 | 33 | 34 | if __name__ == "__main__": 35 | unittest.main() 36 | -------------------------------------------------------------------------------- /tests/other/test_locking.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from manticore.native import Manticore 3 | from pathlib import Path 4 | 5 | 6 | ms_file = str( 7 | Path(__file__).parent.parent.parent.joinpath("examples", "linux", "binaries", "multiple-styles") 8 | ) 9 | 10 | 11 | class TestResume(unittest.TestCase): 12 | def test_resume(self): 13 | m = Manticore(ms_file, stdin_size=17) 14 | 15 | with m.locked_context() as ctx: 16 | self.assertNotIn("unlocked", str(m._lock)) 17 | 18 | 19 | if __name__ == "__main__": 20 | unittest.main() 21 | -------------------------------------------------------------------------------- /tests/other/utils/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | This file is requires so that unittest will be able to discover tests in children directories. 3 | """ 4 | -------------------------------------------------------------------------------- /tests/other/utils/test_events.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from manticore.utils.event import Eventful 4 | 5 | 6 | class A(Eventful): 7 | _published_events = {"eventA"} 8 | 9 | def do_stuff(self): 10 | self._publish("eventA", 1, "a") 11 | 12 | 13 | class B(Eventful): 14 | _published_events = {"eventB"} 15 | 16 | def __init__(self, child, **kwargs): 17 | super().__init__(**kwargs) 18 | self.child = child 19 | self.forward_events_from(child) 20 | 21 | def do_stuff(self): 22 | self._publish("eventB", 2, "b") 23 | 24 | 25 | class C: 26 | def __init__(self): 27 | self.received = [] 28 | 29 | def callback(self, *args): 30 | self.received.append(args) 31 | 32 | 33 | class ManticoreDriver(unittest.TestCase): 34 | _multiprocess_can_split_ = True 35 | 36 | def test_weak_references(self): 37 | a = A() 38 | self.assertSequenceEqual([len(s) for s in (a._signals, a._forwards)], (0, 0)) 39 | 40 | b = B(a) 41 | self.assertSequenceEqual([len(s) for s in (a._signals, a._forwards)], (0, 1)) 42 | self.assertSequenceEqual([len(s) for s in (b._signals, b._forwards)], (0, 0)) 43 | 44 | c = C() 45 | b.subscribe("eventA", c.callback) 46 | self.assertSequenceEqual([len(s) for s in (a._signals, a._forwards)], (0, 1)) 47 | self.assertSequenceEqual([len(s) for s in (b._signals, b._forwards)], (1, 0)) 48 | 49 | b.subscribe("eventB", c.callback) 50 | self.assertSequenceEqual([len(s) for s in (a._signals, a._forwards)], (0, 1)) 51 | self.assertSequenceEqual([len(s) for s in (b._signals, b._forwards)], (2, 0)) 52 | 53 | del c 54 | self.assertSequenceEqual([len(s) for s in (a._signals, a._forwards)], (0, 1)) 55 | self.assertSequenceEqual([len(s) for s in (b._signals, b._forwards)], (0, 0)) 56 | 57 | del b 58 | self.assertSequenceEqual([len(s) for s in (a._signals, a._forwards)], (0, 0)) 59 | 60 | def test_basic(self): 61 | a = A() 62 | b = B(a) 63 | c = C() 64 | 65 | b.subscribe("eventA", c.callback) 66 | b.subscribe("eventB", c.callback) 67 | 68 | a.do_stuff() 69 | self.assertSequenceEqual(c.received, [(1, "a")]) 70 | 71 | b.do_stuff() 72 | self.assertSequenceEqual(c.received, [(1, "a"), (2, "b")]) 73 | -------------------------------------------------------------------------------- /tests/wasm/generate_tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # rm -rf */ 4 | touch __init__.py 5 | 6 | if ! [ -x "$(command -v wast2json)" ]; then 7 | wget -nc -nv -O wabt.tgz -c https://github.com/WebAssembly/wabt/releases/download/1.0.12/wabt-1.0.12-linux.tar.gz 8 | tar --wildcards --strip=1 -xf wabt.tgz 'wabt-*/wast2json' 9 | rm wabt.tgz 10 | else 11 | cp "$(command -v wast2json)" . 12 | fi 13 | 14 | wget -nc -nv -O spec.zip -c https://github.com/WebAssembly/spec/archive/opam-1.1.zip 15 | 16 | unzip -q -j spec.zip 'spec-*/test/core/*' -d . 17 | rm run.py README.md 18 | rm spec.zip 19 | 20 | mkdir skipped_tests 21 | while read skip; do 22 | mv $skip.wast skipped_tests/ 23 | done < skipped_test_sets 24 | 25 | for x in *"-"*.wast; do 26 | mv -- "$x" "${x//-/_}" 27 | done 28 | 29 | ls *.wast | sed 's/\.wast//g' > modules.txt 30 | 31 | cores=$(python -c "import multiprocessing; print(max(multiprocessing.cpu_count() - 2, 1))") 32 | 33 | cat > gen.sh << EOF 34 | module=\$1 35 | echo "Preparing \$module" 36 | mkdir _\$module 37 | touch _\$module/__init__.py 38 | ./wast2json --debug-names \$module.wast -o _\$module/\$module.json 39 | mv \$module.wast _\$module/ 40 | python3 json2mc.py _\$module/\$module.json | black --quiet --fast - > _\$module/test_\$module.py 41 | EOF 42 | 43 | chmod +x gen.sh 44 | cat modules.txt | xargs -n1 -P"$cores" ./gen.sh 45 | rm gen.sh 46 | 47 | mv test_callbacks.skip test_callbacks.py 48 | 49 | exit 0 50 | -------------------------------------------------------------------------------- /tests/wasm/inputs/br_if.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/tests/wasm/inputs/br_if.wasm -------------------------------------------------------------------------------- /tests/wasm/inputs/br_if.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (func (export "main") (param $x i32) (result i32) 3 | (block (result i32) 4 | (i32.const 1) 5 | (i32.sub 6 | (local.get $x) 7 | (i32.const 88) 8 | ) 9 | (br_if 0) 10 | (drop) 11 | (i32.const 0) 12 | ) 13 | ) 14 | ) -------------------------------------------------------------------------------- /tests/wasm/inputs/br_table.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/tests/wasm/inputs/br_table.wasm -------------------------------------------------------------------------------- /tests/wasm/inputs/br_table.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (func (export "main") (param $x i32) (result i32) (local $ret i32) 3 | (local.set $ret (i32.const 2)) 4 | (block $outer 5 | (block 6 | (block 7 | (i32.sub 8 | (local.get $x) 9 | (i32.const 88) 10 | ) 11 | (br_table 0 1 2) 12 | ) 13 | (local.set $ret (i32.const 0)) 14 | (br $outer) 15 | ) 16 | (local.set $ret (i32.const 1)) 17 | (br $outer) 18 | ) 19 | (local.get $ret) 20 | ) 21 | ) 22 | -------------------------------------------------------------------------------- /tests/wasm/inputs/call_indirect.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/tests/wasm/inputs/call_indirect.wasm -------------------------------------------------------------------------------- /tests/wasm/inputs/call_indirect.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (table funcref (elem $const_zero $const_one)) 3 | (type $no_in_one_out (func (result i32))) 4 | 5 | (func $const_zero (result i32) 6 | (i32.const 0)) 7 | 8 | (func $const_one (result i32) 9 | (i32.const 1)) 10 | 11 | (func (export "main") (param $x i32) (result i32) 12 | (i32.sub 13 | (local.get $x) 14 | (i32.const 88) 15 | ) 16 | (call_indirect (type $no_in_one_out)) 17 | ) 18 | ) 19 | -------------------------------------------------------------------------------- /tests/wasm/inputs/if.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/manticore/8861005396ed3e25ecef9cd229e5319ae2fe2612/tests/wasm/inputs/if.wasm -------------------------------------------------------------------------------- /tests/wasm/inputs/if.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (func (export "main") (param $x i32) (result i32) 3 | (if (result i32) 4 | (i32.sub 5 | (local.get $x) 6 | (i32.const 88) 7 | ) 8 | (then 9 | (i32.const 1) 10 | ) 11 | (else 12 | (i32.const 0) 13 | ) 14 | ) 15 | ) 16 | ) 17 | -------------------------------------------------------------------------------- /tests/wasm/skipped_test_sets: -------------------------------------------------------------------------------- 1 | conversions 2 | f32 3 | f64 4 | float_exprs 5 | float_literals 6 | float_memory 7 | float_misc 8 | -------------------------------------------------------------------------------- /tests/wasm_sym/generate_symbolic_tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | rm -rf */ 4 | touch __init__.py 5 | 6 | if ! [ -x "$(command -v wast2json)" ]; then 7 | wget -nc -nv -O wabt.tgz -c https://github.com/WebAssembly/wabt/releases/download/1.0.12/wabt-1.0.12-linux.tar.gz 8 | tar --wildcards --strip=1 -xf wabt.tgz 'wabt-*/wast2json' 9 | rm wabt.tgz 10 | else 11 | cp "$(command -v wast2json)" . 12 | fi 13 | 14 | wget -nc -nv -O spec.zip -c https://github.com/WebAssembly/spec/archive/opam-1.1.zip 15 | 16 | unzip -q -j spec.zip 'spec-*/test/core/*' -d . 17 | rm run.py README.md 18 | rm spec.zip 19 | 20 | mkdir skipped_tests 21 | while read skip; do 22 | mv $skip.wast skipped_tests/ 23 | done < skipped_test_sets 24 | 25 | for x in *"-"*.wast; do 26 | mv -- "$x" "${x//-/_}" 27 | done 28 | 29 | ls *.wast | sed 's/\.wast//g' > modules.txt 30 | 31 | cores=$(python -c "import multiprocessing; print(max(multiprocessing.cpu_count() - 2, 1))") 32 | 33 | cat > gen.sh << EOF 34 | module=\$1 35 | echo "Preparing \$module" 36 | mkdir _\$module 37 | touch _\$module/__init__.py 38 | ./wast2json --debug-names \$module.wast -o _\$module/\$module.json 39 | mv \$module.wast _\$module/ 40 | python3 json2smc.py _\$module/\$module.json | black --quiet --fast - > _\$module/test_symbolic_\$module.py 41 | EOF 42 | 43 | chmod +x gen.sh 44 | cat modules.txt | xargs -n1 -P"$cores" ./gen.sh 45 | rm gen.sh 46 | 47 | exit 0 48 | -------------------------------------------------------------------------------- /tests/wasm_sym/skipped_test_sets: -------------------------------------------------------------------------------- 1 | conversions 2 | f32 3 | f64 4 | float_exprs 5 | float_literals 6 | float_memory 7 | float_misc 8 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py3{6,7,8,9} 3 | 4 | [testenv] 5 | deps = .[dev] 6 | commands = pytest -n auto tests 7 | 8 | [testenv:pep8] 9 | deps = flake8 10 | commands = 11 | flake8 . 12 | 13 | [pep8] 14 | ignore = E265,E501 15 | max-line-length = 100 16 | exclude = docs/,examples/,scripts/,tests/ 17 | 18 | [flake8] 19 | ignore = E265,E501,F403,F405,E266,E712,F841,E741,E722,E731 20 | max-line-length = 100 21 | exclude = .tox,.*.egg,.git,docs/,examples/,scripts/,tests/,iterpickle.py 22 | --------------------------------------------------------------------------------