Files
resimulate/resimulate.py
Niklas Bittner 4a12d1add4
Some checks failed
Build Python Package / build (push) Failing after 22s
fix: replay issues
2025-02-13 17:02:25 +01:00

125 lines
3.5 KiB
Python
Executable File

#!/usr/bin/env python
# PYTHON_ARGCOMPLETE_OK
import argparse
import importlib.metadata
import logging
import argcomplete
from pySim.apdu_source.gsmtap import GsmtapApduSource
from rich_argparse import RichHelpFormatter
from resimulate.commands.record import Recorder
from resimulate.commands.replay import Replayer
from resimulate.util.logger import log
parser = argparse.ArgumentParser(
description="ReSIMulate is a terminal application built for eSIM and SIM-specific APDU analysis. It captures APDU commands, saves them, and replays them to facilitate differential testing, ensuring accurate validation and debugging of SIM interactions.",
formatter_class=RichHelpFormatter,
)
parser.add_argument(
"--version",
action="version",
version=f"%(prog)s {importlib.metadata.version('resimulate')}",
)
parser.add_argument(
"-v",
"--verbose",
action="store_true",
help="Enable verbose output during replay.",
required=False,
)
global_arg_parser = argparse.ArgumentParser(add_help=False)
subparsers = parser.add_subparsers(
title="Commands",
dest="command",
required=True,
help="Available commands: record, replay",
)
# Record command
record_parser = subparsers.add_parser(
"record",
parents=[global_arg_parser],
help="Record APDU commands from a specified source. Uses the SIMtrace2 GSMTAP to capture APDUs via UDP.",
)
record_parser.add_argument(
"-o",
"--output",
required=True,
type=str,
help="File to save recorded APDU commands (e.g., 'commands.apdu').",
)
record_parser.add_argument(
"--isd-r",
type=str,
default="default",
choices=["default", "5ber"],
help="ISD-R to use for recording APDU commands (default: '%(default)s').",
)
record_parser.add_argument(
"-i",
"--bind-ip",
default="127.0.0.1",
help="Local IP address to which to bind the UDP port. (default: %(default)s)",
)
record_parser.add_argument(
"-p", "--bind-port", default=4729, help="Local UDP port. (default: %(default)s)"
)
record_parser.add_argument(
"-t",
"--timeout",
type=int,
default=15,
help="Timeout in seconds for recording (default: 10).",
)
# Replay command
replay_parser = subparsers.add_parser(
"replay",
parents=[global_arg_parser],
help="Replay saved APDU commands to a target device.",
)
replay_parser.add_argument(
"-i",
"--input",
required=True,
type=argparse.FileType("rb"),
help="File containing APDU commands to replay (e.g., 'commands.apdu').",
)
replay_parser.add_argument(
"-p",
"--pcsc-device",
type=int,
default=0,
help="Target PC/SC device to send APDU commands (default: %(default)s).",
)
replay_parser.add_argument(
"--target-isd-r",
type=str,
default="default",
choices=["default", "5ber"],
help="Target ISD-R AID to use for replaying APDU commands (default: '%(default)s').",
)
if __name__ == "__main__":
# TODO: Configure argcomplete for shell tab completion
# argcomplete.autocomplete(parser)
args = parser.parse_args()
log.setLevel(logging.DEBUG if args.verbose else logging.INFO)
if args.command == "record":
source = GsmtapApduSource(args.bind_ip, args.bind_port)
recorder = Recorder(source, args.isd_r)
recorder.record(args.output, args.timeout)
elif args.command == "replay":
replayer = Replayer(args.pcsc_device, args.target_isd_r)
replayer.replay(args.input.name)
else:
raise ValueError(f"Unsupported command: {args.command}")