Migrate bookmarks from 2.5 to 2.6

Purpose

We fixed an issue in Reven 2.6 leading to some changes in the transition number for QEMU scenarios.

This script is here to help you migrate your bookmarks if they are off after replaying your scenario with Reven 2.6.

How to use

Launch after updating the trace resource for your scenario to Reven 2.6+.

usage: migrate_bookmarks_2.5_to_2.6.py [-h] [--host HOST] [-p PORT]

optional arguments:
  -h, --help            show this help message and exit
  --host HOST           Reven host, as a string (default: "localhost")
  -p PORT, --port PORT  Reven port, as an int (default: 13370)

Known limitations

  • It also does not attempt to determine whether the scenario needs to be upgraded or not. Applying the script when bookmarks don't need to be upgraded will actually put them at the wrong position. Apply only if you notice that the bookmarks have been put at the wrong position after updating.

Supported versions

Reven 2.6+

Supported perimeter

Reven scenarios recorded with QEMU.

Dependencies

None.

Source

#!/usr/bin/env python3

import argparse
import sys

import reven2

"""
# Migrate bookmarks from 2.5 to 2.6

## Purpose

We fixed an issue in Reven 2.6 leading to some changes in the transition number for QEMU scenarios.

This script is here to help you migrate your bookmarks if they are off after replaying your scenario with Reven 2.6.

## How to use

Launch after updating the trace resource for your scenario to Reven 2.6+.

```bash
usage: migrate_bookmarks_2.5_to_2.6.py [-h] [--host HOST] [-p PORT]

optional arguments:
  -h, --help            show this help message and exit
  --host HOST           Reven host, as a string (default: "localhost")
  -p PORT, --port PORT  Reven port, as an int (default: 13370)
```

## Known limitations

- It also does not attempt to determine whether the scenario needs to be upgraded or not.
Applying the script when bookmarks don't need to be upgraded will actually put them at the wrong position.
Apply only if you notice that the bookmarks have been put at the wrong position after updating.

## Supported versions

Reven 2.6+

## Supported perimeter

Reven scenarios recorded with QEMU.

## Dependencies

None.
"""


def migrate_bookmarks(reven_server):
    offset_table = {}

    def get_offset(transition_id):
        lower_bound = None
        for key in offset_table.keys():
            if key <= transition_id and (lower_bound is None or lower_bound < key):
                lower_bound = key
        return offset_table[lower_bound] if lower_bound is not None else 0

    print("Generating offset table...")

    c = reven_server.trace.context_before(0)

    counter = 0
    while c is not None:
        c = c.find_register_change(reven2.arch.x64.cr2)

        if c is None:
            continue

        t_exception = c.transition_before()
        t_before_exception = t_exception - 1

        ctx_before = t_exception.context_before()
        ctx_after = t_exception.context_after()

        # We are looking for code pagefault, so CR2 will contains PC
        cr2 = ctx_after.read(reven2.arch.x64.cr2)

        if ctx_before.is64b():
            if cr2 != ctx_before.read(reven2.arch.x64.rip):
                continue
        else:
            if cr2 != ctx_before.read(reven2.arch.x64.eip):
                continue

        try:
            # The issues occurred when the previous instruction was just doing some reads and not any write
            # Warning: This could not work if the trace is desync with the memory
            next(t_before_exception.memory_accesses(operation=reven2.memhist.MemoryAccessOperation.Write))
        except StopIteration:
            counter += 1
            offset_table[t_exception.id - counter] = counter

    print("Migrating bookmarks...")

    for bookmark in list(reven_server.bookmarks.all()):
        offset = get_offset(bookmark.transition.id)

        print(
            "    id: %d | %60.60s | Transition #%d => #%d (+%d)"
            % (bookmark.id, bookmark.description, bookmark.transition.id, bookmark.transition.id + offset, offset)
        )

        if offset == 0:
            continue

        reven_server.bookmarks.add(bookmark.transition + offset, bookmark.description)
        reven_server.bookmarks.remove(bookmark)


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--host", type=str, default="localhost", help='Reven host, as a string (default: "localhost")')
    parser.add_argument("-p", "--port", type=int, default=13370, help="Reven port, as an int (default: 13370)")
    args = parser.parse_args()

    answer = ""
    while answer not in ["y", "n"]:
        answer = input(
            "This script should be launched on a QEMU scenario with the trace generated with Reven 2.6 with bookmarks"
            " that were added in Reven 2.5 or older. Do you want to continue [Y/N]? "
        ).lower()

    if answer == "n":
        print("Aborting")
        sys.exit(0)

    reven_server = reven2.RevenServer(args.host, args.port)
    migrate_bookmarks(reven_server)
    print("Bookmarks migrated!")