Metadata-Version: 2.5
Name: microtaint
Version: 0.7.3
Summary: Bit-precise taint rules generation using Ghidra's P-Code.
Project-URL: Homepage, https://github.com/toby-bro/microtaint
Project-URL: Repository, https://github.com/toby-bro/microtaint
Project-URL: Issues, https://github.com/toby-bro/microtaint/issues
License-Expression: LGPL-2.0-only
License-File: LICENSE
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.12
Requires-Dist: pypcode>=4.0.0
Requires-Dist: qiling>=1.4.6
Requires-Dist: unicorn>=2.1.4
Description-Content-Type: text/markdown

# Microtaint

## Code artifacts

The artifacts for NDSS27 are present in the [artifacts/ndss27](./artifacts/ndss27/) subdirectory, in which there is a [README](./artifacts/ndss27/README.md) explaining how to reproduce all the results presented in the paper.

They are archived at [`10.5281/zenodo.22865047`](https://doi.org/10.5281/zenodo.22865047).

## Introduction

Microtaint is a strictly typed Python library and command-line engine for performing **bit-precise, dynamic Information Flow Tracking (IFT)** on compiled binaries.

Originally an abstract rule generator based on the **CELLIFT** paradigm, Microtaint has evolved into a complete, out-of-the-box dynamic taint analysis emulator. Built on top of [Qiling](https://github.com/qilingframework/qiling) and [Unicorn](https://github.com/unicorn-engine/unicorn), it dynamically monitors program execution, identifies complex exploitation primitives (Buffer Overflows, Use-After-Frees, Side Channels, and Arbitrary Indexed Writes) and logs them in real-time.

It retains its foundational mathematical precision: behind the scenes, Microtaint still lifts executed instructions using Ghidra's P-Code ([pypcode](https://github.com/angr/pypcode)) and models them as logical ASTs, computing taint propagation rigorously down to individual carry/zero flags and partial register mutations.

## Features

- **Out-of-the-box Vulnerability Hunting:** Pre-built command-line flags to instantaneously trace standard input flows and check for vulnerabilities:
  - **BOF (Buffer Overflow):** Detects when the instruction pointer (RIP/PC) becomes tainted.
  - **UAF (Use After Free):** Monitors heap operations via a built-in `HeapTracker` and alarms on poisoned mapping accesses.
  - **AIW (Arbitrary Indexed Write):** Detects store operations executing with tainted pointer addresses.
  - **SC (Side Channels):** Emits findings when critical conditional branching decisions depend on tainted input.
- **Qiling-Powered Emulation Wrapper:** Fully integrates with the Qiling Framework. Drop your ELF/PE/Mach-O binaries in with a custom rootfs, and Microtaint wraps the CPU states gracefully.
- **High-Performance Tracing:** Built-in Cython `BitPreciseShadowMemory`, direct Unicorn state hooks, and custom JIT caching ensure fast execution capabilities.
- **Bit-Precise Rule Generation:** Still capable of generating mathematical formulas statically (via `generate_static_rule`), treating raw assembly instructions as monolithic logical circuits evaluated using simulated differentials.

## Installation

Microtaint is available on the [pypi](https://pypi.org/project/microtaint/), so you can use uv/pip/your_favorite_tool to install it.

If you want to build it locally then once you cloned the repo you can use `uv` to build it.

```sh
uv sync --reinstall-package=microtaint
```

That build targets the baseline x86-64, so the result runs anywhere. To tune it
for the machine you are on, which is what you want for timing work:

```sh
CFLAGS="-march=native" uv sync --reinstall-package=microtaint
```

Published wheels are never built that way. `-march=native` on a build machine
bakes in whatever that CPU happens to support, and a wheel is installed on
machines that are not the one that built it.

### macOS on Apple Silicon

Emulation needs one extra step there, and it is not ours to fix:

```sh
brew install keystone
sudo cp -L "$(brew --prefix)/lib/libkeystone.dylib" /usr/local/lib/
```

`keystone-engine` is a dependency of Qiling. Its last release is 0.9.2, from
June 2020, which predates Apple Silicon and ships wheels only for
`macosx_10_14_x86_64`, `manylinux1` and Windows. With no arm64 library to
load, its loader falls through to `import distutils.sysconfig`, and
`distutils` was removed in Python 3.12, so what you actually see is
`ModuleNotFoundError: No module named 'distutils'` followed by Qiling
reporting `Unable to import module .arch.x86`. The real cause is the missing
library, not distutils.

Homebrew ships keystone 0.9.2 with arm64 bottles, the same version as the
Python binding, so the two match. `/usr/local/lib` is where the binding
looks, and it is on the default dyld search path, so no `DYLD_LIBRARY_PATH`
is needed (System Integrity Protection would strip it anyway).

The taint API itself does not need any of this; only emulating a guest does.
Tracked upstream as [keystone-engine#588](https://github.com/keystone-engine/keystone/issues/588)
for the distutils half. Nothing upstream tracks the missing arm64 wheel.

## Command Line Usage

Use the provided `microtaint` command to execute and dynamically analyze a binary. Provide flags before the `--` separator. Any arguments after `--` represent the execution format for your compiled target.

```bash
# Detect everything, feed stdin automatically from the terminal
uv run microtaint --check-all -- ./binary arg1 arg2

# Read binary taint source from a specific file instead of stdin
uv run microtaint --check-bof --input payload.bin -- ./binary

# Pipe raw data directly to the binary while applying the UAF trace
python -c "print('A'*64)" | uv run microtaint --check-uaf -- ./binary

# Execute quietly and emit structured JSON findings (useful for CI/fuzzers)
uv run microtaint --check-all --quiet --json -- ./binary 2>/dev/null
```

## Python API Integration

### 1. Qiling Emulator Integration (High-Level)

The `MicrotaintWrapper` can be integrated manually onto any existing Qiling instance. This provides fine-grained control to programmatically trace or assert bitwise taints seamlessly during full-system/binary emulation.

```python
from qiling import Qiling
from microtaint.emulator.wrapper import MicrotaintWrapper

# Setup standard Qiling Environment
ql = Qiling(["path/to/binary"], rootfs="/custom/rootfs")

# Mount Bit-Precise Taint Engine on top
wrapper = MicrotaintWrapper(ql)

# Enable active security modules
wrapper.check_bof = True  # Track instruction pointers
wrapper.check_aiw = True  # Track memory addresses
wrapper.check_uaf = True  # Monitor frees

# Taint specific memory regions: one mask byte per memory byte,
# so 12 fully tainted bytes at 0x1000
wrapper.taint_region(0x1000, b"\xff" * 12)

# Run Emulator
ql.run()

# Review findings identified by the Reporter
for finding in wrapper.reporter.findings:
    print(finding)
```

### 2. Stateless AST Generation (Low-Level)

For cases where you don't need full emulation but want to analyze the math and formulas of taint propagation for a specific instruction byte string, you can directly interface with the static generator and native evaluator:

```python
from microtaint.sleigh.engine import generate_static_rule
from microtaint.simulator import CellSimulator
from microtaint.instrumentation.ast import EvalContext
from microtaint.types import Architecture, Register

arch = Architecture.AMD64
simulator = CellSimulator(arch)

# 1. Provide an instruction (AND EAX, 0x0F0F)
bytestring = bytes.fromhex('250f0f0000')

# 2. Lift it into a stateless logical circuit (AST)
circuit = generate_static_rule(arch, bytestring, [Register('RAX', 64)])

# 3. Form a concrete runtime execution context
ctx = EvalContext(
    input_values={'RAX': 0xFFFF},
    input_taint={'RAX': 0xFFFF},
    simulator=simulator
)

# 4. Mathematically evaluate how the taint propagates bit-by-bit
output_taint = circuit.evaluate(ctx)
# output_taint['RAX'] bitmask mathematically evaluates to 0x0F0F
```

## Development & Testing

Run tests and check typings/formatting with:

```bash
uv run mypy .
uv run ruff check .
uv run pytest
```

If a C/Cython file has been modified it is necessary to force a rebuild of the .so shared libraries with a

```sh
uv sync --reinstall-package=microtaint
```
