Skip to content

Instantly share code, notes, and snippets.

@jevinskie
Created July 14, 2023 02:34
Show Gist options
  • Save jevinskie/801163b71f0845e6c3487413cb7706b0 to your computer and use it in GitHub Desktop.
Save jevinskie/801163b71f0845e6c3487413cb7706b0 to your computer and use it in GitHub Desktop.
xnu-unsuspend
jevin@wombat [22:32:18] [~/code/mac/widget/xnu_unsuspend] [main *]
-> % sudo taskinfo 'Deliveries Widget'
process: "Deliveries Widget" [30145] [unique ID: 1220404]
architecture: arm64
coalition (type 0) ID: 105936
coalition (type 1) ID: 591
suspend count: 1
virtual bytes: 389.40 GB; phys_footprint bytes: 8.92 MB; phys_footprint lifetime maximum bytes: 8.92 MB
run time: 42 s
user/system time (current threads): 0.046565 s / 0.036279 s
user/system time (terminated threads): 0.000000 s / 0.000000 s
P-time: 0.077003 s (92%)
P/E switches: 11
energy used (nJ): 191087703
interrupt wakeups: 3 (0 / 0.00% from platform idle)
default sched policy: POLICY_TIMESHARE
CPU usage monitor: 50% CPU over 180 seconds
CPU wakes monitor: 150 wakes per second (over system-default time period)
dirty tracking: tracked idle-exit clean
boosts: 0 (0 externalized)
requested policy
req apptype: TASK_APPTYPE_DAEMON_INTERACTIVE
req role: TASK_DEFAULT_APPLICATION (PRIO_DARWIN_ROLE_UI)
req qos clamp: THREAD_QOS_UNSPECIFIED
req base/override latency qos: LATENCY_QOS_TIER_UNSPECIFIED / LATENCY_QOS_TIER_UNSPECIFIED
req base/override thruput qos: THROUGHPUT_QOS_TIER_UNSPECIFIED / THROUGHPUT_QOS_TIER_UNSPECIFIED
req darwin BG: YES (external)
req internal/external iotier: THROTTLE_LEVEL_TIER0 (IMPORTANT) / THROTTLE_LEVEL_TIER0 (IMPORTANT)
req darwin BG iotier: THROTTLE_LEVEL_TIER2 (UTILITY)
req managed: NO
req other:
req suppression (App Nap) behaviors:
effective policy
eff role: TASK_DEFAULT_APPLICATION (PRIO_DARWIN_ROLE_UI)
eff latency qos: LATENCY_QOS_TIER_UNSPECIFIED
eff thruput qos: THROUGHPUT_QOS_TIER_UNSPECIFIED
eff darwin BG: YES
eff iotier: THROTTLE_LEVEL_TIER2 (UTILITY)
eff managed: NO
eff qos ceiling: THREAD_QOS_USER_INITIATED
eff qos clamp: THREAD_QOS_UNSPECIFIED
eff other: low-priority-cpu (4) bg-allsockets bg-newsockets bg-watchers
imp_donor: YES
imp_receiver: NO
pid suspended: YES
adaptive daemon: NO (boosted: NO)
jevin@wombat [22:32:24] [~/code/mac/widget/xnu_unsuspend] [main *]
-> % sudo env PATH="${PATH}" ./xnu-unsuspend.py -n 'Deliveries Widget'
Resumed PID 30145.
jevin@wombat [22:32:41] [~/code/mac/widget/xnu_unsuspend] [main *]
-> % sudo taskinfo 'Deliveries Widget'
process: "Deliveries Widget" [30145] [unique ID: 1220404]
architecture: arm64
coalition (type 0) ID: 105936
coalition (type 1) ID: 591
suspend count: 0
virtual bytes: 389.40 GB; phys_footprint bytes: 8.92 MB; phys_footprint lifetime maximum bytes: 8.92 MB
run time: 61 s
user/system time (current threads): 0.042884 s / 0.035128 s
user/system time (terminated threads): 0.003909 s / 0.001453 s
P-time: 0.077003 s (92%)
P/E switches: 12
energy used (nJ): 191126927
interrupt wakeups: 4 (0 / 0.00% from platform idle)
default sched policy: POLICY_TIMESHARE
CPU usage monitor: 50% CPU over 180 seconds
CPU wakes monitor: 150 wakes per second (over system-default time period)
dirty tracking: tracked idle-exit clean
boosts: 0 (0 externalized)
requested policy
req apptype: TASK_APPTYPE_DAEMON_INTERACTIVE
req role: TASK_DEFAULT_APPLICATION (PRIO_DARWIN_ROLE_UI)
req qos clamp: THREAD_QOS_UNSPECIFIED
req base/override latency qos: LATENCY_QOS_TIER_UNSPECIFIED / LATENCY_QOS_TIER_UNSPECIFIED
req base/override thruput qos: THROUGHPUT_QOS_TIER_UNSPECIFIED / THROUGHPUT_QOS_TIER_UNSPECIFIED
req darwin BG: YES (external)
req internal/external iotier: THROTTLE_LEVEL_TIER0 (IMPORTANT) / THROTTLE_LEVEL_TIER0 (IMPORTANT)
req darwin BG iotier: THROTTLE_LEVEL_TIER2 (UTILITY)
req managed: NO
req other:
req suppression (App Nap) behaviors:
effective policy
eff role: TASK_DEFAULT_APPLICATION (PRIO_DARWIN_ROLE_UI)
eff latency qos: LATENCY_QOS_TIER_UNSPECIFIED
eff thruput qos: THROUGHPUT_QOS_TIER_UNSPECIFIED
eff darwin BG: YES
eff iotier: THROTTLE_LEVEL_TIER2 (UTILITY)
eff managed: NO
eff qos ceiling: THREAD_QOS_USER_INITIATED
eff qos clamp: THREAD_QOS_UNSPECIFIED
eff other: low-priority-cpu (4) bg-allsockets bg-newsockets bg-watchers
imp_donor: YES
imp_receiver: NO
pid suspended: NO
adaptive daemon: NO (boosted: NO)
#!/usr/bin/env python3
import argparse
import errno
import sys
import os
from typing import Optional
import frida
def xnu_unsuspend(pid: Optional[int] = None, name: Optional[str] = None):
if pid is None and name is None:
raise ValueError("xnu_unsuspend requires a PID or a process name.")
if pid is not None and name is not None:
raise ValueError("xnu_unsuspend received both a PID and a process name. Ambiguous.")
if pid is None:
pid = frida.get_local_device().get_process(name).pid
# runningboardd has com.apple.private.process.suspend-resume.any entitlement
session = frida.attach("runningboardd")
script = session.create_script("""
const pid_resume_ptr = Module.getExportByName('libSystem.B.dylib', 'pid_resume');
const pid_resume = new SystemFunction(pid_resume_ptr, 'int', ['int']);
send(pid_resume({pid}));
""".format(pid=pid)
)
def on_message(message: dict, data: Optional[bytes]):
if data is not None:
raise ValueError(f"xnu_unsuspend got unexpected data: {data.hex()}")
if message["type"] != "send":
raise ValueError(f"xnu_unsuspend got unexpected type: {message['type']}")
res = message["payload"]["value"]
err_num = message["payload"]["errno"]
if res != 0:
print(
f"pid_resume({pid}) = {res}, not the expected 0! errno = {err_num} AKA {errno.errorcode[err_num]} AKA \"{os.strerror(err_num)}\".",
file=sys.stderr,
)
script.unload()
session.detach()
sys.exit(-1)
else:
print(f"Resumed PID {pid}.")
script.unload()
session.detach()
sys.exit(0)
script.on("message", on_message)
script.load()
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="xnu-unsuspend")
target_group = parser.add_mutually_exclusive_group(required=True)
target_group.add_argument(
"-p",
"--pid",
type=int,
help="PID to unsuspend",
)
target_group.add_argument(
"-n",
"--name",
type=str,
help="Process name to unsuspend",
)
args = parser.parse_args()
xnu_unsuspend(pid=args.pid, name=args.name)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment