Framework
cea-sec/miasm avatar
cea-sec/miasm

cea-sec/miasm: a Python framework for lifting machine code into an IR

Reverse engineering framework in Python

3,977 stars488 forksPythonGPL-2.0

At a glance

What is it?
Miasm assembles, disassembles, lifts and JIT-emulates x86, ARM, MIPS, SH4 and MSP430 binaries from Python. It is a library for people who write their own analysis tooling, not a finished reverse engineering GUI.
Who is it for?
Adopt miasm if you are building custom static or dynamic analysis and want a programmable IR, a JIT and a symbolic execution layer in one Python package. Do not adopt it if you want a point-and-click disassembler or a maintained stable API surface: the last push was on 2026-09-21, the newest tagged release is v0.1.3 from 2019-12-12, and pyproject.toml declares the classifier Development Status :: 4 - Beta.
Can I use it commercially?
Yes, with conditions. GPL-2.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 9 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The gap miasm fills between a disassembler and a scripting language

Most disassemblers give you a listing. Miasm gives you objects. The README describes the project as a reverse engineering framework that aims to analyze, modify and generate binary programs, and the feature list is explicit: opening, modifying and generating PE and ELF for 32 and 64 bit, little and big endian; assembling and disassembling X86, ARM, MIPS, SH4 and MSP430; representing assembly semantics in an intermediate language; emulating through a JIT; and expression simplification for automatic de-obfuscation.

That last item is the part worth pausing on. De-obfuscation is not a feature you switch on, it is what you get when instructions become symbolic expressions you can rewrite. The audience is therefore narrow and specific: malware analysts writing unpackers, people building custom CFG recovery, researchers who need to run a fragment of code without a full OS, and anyone who wants to answer a question about a binary that no existing tool exposes as a query. If your workflow ends with a human reading a listing, miasm is more machinery than you need.

How the pipeline works: mnemo, lifter, ircfg, jitter

The README's examples expose the architecture layer by layer. A Machine object wraps an architecture and hands you two things: a mnemo (mn) for assembly and disassembly, and a lifter that converts instructions into an intermediate representation. The lifter produces an ircfg, a control flow graph of IR blocks. Each block is a sequence of assignment blocks, and each assignment block can report its reads and writes through get_rw, which is how you build data flow without parsing text.

Emulation is a separate engine. The jitter takes a memory model, a stack, and breakpoints. In the README's shellcode walkthrough, the code is placed at 0x40000000 with PAGE_READ | PAGE_WRITE, a sentinel breakpoint is registered at 0x1337beef, and that address is pushed as the return target so the run stops cleanly when the shellcode returns. Trace logging is enabled with set_trace_log, and the run is started with init_run followed by continue_run. The printed trace shows registers and flags after each instruction, which is the fastest way to see where a lifter and a real CPU disagree.

The IR is where the framework's real weight sits. The README points to a Jupyter notebook under doc/expression/expression.ipynb for the details, and the repository ships example directories for asm, disasm, expression, ida, jitter, loader, symbol_exec and samples. Those directories are the practical documentation.

Installing miasm and running a first disassembly

pyproject.toml declares requires-python >= 3.10 and lists future and pyparsing==3.3.2 as the only mandatory dependencies. Everything else is optional and grouped: cparser pulls pycparser, z3 pulls z3-solver, llvm pulls llvmlite, graph pulls graphviz, crypto pulls pycryptodome, and the all extra combines them. The build backend is setuptools, and setup.py compiles a JIT extension, so a C compiler is needed unless you accept a build without it.

A plain install from the repository root:

bash
pip3 install .

The Dockerfile shows the intended full setup. It builds on python:3.13-slim-bookworm, installs gcc and g++, and runs the install with the JIT required and the dev dependency group included:

bash
MIASM_REQUIRE_JIT=1 pip3 install --group dev '.[cparser,z3,llvm]'

The container's default command is a test run rather than a shell prompt:

bash
docker build -t miasm .
docker run --rm miasm

That command executes /bin/bash -c "python test_all.py -m" from the test directory. If you build the image yourself, expect the test suite to be the first thing that runs.

For a first real use, the README's simplest example is disassembly through the Machine abstraction. It avoids the lifter and the jitter entirely, which makes it a fair check that the install works:

python
from miasm.analysis.machine import Machine
mn = Machine('x86_32').mn
print(mn.dis('\x33\x30', 32))

The output is XOR ESI, DWORD PTR [EAX]. The same pattern works for other architectures by changing the string, for example Machine('mips32b').mn with the byte string b'\x97\xa3\x00 ' and the mode string "b", which the README prints as LHU V1, 0x20(SP).

Where the framework pushes work back onto you

The README's own wording is a warning worth taking literally: the feature list is described as non exhaustive. There is no documented rollback story for the IR, no compatibility guarantee for the lifter output, and the README does not document error behaviour when an architecture's mnemo rejects an input. You find that out by running it.

