The TimeTravelEmulator
is a powerful IDA Pro plugin that brings the concept of time-travel debugging to your reverse engineering workflow. By integrating with the Unicorn emulation framework, it provides a unique capability to record and replay program execution, allowing for detailed analysis of runtime behavior.
English | ä¸ć–‡
- Emulation powered by Unicorn: Utilizes the Unicorn CPU emulator to execute code snippets or entire functions within IDA Pro.
- Comprehensive State Capture: Records detailed snapshots of the CPU registers and memory changes at each instruction executed.
- Time Travel Debugging:
- Forward and Backward Navigation: Seamlessly step forward (F3) and backward (F2) through the execution history.
- State Switching: Jump to any captured program state (Q) to analyze the exact conditions at a specific point in time.
- State Switching by ID: Jump to any captured program state by entering its unique
state_id
(I). Thestate_id
is formatted as$<instruction address>#<execution count>
, allowing precise navigation.
- Visualizing Differences: When switching between states, the plugin highlights the memory and register differences in the plugin interface,
- Memory and Register Tracking: Provides visibility into how memory and register values evolve during execution.
- Configurable Emulation:
- Set custom emulation ranges (start and end addresses).
- Load initial register values from the current debugger state (if a debugger is attached).
- Configure emulation step limits and timeouts.
- Option to set custom preprocessing code to set up the Unicorn environment before emulation.
- IDA Pro version >= 7.7
- Python version >= 3.8
- Use
pip install bsdiff4 capstone sortedcontainers unicorn
to install nessesary dependencies for this plugin in your IDAPython. - Place the
TimeTravelEmulator.py
file into your IDA Proplugins
directory. - Restart IDA Pro.

Press the hotkey Shift+T
to open the TimeTravel Emulator: Emulator Settings
dialog.
After the setting is completed, You can click "Emulate" to start the time-travel emulation.

Once emulation is completed, the plugin will create a independent view, you can use the following hotkeys to navigate through the recorded states in this view:
F3
: Move to the next recorded state.F2
: Move to the previous recorded state.Q
: Switch to a specific state by the instruction position where the cursor is located.
#include <iostream>
int main() {
volatile int a = 5;
volatile int b = 3;
volatile int result = 0;
int i = 0;
while (i < 32) {
result = result + i;
b += a;
i+= 1;
}
printf("Result: %d\n", result);
return 0;
}
Source code of a simple program for emulation.

Opening the emulation settings dialog by selecting code and using Shift+T
.
In the settings dialog, configure the emulation parameters:
-
Emulation Execute Range: Specify a start and end address, or select a function as the emulation range.
-
Emulate step limit: Set a limit on the number of instructions to emulate.
-
Emulate time out: Set a time limit for the emulation run.
-
load registers: Choose whether to load current register values (effective in debug mode).
-
Set Stack value: Configure special stack frame register values.
-
Skip interrupts: Skip
int
instructions during simulation -
Skip unloaded calls: Skip the call instructions whose target address not loaded
-
Skip thunk functions: Skip thunk functions during simulation
-
Log level & Log file path: Set logging level and save location for logs.

- Set custom preprocessing code: Add custom Python code to execute before emulation. This can be used to set up memory, register values, or add hooks.
Click "Emulate" to start the emulation. When the emulation is completed, a new window will open displaying the disassembly, register, and memory views, starting from the first emulated state.

This is the core view, highlighting the currently executed assembly instruction line. The number on the far left indicates how many times the current instruction has been executed throughout the emulation.
Use the following hotkeys for navigation:
F3
: Move to the next recorded state.F2
: Move to the previous recorded state.Q
: Jump to the state corresponding to the instruction at the cursor.I
: Prompt to enter astate_id
(e.g.,$0x401000#5
) to jump to a specific state.
When switching between states, these views will highlight the changed register values and memory bytes respectively, making it easy to identify differences.

In the memory view, you can select a range of bytes and press E
to print the content to the console.
The plugin also provides the following auxiliary views:

Use the hotkey C
to open the state chooser view. This view displays all saved states during the emulation. Double-click an entry to jump to the corresponding state.

The plugin employs a lazy-loading mechanism for memory pages during emulation, meaning pages are mapped and loaded only when accessed by an instruction.
Use hotkey M
to open this view and quickly ascertain the memory pages loaded in the current state.
Use hotkey D
to open the difference chooser view. This view automatically updates when switching states, providing a clear visual representation of memory and register changes between the two states.

The plugin supports emulation in IDA's debugging mode and can automatically load the current register values.

When the simulation execution flow enters a segment of data that the IDA does not recognize as executable code, the plugin disassembles the data using the Capstone engine.
The plugin currently supports x86 (32-bit) and x64 (64-bit) architectures. More architectures will be added in the future.
Contributions are welcome! Please feel free to open issues or submit pull requests.