2021-05-01 10:05:21 +00:00
|
|
|
#!/usr/bin/env python3
|
2021-06-10 10:40:48 +00:00
|
|
|
# SPDX-License-Identifier: MIT
|
2021-06-20 17:03:36 +00:00
|
|
|
import sys, pathlib, traceback
|
2021-06-10 10:40:48 +00:00
|
|
|
sys.path.append(str(pathlib.Path(__file__).resolve().parents[1]))
|
2021-05-01 10:05:21 +00:00
|
|
|
|
|
|
|
import argparse, pathlib
|
2022-06-06 12:50:54 +00:00
|
|
|
from io import BytesIO
|
2021-05-01 10:05:21 +00:00
|
|
|
|
2022-08-01 09:35:17 +00:00
|
|
|
def volumespec(s):
|
|
|
|
return tuple(s.split(":", 2))
|
|
|
|
|
2021-05-01 10:05:21 +00:00
|
|
|
parser = argparse.ArgumentParser(description='Run a Mach-O payload under the hypervisor')
|
2021-05-13 10:02:35 +00:00
|
|
|
parser.add_argument('-s', '--symbols', type=pathlib.Path)
|
2021-06-11 02:57:57 +00:00
|
|
|
parser.add_argument('-m', '--script', type=pathlib.Path, action='append', default=[])
|
|
|
|
parser.add_argument('-c', '--command', action="append", default=[])
|
2021-06-10 13:34:29 +00:00
|
|
|
parser.add_argument('-S', '--shell', action="store_true")
|
2021-09-15 13:10:07 +00:00
|
|
|
parser.add_argument('-e', '--hook-exceptions', action="store_true")
|
2021-09-21 04:15:24 +00:00
|
|
|
parser.add_argument('-d', '--debug-xnu', action="store_true")
|
2021-11-03 18:58:51 +00:00
|
|
|
parser.add_argument('-l', '--logfile', type=pathlib.Path)
|
2022-03-14 12:08:23 +00:00
|
|
|
parser.add_argument('-C', '--cpus', default=None)
|
2022-06-22 00:04:42 +00:00
|
|
|
parser.add_argument('-r', '--raw', action="store_true")
|
2022-08-30 13:39:20 +00:00
|
|
|
parser.add_argument('-E', '--entry-point', action="store", type=int, help="Entry point for the raw image", default=0x800)
|
2022-06-06 12:50:54 +00:00
|
|
|
parser.add_argument('-a', '--append-payload', type=pathlib.Path, action="append", default=[])
|
2022-08-01 09:35:17 +00:00
|
|
|
parser.add_argument('-v', '--volume', type=volumespec, action='append',
|
|
|
|
help='Attach a 9P virtio device for file export to the guest. The argument is a host path to the '
|
|
|
|
'exported tree, joined by colon (\':\') with a tag under which the tree will be advertised '
|
|
|
|
'on the guest side.')
|
2021-05-01 10:05:21 +00:00
|
|
|
parser.add_argument('payload', type=pathlib.Path)
|
2021-05-08 18:18:08 +00:00
|
|
|
parser.add_argument('boot_args', default=[], nargs="*")
|
2021-05-01 10:05:21 +00:00
|
|
|
args = parser.parse_args()
|
|
|
|
|
2021-06-10 10:40:48 +00:00
|
|
|
from m1n1.proxy import *
|
|
|
|
from m1n1.proxyutils import *
|
|
|
|
from m1n1.utils import *
|
2021-06-10 13:34:29 +00:00
|
|
|
from m1n1.shell import run_shell
|
2021-06-10 10:40:48 +00:00
|
|
|
from m1n1.hv import HV
|
2022-08-01 09:35:17 +00:00
|
|
|
from m1n1.hv.virtio import Virtio9PTransport
|
2022-06-05 08:03:45 +00:00
|
|
|
from m1n1.hw.pmu import PMU
|
2021-05-01 10:05:21 +00:00
|
|
|
|
|
|
|
iface = UartInterface()
|
|
|
|
p = M1N1Proxy(iface, debug=False)
|
|
|
|
bootstrap_port(iface, p)
|
|
|
|
u = ProxyUtils(p, heap_size = 128 * 1024 * 1024)
|
|
|
|
|
|
|
|
hv = HV(iface, p, u)
|
|
|
|
|
2021-09-15 13:10:07 +00:00
|
|
|
hv.hook_exceptions = args.hook_exceptions
|
|
|
|
|
2021-05-01 10:05:21 +00:00
|
|
|
hv.init()
|
2021-05-08 18:18:08 +00:00
|
|
|
|
2022-03-14 12:08:23 +00:00
|
|
|
if args.cpus:
|
|
|
|
avail = [i.name for i in hv.adt["/cpus"]]
|
|
|
|
want = set(f"cpu{i}" for i in args.cpus)
|
|
|
|
for cpu in avail:
|
|
|
|
if cpu in want:
|
|
|
|
continue
|
|
|
|
try:
|
|
|
|
del hv.adt[f"/cpus/{cpu}"]
|
|
|
|
print(f"Disabled {cpu}")
|
|
|
|
except KeyError:
|
|
|
|
continue
|
|
|
|
|
2021-09-21 04:15:24 +00:00
|
|
|
if args.debug_xnu:
|
|
|
|
hv.adt["chosen"].debug_enabled = 1
|
|
|
|
|
2022-08-01 09:35:17 +00:00
|
|
|
if args.volume:
|
|
|
|
for path, tag in args.volume:
|
|
|
|
hv.attach_virtio(Virtio9PTransport(root=path, tag=tag))
|
|
|
|
|
2021-11-03 18:58:51 +00:00
|
|
|
if args.logfile:
|
|
|
|
hv.set_logfile(args.logfile.open("w"))
|
|
|
|
|
2021-05-08 18:18:08 +00:00
|
|
|
if len(args.boot_args) > 0:
|
|
|
|
boot_args = " ".join(args.boot_args)
|
|
|
|
hv.set_bootargs(boot_args)
|
|
|
|
|
2021-05-13 10:02:35 +00:00
|
|
|
symfile = None
|
|
|
|
if args.symbols:
|
|
|
|
symfile = args.symbols.open("rb")
|
2022-06-06 12:50:54 +00:00
|
|
|
|
|
|
|
payload = args.payload.open("rb")
|
|
|
|
|
|
|
|
if args.append_payload:
|
|
|
|
concat = BytesIO()
|
|
|
|
concat.write(payload.read())
|
|
|
|
for part in args.append_payload:
|
|
|
|
concat.write(part.open("rb").read())
|
|
|
|
concat.seek(0)
|
|
|
|
payload = concat
|
|
|
|
|
2022-06-22 00:04:42 +00:00
|
|
|
if args.raw:
|
2022-08-30 13:39:20 +00:00
|
|
|
hv.load_raw(payload.read(), args.entry_point)
|
2022-06-22 00:04:42 +00:00
|
|
|
else:
|
2022-06-06 12:50:54 +00:00
|
|
|
hv.load_macho(payload, symfile=symfile)
|
2021-06-10 13:34:29 +00:00
|
|
|
|
2022-06-05 08:03:45 +00:00
|
|
|
PMU(u).reset_panic_counter()
|
|
|
|
|
2021-06-10 13:34:29 +00:00
|
|
|
for i in args.script:
|
2021-06-20 17:03:36 +00:00
|
|
|
try:
|
|
|
|
hv.run_script(i)
|
|
|
|
except:
|
|
|
|
traceback.print_exc()
|
|
|
|
args.shell = True
|
2021-06-10 13:34:29 +00:00
|
|
|
|
|
|
|
for i in args.command:
|
2021-06-20 17:03:36 +00:00
|
|
|
try:
|
|
|
|
hv.run_code(i)
|
|
|
|
except:
|
|
|
|
traceback.print_exc()
|
|
|
|
args.shell = True
|
2021-06-10 13:34:29 +00:00
|
|
|
|
|
|
|
if args.shell:
|
2022-08-30 12:42:00 +00:00
|
|
|
run_shell(hv.shell_locals, "Entering hypervisor shell. Type ^D to start the guest.")
|
|
|
|
|
|
|
|
hv.start()
|