This project provides a lightweight Unicorn engine-based ARM64 dynamic tracing emulation tool that can run as an IDA Pro plugin or standalone. The tool integrates tightly with IDA to ensure execution consistency and avoid errors. It provides reliable simulation reproduction capabilities and generates beautiful Tenet logs for debugging and analysis. Key features include dynamic code simulation, memory dumping, register state tracking, and instruction-level logging.
The tool doesn't require full memory dumps, instead dynamically dumping memory on demand during execution, making it highly efficient. Process verification ensures the entire acquisition process is complete and error-free. As a trace tool, it's particularly useful for VM analysis with good applicability and speed. Performance may be affected when dealing with numerous external function calls, which may be optimized in the future.
-
IDA Integration Plugin (
dyn_trace_ida.py)- Configure simulation parameters via GUI (end address, SO name, TPIDR value, etc.)
- Automatically dump memory segments and register states
- Support Tenet-compatible trace logs
- Error handling (memory access exceptions, range checks, etc.)
-
Standalone Emulator (
local_emu.py)- Load memory maps and register states from files
- Custom simulation ranges
- Generate detailed execution logs (
uc.logandtenet.log) - Skip external function calls automatically
- Merge trace logs from multiple execution segments
- Support for continuous execution across memory dumps
-
Single Script Mode (
single_script/dynamic_dump.py)- Direct execution in IDA without library dependencies
- Lightweight alternative to the full plugin
.
├── dyn_trace_ida.py # IDA plugin version
├── local_emu.py # Standalone emulator
├── unicorn_trace/ # Emulator core
│ └── unicorn_class.py # ARM64 emulator base class
├── single_script/ # Utility scripts
│ ├── dynamic_dump.py # IDA single-script version
│ └── dump_single.py # Single dump script (not provided)
├── imgs/ # Screenshots and GIFs
│ ├── 1.gif
│ ├── 2.gif
│ └── 3.gif
├── example.py # Example for emulator
├── README.md # English documentation
└── README_zh.md # Chinese documentation
pip install unicorn capstonePlace dyn_trace_ida.py and the unicorn_trace folder in IDA's plugins directory
Use single_script/dynamic_dump.py directly in IDA debugging without library files
Run to specified location in IDA, write the target run address, and it will automatically run and record the trace to the end address
- Open configuration window with
Ctrl-Alt-Uin IDA - Set parameters:
- End address (relative offset)
- SO name (optional, required for Tenet)
- TPIDR value (optional, required if errors occur)
- Output path (optional, default local)
- Enable Tenet logging (optional, not recommended as it affects efficiency; suggest offline updates)
- Click confirm to start simulation
If plugin is installed, use dyn_trace_ida.py directly. Otherwise use dynamic_dump.py from single_script.
Fill required parameters in main function (same as above)
Run a single dump section.
from local_emu import run_once
if __name__ == "__main__":
result = run_once(
dump_path="./dumps",
so_path="/path/to/your.so",
end_addr_relative=0x000000
)from unicorn_trace import SelfRunArm64Emulator
# Initialize emulator
emulator = SelfRunArm64Emulator()
emulator.setup_from_files("libtarget.so", "./dumps")
# Run simulation
result = emulator.custom_main_trace(
so_name="libtarget.so",
end_addr=0x123456,
tenet_log_path="./trace.log",
user_log_path="./sim.log",
load_dumps_path="./dumps"
)When dealing with code that contains multiple external function calls, the plugin creates separate dump folders for each execution segment. The run_all_continuous function in local_emu.py allows you to execute all these segments in order, skipping external calls and merging the trace logs.
# In local_emu.py or your own script
from local_emu import run_all_continuous
# Execute all dump folders in chronological order
success = run_all_continuous(
dump_path="./tmp",
so_path="/path/to/your.so",
end_addr_relative=end_addr
)
if success:
print("Continuous execution completed successfully!")
else:
print("Continuous execution failed or incomplete.")- Sort dump folders: Automatically sorts
dump_<timestamp>folders by timestamp (oldest first) - Continuous execution: Executes each dump folder in order, starting from the first
- External call skipping: When encountering external function calls (result_code == 1), automatically continues with the next dump folder
- Trace merging: Combines all execution logs into continuous
continuous_sim.logandcontinuous_tenet.logfiles - State preservation: Maintains register state across execution segments (when supported by the emulator)
- Seamless analysis: Get a continuous trace even when code calls external libraries
- Time-ordered execution: Ensures execution follows the actual temporal sequence
- Automated workflow: No need to manually run each dump folder separately
- Consolidated logs: All trace data in one place for easier analysis
See example.py
Also see Kanxue Article
-
Dynamic Execution, Memory Dump, Save State: Use plugin or script to run to end position
-
Analyze Trace, Generate Tenet Log: Use
local_emu.pyto generate tenet.log and combine all logs -
Log Analysis, Offline Simulation:
- Memory region dumping affects efficiency - larger
DUMP_SINGLE_SEG_SIZEis slower, smaller may cause errors - Exception handling support:
- Memory access errors (UC_ERR_READ_UNMAPPED)
- Range violations (Code Run out of range)
- AUTIASP instruction exceptions
- B4 register handling
- UNICORN runtime comparison with IDA
- Each run is independent - if an error occurs mid-run, existing dump folders are unaffected. Just delete the latest error dump file and rerun after fixing the issue
- Single round external call limit is 50 (shows
restartwhen exceeded). ModifyROUND_MAXin code to change
Common error codes:
- Missing
TPIDR: Need PC value near error (or check log assembly), manually debug tomrs xxxlocation to getTPIDRregister value. This occurs because IDA can't retrieve it, though it remains constant throughout execution - IDA breakpoints causing errors: Disable all IDA breakpoints before running to avoid errors during comparison and call skipping
- IDA errors: IDA errors pause execution - just restart
Execute a single dump folder.
Parameters:
dump_path: Path to the dump folderso_path: Path to the shared object fileend_addr_relative: Target address relative to basetdpr: Optional TPIDR register value
Returns:
- Result code (114514 for success, other codes for errors)
Execute multiple dump folders continuously.
Parameters:
dump_path: Path containing dump foldersso_path: Path to the shared object fileend_addr_relative: Target address relative to basetdpr: Optional TPIDR register value
Returns:
Trueif execution reached target address,Falseotherwise
Legacy main function for single execution.
Main emulator class for standalone execution.
Key methods:
setup_from_files(so_path, load_path): Initialize from dump filescustom_main_trace(so_name, end_addr, tenet_log_path=None, user_log_path="./uc.log", load_dumps_path="./dumps"): Execute simulation
IDA-integrated emulator class (used by plugin).
Welcome to submit Issues or Pull Requests. Please ensure:
- Follow existing code style
- Add necessary unit tests
- Update relevant documentation
- ✓ Continuous execution: Added
run_all_continuousfunction inlocal_emu.pyto execute multiple dump folders in order, skip external calls, and merge trace logs - ✓ Improve efficiency: Continue execution after mid-process memory dumps instead of restarting
- Multi-architecture support
- Better state preservation across execution segments
- Enhanced external call detection and handling
- Performance optimization for large memory dumps
- GUI interface for continuous execution configuration
Tenet IDA 9.0: https://github.com/jiqiu2022/Tenet-IDA9.0
Tenet: https://github.com/gaasedelen/tenet
Unicorn Engine: https://github.com/unicorn-engine/unicorn
Capstone Engine: https://github.com/capstone-engine/capstone