The release history is the sharper constraint. The newest tagged release is v0.1.3 from 2019-12-12, preceded by v0.1.2 and v0.1.1. The version recorded in pyproject.toml is 0.1.5, and the classifier is Development Status :: 4 - Beta. In practice this means you should install from a git checkout or a pinned commit rather than expecting a release cadence to carry you, and you should expect internal APIs to move. The last push was on 2026-09-21, so the tree is being touched, but a moving master is not the same thing as a stable interface.

Two more boundaries are structural. First, the JIT is a compiled extension; setup.py reads MIASM_REQUIRE_JIT from the environment, which tells you the build can succeed without JIT support and that a silent absence is possible. If your analysis depends on emulation, verify the JIT is actually present rather than assuming it. Second, miasm is a library. There is no bundled user interface, no report generator, and no project file format. If you want a tool, you are writing it.

The wrong-tool case is the common one: you have a single suspicious binary and want to know what it does. Miasm will make you write the script that answers that, and the answer may not be better than what a mature interactive disassembler gives you in ten minutes.

Miasm against angr, and why the IR choice matters

The obvious comparison for symbolic execution is angr, which also offers symbolic execution of binaries from Python. The difference is where the abstraction lives. Angr's model is built around a simulated program state and path exploration at the level of a loaded binary; you ask it to explore and it manages states, constraints and memory for you. Miasm exposes the layer underneath: you get the mnemo, the lifter, the ircfg and the assignment blocks, and you assemble the analysis yourself. The README's symbolic execution example lives under example/symbol_exec rather than being the entry point.

That is a real trade-off in both directions. Miasm hands you get_rw on individual assignment blocks, which is a clean hook for custom data flow and expression simplification, and the de-obfuscation angle in the feature list follows from having that hook. Angr gives you a higher-level path explorer out of the box. If your problem is 'find the input that reaches this branch', the higher-level tool will get there sooner. If your problem is 'rewrite these expressions until the obfuscation falls apart', you want the IR in your hands.

Miasm's architecture coverage is also its own thing: X86, ARM, MIPS, SH4 and MSP430, with PE and ELF generation and modification listed alongside the analysis features. Generating binaries, not just reading them, is unusual in this space.

Licence and the cost of tracking master

Miasm is GPL-2.0, and pyproject.toml declares the SPDX identifier as GPL-2.0-only with license-files pointing at LICENSE. The Dockerfile carries its own GPL notice. GPL-2.0-only is a copyleft licence, which matters the moment you link miasm into something you distribute. Internal analysis tooling that never leaves the organisation is a different situation from a product that embeds the library. This is not legal advice; read LICENSE and decide with whoever handles licensing for you.

Upgrade cost is the practical question, and the material points one way. With the newest tag at v0.1.3 from 2019-12-12 and the version field at 0.1.5, the tagged releases are not a useful upgrade path. Pin a commit, keep the test suite runnable, and treat a rebase as a small project rather than a version bump. The dependency pins reinforce this: pyparsing is pinned to exactly 3.3.2, and the optional extras pin z3-solver==4.16.0.0 and llvmlite==0.44.0. Those exact pins will collide with other tools in the same environment sooner or later, and the fix is a virtualenv or the Docker image, not a loose constraint.

Editorial conclusion

Adopt miasm if you are building custom static or dynamic analysis and want a programmable IR, a JIT and a symbolic execution layer in one Python package. Do not adopt it if you want a point-and-click disassembler or a maintained stable API surface: the last push was on 2026-09-21, the newest tagged release is v0.1.3 from 2019-12-12, and pyproject.toml declares the classifier Development Status :: 4 - Beta. Before committing, run the test suite through the Dockerfile's test_all.py invocation and check that the architectures you care about are covered by the tests you can run yourself.

Frequently asked questions

What is cea-sec/miasm?

It is a free and open source GPLv2 reverse engineering framework written in Python. The README says it aims to analyze, modify and generate binary programs, with assembling and disassembling for X86, ARM, MIPS, SH4 and MSP430, an intermediate representation for assembly semantics, and JIT-based emulation.

Which Python versions does cea-sec/miasm require?

pyproject.toml sets requires-python to >=3.10 and lists classifiers for Python 3.10 through 3.13. The mandatory dependencies are future and pyparsing==3.3.2.

How do I install cea-sec/miasm?

pyproject.toml defines optional extras named cparser, z3, llvm, graph, crypto and all, and the Dockerfile installs the package with MIASM_REQUIRE_JIT=1 pip3 install --group dev '.[cparser,z3,llvm]' on top of gcc and g++. A plain pip3 install . from the repository root works for the base package.

Does cea-sec/miasm have stable releases I can track?

The newest tagged release listed is v0.1.3 from 2019-12-12, while pyproject.toml records version 0.1.5 and the classifier Development Status :: 4 - Beta. The repository's last push was on 2026-09-21, so the tree moves even though the tags do not.

What licence does cea-sec/miasm use?

It is GPL-2.0, and pyproject.toml declares the SPDX identifier as GPL-2.0-only with license-files set to LICENSE. The Dockerfile in the repository also carries a GNU General Public License notice.

Official sources

  1. cea-sec/miasm on GitHub
  2. License: GPL-2.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/cea-sec-miasm.svg)](https://hysenlabs.com/projects/cea-sec-miasm)