Strings statistics

Purpose

Display statistics about strings accesses such as:

  • binary that read/write a string.
  • number of read/write accesses a binary does on a string.

How to use

usage: strings_stat.py [-h] [--host HOST] [--port PORT] [-v] [pattern]

Display statistics about strings accesses.

positional arguments:
  pattern        Pattern of the string, looking for "*pattern*", does not
                 support Regular Expression. If no pattern provided, all
                 strings will be used.

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

Known limitations

N/A

Supported versions

REVEN 2.2+

Supported perimeter

Any REVEN scenario.

Dependencies

The script requires that the target REVEN scenario have: * The Strings feature replayed. * The OSSI feature replayed.

Source

import argparse
import builtins
import logging

import reven2


'''
# Strings statistics

## Purpose

Display statistics about strings accesses such as:
  * binary that read/write a string.
  * number of read/write accesses a binary does on a string.

## How to use

```bash
usage: strings_stat.py [-h] [--host HOST] [--port PORT] [-v] [pattern]

Display statistics about strings accesses.

positional arguments:
  pattern        Pattern of the string, looking for "*pattern*", does not
                 support Regular Expression. If no pattern provided, all
                 strings will be used.

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

## Known limitations

N/A

## Supported versions

REVEN 2.2+

## Supported perimeter

Any REVEN scenario.

## Dependencies

The script requires that the target REVEN scenario have:
    * The Strings feature replayed.
    * The OSSI feature replayed.
'''


class BinaryStringOperations(object):
    def __init__(self, binary):
        self.binary = binary
        self.read_count = 0
        self.write_count = 0


def strings_stat(reven_server, pattern=''):
    for string in reven_server.trace.strings(args.pattern):
        binaries = builtins.dict()
        try:
            # iterates on all accesses to all binaries that access to the string (read/write).
            for memory_access in string.memory_accesses():
                ctx = memory_access.transition.context_before()
                if ctx.ossi.location() is None:
                    continue
                binary = ctx.ossi.location().binary
                try:
                    binary_operations = binaries[binary.path]
                except KeyError:
                    binaries[binary.path] = BinaryStringOperations(binary)
                    binary_operations = binaries[binary.path]
                if memory_access.operation == reven2.memhist.MemoryAccessOperation.Read:
                    binary_operations.read_count += 1
                else:
                    binary_operations.write_count += 1
        except RuntimeError:
            # Limitation of `memory_accesses` method that raise a RuntimeError when
            # the service timeout.
            pass
        yield (string, binaries)


def parse_args():
    parser = argparse.ArgumentParser(description='Display statistics about strings accesses.')
    parser.add_argument('--host', dest='host', help='Reven host, as a string (default: "localhost")',
                        default='localhost', type=str)
    parser.add_argument('--port', dest='port', help='Reven port, as an int (default: 13370)',
                        type=int, default=13370)
    parser.add_argument('-v', '--verbose', dest='log_level', help='Increase output verbosity',
                        action='store_const', const=logging.DEBUG, default=logging.INFO)
    parser.add_argument('pattern', nargs='?', help='Pattern of the string, looking for '
                        '"*pattern*", does not support Regular Expression. If no pattern provided, '
                        'all strings will be used.',
                        default='', type=str)
    return parser.parse_args()


if __name__ == '__main__':
    args = parse_args()

    logging.basicConfig(format='%(message)s', level=args.log_level)

    logging.debug('##### Getting stat for all strings containing "{0}" #####\n'.format(args.pattern))

    # Get a server instance
    reven_server = reven2.RevenServer(args.host, args.port)

    # Print strings
    for string, binaries in strings_stat(reven_server, args.pattern):
        logging.info('"{}":'.format(string.data))
        for binary_operations in binaries.values():
            logging.info('\t- {} (Read: {} - Write: {})'.format(binary_operations.binary.filename,
                                                                binary_operations.read_count,
                                                                binary_operations.write_count))
        logging.info('')
    logging.debug('##### Done #####')