Created
July 14, 2023 02:34
-
-
Save jevinskie/801163b71f0845e6c3487413cb7706b0 to your computer and use it in GitHub Desktop.
xnu-unsuspend
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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